added more MCP commands

This commit is contained in:
Nico Melone
2025-05-27 21:01:53 -05:00
parent 2af477542e
commit 3f73cc27f9
8 changed files with 139867 additions and 0 deletions

Binary file not shown.

Binary file not shown.

Submodule LLM Integration/examples/openapi-servers added at 2b7844d634

95
LLM Integration/main.py Normal file
View 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

File diff suppressed because one or more lines are too long

View 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)

File diff suppressed because one or more lines are too long