Download app/main.py from umairali64488/multi_llm_debugging_engine: direct link, hf CLI and curl.
- Browser
- Download file 5.73 kB
-
https://huggingface.co/spaces/umairali64488/multi_llm_debugging_engine/resolve/main/app/main.py
- Command line
-
hf download hf://spaces/umairali64488/multi_llm_debugging_engine/app/main.py
-
curl -L -o main.py https://huggingface.co/spaces/umairali64488/multi_llm_debugging_engine/resolve/main/app/main.py
5.73 kB
| """ | |
| main.py — FastAPI app for the CodeDebug Multi-LLM Debugger. | |
| Endpoints: | |
| GET / → serves frontend/index.html | |
| GET /health → health check | |
| GET /api/v1/models → list configured models | |
| POST /api/v1/debug → main pipeline (3 panel LLMs → Qwen3 judge) | |
| """ | |
| from contextlib import asynccontextmanager | |
| from pathlib import Path | |
| from fastapi import FastAPI, HTTPException, Request | |
| from fastapi.exceptions import RequestValidationError | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from fastapi.responses import FileResponse, JSONResponse | |
| from pydantic import BaseModel, Field, validator | |
| from app.config import settings | |
| from app.llm_chain import debug_query | |
| # ── Lifespan ────────────────────────────────────────────────────────────────── | |
| async def lifespan(app: FastAPI): | |
| print("⚡ Starting CodeDebug Multi-LLM Debugger...") | |
| print(f" Panel models : {settings.PANEL_MODELS}") | |
| print(f" Judge model : {settings.JUDGE_MODEL}") | |
| if not settings.OPENROUTER_API_KEY: | |
| print("⚠️ WARNING: OPENROUTER_API_KEY is not set — requests will fail!") | |
| else: | |
| print("✅ API key loaded. Ready!") | |
| yield | |
| print("🛑 Shutting down") | |
| # ── App ─────────────────────────────────────────────────────────────────────── | |
| app = FastAPI( | |
| title="CodeDebug Multi-LLM Debugger", | |
| version="2.0.0", | |
| description="3 panel LLMs in parallel → Qwen3 judge synthesizes the final answer.", | |
| lifespan=lifespan, | |
| ) | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| # ── Validation error handler ────────────────────────────────────────────────── | |
| async def validation_error_handler(request: Request, exc: RequestValidationError): | |
| print(f"❌ Validation error: {exc.errors()}") | |
| return JSONResponse( | |
| status_code=422, | |
| content={"error": str(exc.errors()), "detail": exc.errors()}, | |
| ) | |
| # ── Request schema ──────────────────────────────────────────────────────────── | |
| class DebugRequest(BaseModel): | |
| question: str = Field(..., min_length=1, description="The debugging question or code snippet") | |
| temperature: float = Field(default=0.3, ge=0.0, le=1.0, description="Sampling temperature for panel models") | |
| def coerce_float(cls, v): | |
| try: | |
| return float(v) | |
| except Exception: | |
| return 0.3 | |
| def strip_question(cls, v): | |
| v = v.strip() | |
| if not v: | |
| raise ValueError("question must not be empty") | |
| return v | |
| # ── Frontend ────────────────────────────────────────────────────────────────── | |
| FRONTEND = Path(__file__).parent.parent / "frontend" | |
| def serve_ui(): | |
| """Serve the single-page frontend.""" | |
| index = FRONTEND / "index.html" | |
| if index.exists(): | |
| return FileResponse(str(index)) | |
| return JSONResponse( | |
| status_code=200, | |
| content={"message": "CodeDebug API running. See /docs for endpoints."}, | |
| ) | |
| # ── System endpoints ────────────────────────────────────────────────────────── | |
| def health(): | |
| """Health check.""" | |
| return { | |
| "status": "ok", | |
| "version": "2.0.0", | |
| "api_key_set": bool(settings.OPENROUTER_API_KEY), | |
| } | |
| def list_models(): | |
| """List all configured models.""" | |
| return { | |
| "panel_models": [ | |
| {"model": m, "label": settings.PANEL_MODEL_LABELS.get(m, m)} | |
| for m in settings.PANEL_MODELS | |
| ], | |
| "judge_model": { | |
| "model": settings.JUDGE_MODEL, | |
| "label": settings.JUDGE_LABEL, | |
| }, | |
| } | |
| # ── Debug endpoint ──────────────────────────────────────────────────────────── | |
| async def debug(body: DebugRequest): | |
| """ | |
| Main endpoint. | |
| Sends `question` to 3 panel LLMs in parallel (LangChain LCEL chains), | |
| then forwards all responses to the Qwen3 judge which returns: | |
| - reasoning : judge's analysis of the three answers | |
| - final_answer: synthesised definitive answer | |
| """ | |
| if not settings.OPENROUTER_API_KEY: | |
| raise HTTPException( | |
| status_code=503, | |
| detail="OPENROUTER_API_KEY is not configured on the server.", | |
| ) | |
| print(f"📨 '{body.question[:70]}...' | temp={body.temperature}") | |
| result = await debug_query(body.question, body.temperature) | |
| successful = sum(1 for p in result["panel"] if not p.get("error")) | |
| print(f"✅ {successful}/3 panel responses · judge {'ok' if not result['judge'].get('error') else 'failed'} · {result['total_ms']}ms") | |
| return result | |