Spaces:
Sleeping
Sleeping
File size: 4,705 Bytes
e7d7c61 c24bfe8 e7d7c61 99fa656 e7d7c61 99fa656 e7d7c61 99fa656 e7d7c61 c24bfe8 570f7bd e7d7c61 570f7bd c24bfe8 570f7bd c24bfe8 e7d7c61 c24bfe8 e7d7c61 c1bc4eb 99fa656 e7d7c61 c24bfe8 e7d7c61 c24bfe8 e7d7c61 c24bfe8 e7d7c61 c24bfe8 99fa656 e7d7c61 99fa656 e7d7c61 c24bfe8 e7d7c61 4c2cf14 c24bfe8 e7d7c61 570f7bd c1bc4eb 99fa656 570f7bd c1bc4eb 99fa656 570f7bd c1bc4eb e7d7c61 99fa656 e7d7c61 ccefd8e c24bfe8 ccefd8e |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
import os
import time
from fastapi import FastAPI, Request, Response, HTTPException
from fastapi.responses import PlainTextResponse, RedirectResponse
from prometheus_client import Counter, Histogram, generate_latest, CONTENT_TYPE_LATEST
from nl2sql.prom import REGISTRY
from app.routers import dev
try:
from dotenv import load_dotenv
load_dotenv()
except Exception:
pass
from app.routers import nl2sql
# ----------------------------------------------------------------------------
# App definition
# ----------------------------------------------------------------------------
application = FastAPI(
title="NL2SQL Copilot Prototype",
version=os.getenv("APP_VERSION", "0.1.0"),
description="Convert natural language to safe & verified SQL",
)
# Register only versioned API
application.include_router(nl2sql.router, prefix="/api/v1")
# Register Dev-only routes (only when APP_ENV=dev)
if os.getenv("APP_ENV", "dev").lower() == "dev":
application.include_router(dev.router, prefix="/api/v1")
# ----------------------------------------------------------------------------
# Prometheus Metrics Middleware
# ----------------------------------------------------------------------------
REQUEST_COUNT = Counter(
"http_requests_total",
"Total HTTP requests",
["path", "method", "status_code"],
registry=REGISTRY,
)
REQUEST_LATENCY = Histogram(
"http_request_latency_seconds",
"Request latency (seconds)",
["path", "method"],
registry=REGISTRY,
)
@application.middleware("http")
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 = getattr(route, "path", None) or request.url.path
name = getattr(route, "name", None) or path
REQUEST_COUNT.labels(
path=name,
method=request.method,
status_code=str(getattr(response, "status_code", 500)),
).inc()
REQUEST_LATENCY.labels(path=name, method=request.method).observe(elapsed)
return response
# ----------------------------------------------------------------------------
# System Endpoints
# ----------------------------------------------------------------------------
@application.get("/healthz", response_class=PlainTextResponse, tags=["system"])
def healthz() -> str:
return "ok"
@application.get("/readyz", response_class=PlainTextResponse, tags=["system"])
def readyz() -> str:
mode = os.getenv("DB_MODE", "sqlite").lower()
try:
if mode == "postgres":
from adapters.db.postgres_adapter import PostgresAdapter
pg = PostgresAdapter(os.environ["POSTGRES_DSN"])
ping_fn = getattr(pg, "ping", None)
if callable(ping_fn):
ping_fn()
else:
from adapters.db.sqlite_adapter import SQLiteAdapter
sq = SQLiteAdapter(
os.getenv("DEFAULT_SQLITE_PATH", "data/Chinook_Sqlite.sqlite")
)
ping_fn = getattr(sq, "ping", None)
if callable(ping_fn):
ping_fn()
return "ready"
except Exception:
raise HTTPException(status_code=503, detail="not ready")
@application.get("/")
def root():
return {"status": "ok", "message": "NL2SQL Copilot API is running"}
@application.get("/health")
def health():
return {"status": "ok", "db": "connected", "llm": "reachable", "uptime_sec": 123.4}
@application.get("/metrics", tags=["system"])
def metrics():
data = generate_latest(REGISTRY)
return Response(content=data, media_type=CONTENT_TYPE_LATEST)
# ----------------------------------------------------------------------------
# Legacy Redirects (clean compatibility)
# ----------------------------------------------------------------------------
@application.api_route("/nl2sql", methods=["GET", "POST"])
async def legacy_nl2sql_redirect(request: Request):
return RedirectResponse(url="/api/v1/nl2sql", status_code=307)
@application.api_route(
"/{path:path}", methods=["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"]
)
async def legacy_catch_all(request: Request, path: str):
"""Redirect old root-level endpoints to versioned API."""
if path.startswith("api/v1"):
return RedirectResponse(url=f"/{path}", status_code=307)
return RedirectResponse(url=f"/api/v1/{path}", status_code=307)
# ----------------------------------------------------------------------------
# Backward-compatible alias for uvicorn
# ----------------------------------------------------------------------------
app = application
__all__ = ["application", "app"]
|