Spaces:
Sleeping
Sleeping
Melika Kheirieh
refactor(core): DI-ready Pipeline; add registry + YAML factory + typed trace/result
5b7b403
| import os | |
| import time | |
| from fastapi import FastAPI, Request, Response, HTTPException | |
| from fastapi.responses import PlainTextResponse | |
| from prometheus_client import ( | |
| Counter, | |
| Histogram, | |
| CollectorRegistry, | |
| generate_latest, | |
| CONTENT_TYPE_LATEST, | |
| ) | |
| try: | |
| from dotenv import load_dotenv | |
| load_dotenv() | |
| except Exception: | |
| pass | |
| from app.routers import nl2sql | |
| # ---- Optionally restore uploaded DB map ---- | |
| try: | |
| from app.routers.nl2sql import _load_db_map | |
| _load_db_map() | |
| except Exception as e: | |
| print(f"⚠️ DB map not restored: {e}") | |
| application: FastAPI = FastAPI( | |
| title="NL2SQL Copilot Prototype", | |
| version=os.getenv("APP_VERSION", "0.1.0"), | |
| description="Convert natural language to safe & verified SQL", | |
| ) | |
| application.include_router(nl2sql.router, prefix="/api/v1") # e.g. /api/v1/nl2sql | |
| application.include_router(nl2sql.router) # e.g. /nl2sql | |
| # ---- Prometheus metrics ---- | |
| REGISTRY = CollectorRegistry() | |
| REQUEST_COUNT = Counter( | |
| "http_requests_total", | |
| "Total HTTP requests", | |
| ["path", "method", "status_code"], | |
| registry=REGISTRY, | |
| ) | |
| REQUEST_LATENCY = Histogram( | |
| "http_request_latency_seconds", | |
| "Request latency", | |
| ["path", "method"], | |
| registry=REGISTRY, | |
| ) | |
| async def metrics_middleware(request: Request, call_next): | |
| start = time.perf_counter() | |
| response: Response = await call_next(request) | |
| elapsed = time.perf_counter() - start | |
| route = request.scope.get("route") | |
| path = route.path if route else request.url.path | |
| REQUEST_COUNT.labels( | |
| path=path, method=request.method, status_code=str(response.status_code) | |
| ).inc() | |
| REQUEST_LATENCY.labels(path=path, method=request.method).observe(elapsed) | |
| return response | |
| # --- Liveness --- | |
| def healthz() -> str: | |
| return "ok" | |
| # --- Readiness --- | |
| def readyz() -> str: | |
| mode = os.getenv("DB_MODE", "sqlite").lower() | |
| try: | |
| if mode == "postgres": | |
| from adapters.db.postgres_adapter import PostgresAdapter | |
| dsn = os.environ["POSTGRES_DSN"] | |
| pg = PostgresAdapter(dsn) | |
| ping = getattr(pg, "ping", None) | |
| if callable(ping): | |
| ping() | |
| else: | |
| from adapters.db.sqlite_adapter import SQLiteAdapter | |
| db_path = os.getenv("SQLITE_DB_PATH", "data/chinook.db") | |
| sq = SQLiteAdapter(db_path) | |
| ping = getattr(sq, "ping", None) | |
| if callable(ping): | |
| ping() | |
| return "ready" | |
| except Exception: | |
| raise HTTPException(status_code=503, detail="not ready") | |
| def root(): | |
| return {"status": "ok", "message": "NL2SQL Copilot API is running"} | |
| def health(): | |
| return {"status": "ok", "db": "connected", "llm": "reachable", "uptime_sec": 123.4} | |
| def metrics(): | |
| data = generate_latest(REGISTRY) | |
| return Response(content=data, media_type=CONTENT_TYPE_LATEST) | |
| # Backward compatibility for tests & uvicorn targets | |
| app: FastAPI = application | |
| __all__ = ["application", "app"] | |