| from fastapi import FastAPI, HTTPException, Request, Response |
| from pydantic import BaseModel |
| import subprocess |
| import json |
| import os |
| import sys |
|
|
| app = FastAPI(title="Firm Workspace Proxy") |
|
|
| WORKSPACE_DIR = os.environ.get("FIRM_WORKSPACE", "/app/workspace") |
|
|
| |
| class QueryRequest(BaseModel): |
| query: str |
|
|
| class EntityRequest(BaseModel): |
| type: str |
| id: str |
|
|
| @app.get("/health") |
| def health(): |
| return {"status": "ok"} |
|
|
| @app.get("/api-docs") |
| def api_docs(): |
| return { |
| "endpoints": [ |
| { |
| "path": "/health", |
| "method": "GET", |
| "purpose": "Returns HTTP 200 when the app is ready" |
| }, |
| { |
| "path": "/api-docs", |
| "method": "GET", |
| "purpose": "Documents all available API endpoints" |
| }, |
| { |
| "path": "/query", |
| "method": "POST", |
| "purpose": "Run a Firm query string", |
| "request": {"query": "from task | where is_completed == false"}, |
| "response": {"result": "[...JSON array...]"} |
| }, |
| { |
| "path": "/get", |
| "method": "POST", |
| "purpose": "Get a specific entity by type and ID", |
| "request": {"type": "person", "id": "john_doe"}, |
| "response": {"result": "{...JSON object...}"} |
| }, |
| { |
| "path": "/list/{type}", |
| "method": "GET", |
| "purpose": "List all entity IDs for a given type", |
| "request": {}, |
| "response": {"result": "[...JSON array...]"} |
| } |
| ] |
| } |
|
|
| @app.post("/query") |
| async def run_query(req: QueryRequest): |
| try: |
| |
| |
| proc = subprocess.run( |
| ["firm", "query", req.query, "--workspace", WORKSPACE_DIR, "--format", "json"], |
| capture_output=True, text=True |
| ) |
| if proc.returncode != 0: |
| raise HTTPException(status_code=400, detail=proc.stderr) |
| |
| try: |
| return {"result": json.loads(proc.stdout)} |
| except json.JSONDecodeError: |
| return {"result": proc.stdout} |
| |
| except Exception as e: |
| raise HTTPException(status_code=500, detail=str(e)) |
|
|
| @app.post("/get") |
| async def run_get(req: EntityRequest): |
| try: |
| proc = subprocess.run( |
| ["firm", "get", req.type, req.id, "--workspace", WORKSPACE_DIR, "--format", "json"], |
| capture_output=True, text=True |
| ) |
| if proc.returncode != 0: |
| raise HTTPException(status_code=400, detail=proc.stderr) |
| |
| try: |
| return {"result": json.loads(proc.stdout)} |
| except json.JSONDecodeError: |
| return {"result": proc.stdout} |
| |
| except Exception as e: |
| raise HTTPException(status_code=500, detail=str(e)) |
|
|
| @app.get("/list/{type}") |
| async def run_list(type: str): |
| try: |
| proc = subprocess.run( |
| ["firm", "list", type, "--workspace", WORKSPACE_DIR, "--format", "json"], |
| capture_output=True, text=True |
| ) |
| if proc.returncode != 0: |
| raise HTTPException(status_code=400, detail=proc.stderr) |
| |
| try: |
| return {"result": json.loads(proc.stdout)} |
| except json.JSONDecodeError: |
| return {"result": proc.stdout} |
| |
| except Exception as e: |
| raise HTTPException(status_code=500, detail=str(e)) |
|
|
| if __name__ == "__main__": |
| import uvicorn |
| uvicorn.run(app, host="0.0.0.0", port=7860) |
|
|