Spaces:
Sleeping
Sleeping
| """ | |
| main.py β FastAPI application for AgentForge. | |
| Exposes POST /run, GET /health, GET /benchmark. | |
| """ | |
| import asyncio | |
| import logging | |
| import time | |
| from fastapi import FastAPI, HTTPException | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from pydantic import BaseModel | |
| import memory | |
| from config import get_settings | |
| from orchestrator import run_pipeline | |
| logging.basicConfig(level=logging.INFO, format="%(levelname)s %(name)s: %(message)s") | |
| logger = logging.getLogger(__name__) | |
| settings = get_settings() | |
| app = FastAPI(title="AgentForge", version="1.0.0") | |
| # ββ CORS βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=settings.allowed_origins_list, | |
| allow_origin_regex=r"https://.*\.vercel\.app", | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| # ββ Request / Response models ββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| class RunRequest(BaseModel): | |
| task: str | |
| # ββ Routes ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| async def health(): | |
| return { | |
| "status": "ok", | |
| "redis": "connected" if memory.is_available() else "unavailable", | |
| "model": settings.model_name, | |
| } | |
| async def run(req: RunRequest): | |
| if not req.task.strip(): | |
| raise HTTPException(status_code=400, detail="task cannot be empty") | |
| logger.info("POST /run β task: %sβ¦", req.task[:80]) | |
| result = await run_pipeline(req.task) | |
| return result | |
| BENCHMARK_TASK = "Compare PostgreSQL vs MongoDB for a startup in 2025" | |
| async def benchmark(): | |
| """ | |
| Run the same task twice. First call hits LLM; second hits Redis cache. | |
| Returns timing comparison to demonstrate cache speedup. | |
| """ | |
| # Flush any existing cache for this task so benchmark is honest | |
| from orchestrator import decompose_task | |
| subtasks = await decompose_task(BENCHMARK_TASK) | |
| for s in subtasks: | |
| key = memory.cache_key(s["prompt"]) | |
| if memory.is_available() and memory._client: | |
| try: | |
| memory._client.delete(key) | |
| except Exception: | |
| pass | |
| t0 = time.perf_counter() | |
| run1 = await run_pipeline(BENCHMARK_TASK) | |
| time1 = time.perf_counter() - t0 | |
| t0 = time.perf_counter() | |
| run2 = await run_pipeline(BENCHMARK_TASK) | |
| time2 = time.perf_counter() - t0 | |
| return { | |
| "task": BENCHMARK_TASK, | |
| "run1_cold": { | |
| "total_time": round(time1, 2), | |
| "parallel_time": run1["parallel_time"], | |
| "sequential_time": run1["sequential_time"], | |
| "speedup": run1["speedup"], | |
| }, | |
| "run2_cached": { | |
| "total_time": round(time2, 2), | |
| "parallel_time": run2["parallel_time"], | |
| "sequential_time": run2["sequential_time"], | |
| }, | |
| "cache_speedup": round(time1 / time2, 1) if time2 > 0 else "β", | |
| } | |