added more MCP commands
This commit is contained in:
BIN
LLM Integration/__pycache__/main.cpython-313.pyc
Normal file
BIN
LLM Integration/__pycache__/main.cpython-313.pyc
Normal file
Binary file not shown.
BIN
LLM Integration/__pycache__/model.cpython-313.pyc
Normal file
BIN
LLM Integration/__pycache__/model.cpython-313.pyc
Normal file
Binary file not shown.
BIN
LLM Integration/__pycache__/thingsboard.cpython-313.pyc
Normal file
BIN
LLM Integration/__pycache__/thingsboard.cpython-313.pyc
Normal file
Binary file not shown.
1
LLM Integration/examples/openapi-servers
Submodule
1
LLM Integration/examples/openapi-servers
Submodule
Submodule LLM Integration/examples/openapi-servers added at 2b7844d634
95
LLM Integration/main.py
Normal file
95
LLM Integration/main.py
Normal file
@@ -0,0 +1,95 @@
|
||||
import json
|
||||
import httpx
|
||||
from fastapi import FastAPI, Request
|
||||
from fastapi.responses import JSONResponse
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from pydantic import BaseModel
|
||||
from typing import Dict, Any
|
||||
import uvicorn
|
||||
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv()
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
origins = ["*"]
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=origins,
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
|
||||
# Load OpenAPI spec from IBM COS API
|
||||
OPENAPI_URL = "https://thingsboard.cloud/v3/api-docs/thingsboard"
|
||||
|
||||
class ToolCallInput(BaseModel):
|
||||
tool_name: str
|
||||
input: Dict[str, Any]
|
||||
|
||||
# In-memory registry of tools
|
||||
tool_registry = {}
|
||||
|
||||
async def fetch_openapi_spec():
|
||||
async with httpx.AsyncClient() as client:
|
||||
response = await client.get(OPENAPI_URL)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
def generate_tools_from_openapi(openapi: Dict[str, Any]):
|
||||
paths = openapi.get("paths", {})
|
||||
if not paths:
|
||||
raise ValueError(f"Path is empty or invalid for {service_name}")
|
||||
|
||||
for path, methods in paths.items():
|
||||
for method, details in methods.items():
|
||||
operation_id = details.get("operationId") or f"{method}_{path.replace('/', '_')}"
|
||||
summary = details.get("summary", "")
|
||||
|
||||
# Create a basic tool function with a name and HTTP method
|
||||
def make_tool(p, m):
|
||||
async def tool_func(input_data):
|
||||
region = input_data.get("region", "us-south")
|
||||
headers = input_data.get("headers", {})
|
||||
body = input_data.get("body", None)
|
||||
params = input_data.get("params", None)
|
||||
params = input_data.get("params", {})
|
||||
formatted_path = p
|
||||
for key, value in params.items():
|
||||
formatted_path = formatted_path.replace(f"{{{key}}}", value)
|
||||
url = f"https://thingsboard.cloud/v3{formatted_path}"
|
||||
async with httpx.AsyncClient() as client:
|
||||
req = client.build_request(m.upper(), url, headers=headers, json=body, params=params)
|
||||
res = await client.send(req)
|
||||
return {"status_code": res.status_code, "body": res.text}
|
||||
return tool_func
|
||||
|
||||
tool_registry[operation_id] = make_tool(path, method)
|
||||
|
||||
@app.post("/invoke")
|
||||
async def invoke_tool(call: ToolCallInput):
|
||||
tool_name = call.tool_name
|
||||
input_data = call.input
|
||||
print(input_data)
|
||||
if tool_name not in tool_registry:
|
||||
return JSONResponse(status_code=404, content={"error": "Tool not found"})
|
||||
|
||||
tool_func = tool_registry[tool_name]
|
||||
try:
|
||||
result = await tool_func(input_data)
|
||||
return JSONResponse(content={"output": result})
|
||||
except Exception as e:
|
||||
return JSONResponse(status_code=500, content={"error": str(e)})
|
||||
|
||||
@app.get("/tools")
|
||||
async def list_tools():
|
||||
return JSONResponse(content={"tools": list(tool_registry.keys())})
|
||||
|
||||
@app.on_event("startup")
|
||||
async def startup():
|
||||
openapi = await fetch_openapi_spec()
|
||||
generate_tools_from_openapi(openapi)
|
||||
print(f"Registered tools: {list(tool_registry.keys())}")
|
||||
10357
LLM Integration/model.py
Normal file
10357
LLM Integration/model.py
Normal file
File diff suppressed because one or more lines are too long
113
LLM Integration/thingsboard.py
Normal file
113
LLM Integration/thingsboard.py
Normal file
@@ -0,0 +1,113 @@
|
||||
from model import *
|
||||
from fastapi import FastAPI, HTTPException, Body
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from typing import Literal
|
||||
import requests, json
|
||||
from datetime import datetime as dt
|
||||
from datetime import timedelta as td
|
||||
app = FastAPI(
|
||||
title="Thingsboard API",
|
||||
version="1.0.0",
|
||||
description="Provides secure access to Thingsboard API",
|
||||
)
|
||||
|
||||
|
||||
origins = ["*"]
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=origins,
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
|
||||
def getJWT():
|
||||
response = requests.post(url_base + 'auth/login', headers=headers,data=credentials)
|
||||
token = response.json()
|
||||
headers["X-Authorization"] = "Bearer " + token['token']
|
||||
|
||||
@app.get("/customers", response_model=List[Customer])
|
||||
def getCustomers(page: int = 0, pageSize: int = 10):
|
||||
"""
|
||||
Returns a list of customers from Thingsboard API.
|
||||
"""
|
||||
response = requests.get(
|
||||
url_base + f"customers?page={page}&pageSize={pageSize}", headers=headers)
|
||||
#print(json.dumps(response.json(), indent=4))
|
||||
customers = []
|
||||
customers = response.json()['data']
|
||||
while(response.json()["hasNext"]):
|
||||
page += 1
|
||||
response = requests.get(url_base + f"customers?page={page}&pageSize={pageSize}", headers=headers)
|
||||
customers += response.json()['data']
|
||||
#print(customers)
|
||||
return customers
|
||||
|
||||
@app.get("/customerNames", response_model=List[str])
|
||||
def getCustomerNames(page=0, pageSize=10):
|
||||
"""
|
||||
Returns a list of customer names from Thingsboard API.
|
||||
"""
|
||||
customers = getCustomers(page=0, pageSize=10)
|
||||
names = []
|
||||
for c in customers:
|
||||
names.append(c['name'])
|
||||
#print(names)
|
||||
return names
|
||||
|
||||
|
||||
@app.get("/telemetry", response_model=dict)
|
||||
def getTelemetry(startTs, endTs, keys, eType, deviceId):
|
||||
"""
|
||||
Returns a list of telemetry data from Thingsboard API.
|
||||
parameters:
|
||||
startTs: Timestamp of the start time for the data in milliseconds.
|
||||
endTs: Timestamp of the end time for the data in milliseconds.
|
||||
keys: List of attribute keys to retrieve (e.g., temperature,humidity,etc.).
|
||||
eType: Type of entity (e.g., 'ASSET', 'DEVICE').
|
||||
deviceId: ID of the device as a UUID
|
||||
"""
|
||||
if(not keys):
|
||||
keys = ["temperature", "humidity"]
|
||||
if(not startTs):
|
||||
#set startTs to time from 1 hour ago and put it in timestamp format with milliseconds
|
||||
startTs = dt.timestamp(dt.now() - td(hours=1)) * 1000
|
||||
if(not endTs):
|
||||
#set endTs to time from now and put it in timestamp format with milliseconds
|
||||
endTs = dt.timestamp(dt.now()) * 1000
|
||||
telemetry = requests.get(
|
||||
url_base + f"plugins/telemetry/{eType}/{deviceId}/values/timeseries?startTs={startTs}&endTs={endTs}&keys={keys}", headers=headers)
|
||||
print(telemetry.json())
|
||||
return telemetry.json()
|
||||
|
||||
@app.get("/deviceIdByName", response_model=dict)
|
||||
def getDeviceByName(textSearch: str, deviceType: str = None, sortProperty: str = None, sortOrder: str = "ASC",page: int = 0, pageSize: int = 10):
|
||||
"""
|
||||
Returns a dictionary with the device ID (as a UUID) of a device with a given name in the textSearch param
|
||||
parameters:
|
||||
deviceType: optional parameter to specify the device type for search
|
||||
textSearch: the string or substring of the name of the device being searched for
|
||||
sortProperty: optional parameter to specify the property to sort by can be one of the following [createdTime, name, deviceProfileName, label, customerTitle]
|
||||
sortOrder: optional parameter to specify is ascending or descending order [ASC, DESC]
|
||||
page: the page of results to acquire default is set to 0 to get the first page
|
||||
pageSize: the number of results per page
|
||||
"""
|
||||
response = requests.get(url_base + f"user/devices?page={page}&pageSize={pageSize}&textSearch={textSearch}", headers=headers)
|
||||
#print(response.url)
|
||||
#print(response.request)
|
||||
#print(json.dumps(response.json(),indent=4))
|
||||
devices = response.json()["data"]
|
||||
device = {textSearch: devices[0]["id"]["id"]}
|
||||
return device
|
||||
headers = {"Content-Type": "application/json",
|
||||
"Accept": "application/json"}
|
||||
username = "nmelone@henry-pump.com"
|
||||
password = "gzU6$26v42mU%3jDzTJf"
|
||||
domain = "thingsboard.cloud"
|
||||
credentials = json.dumps(
|
||||
{"username": f"{username}", "password": f"{password}"})
|
||||
url_base = f"https://{domain}/api/"
|
||||
getJWT()
|
||||
#print(headers)
|
||||
129301
LLM Integration/thingsboardAPI.json
Normal file
129301
LLM Integration/thingsboardAPI.json
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user