Spaces:
Runtime error
Runtime error
File size: 4,577 Bytes
d2d4409 02427e3 0358051 d2d4409 bc2b07b 0358051 cc78da3 0358051 02427e3 49206fb 0358051 d2d4409 f7d6cd3 0358051 bc2b07b 0358051 bc2b07b 0358051 f7d6cd3 148b563 3d08a7e b13c030 d2d4409 148b563 d2d4409 cc78da3 b07d245 d2d4409 b07d245 cc78da3 f7d6cd3 02427e3 f7d6cd3 | 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 | import uuid
import logging
from fastapi import FastAPI, Request, Depends
from fastapi.middleware.cors import CORSMiddleware
from fastapi.exceptions import RequestValidationError
from starlette.exceptions import HTTPException as StarletteHTTPException
import app
from transparent_fastapi import install
from app.config import settings
from app.routers import auth, hubs, documents
from app.errors import AppError, error_response
from app.deps import get_current_user
from app.models import User
from app.services.groq_service import AiUnavailable
logger = logging.getLogger("uvicorn.error")
def create_app() -> FastAPI:
app = FastAPI(
title="ContextQuery AI",
version="0.1.0",
docs_url="/docs",
redoc_url=None,
)
# Initialize transparent-fastapi for /metrics
install(app)
app.add_middleware(
CORSMiddleware,
allow_origins=[
"http://localhost:3000",
"http://127.0.0.1:3000",
"http://localhost:8000",
"http://127.0.0.1:8000",
"http://localhost:5500", # <-- Add this (Live Server localhost)
"http://127.0.0.1:5500",
"null", # <--- THIS IS CRITICAL FOR LOCAL FILE TESTING
],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
expose_headers=["X-Request-ID", "Idempotent-Replayed", "Retry-After"],
)
app.include_router(auth.router, prefix="/api/v1")
app.include_router(hubs.router, prefix="/api/v1")
app.include_router(documents.router, prefix="/api/v1")
@app.middleware("http")
async def catch_unhandled(request: Request, call_next):
try:
return await call_next(request)
except Exception:
logger.exception("unhandled error", extra={"request_id": getattr(request.state, "request_id", "unknown")})
return error_response(request, 500, "INTERNAL_ERROR", "Unexpected server error.")
@app.middleware("http")
async def add_request_id(request: Request, call_next):
request.state.request_id = str(uuid.uuid4())
response = await call_next(request)
response.headers["X-Request-ID"] = request.state.request_id
return response
@app.exception_handler(AppError)
async def app_error_handler(request: Request, exc: AppError):
return error_response(request, exc.status_code, exc.code, exc.message, exc.details, exc.headers)
@app.exception_handler(RequestValidationError)
async def validation_error_handler(request: Request, exc: RequestValidationError):
details = []
for error in exc.errors():
loc = error.get("loc", [])
field = ".".join(str(x) for x in loc) if loc else "unknown"
details.append({
"field": field,
"reason": error.get("type", "invalid"),
"message": error.get("msg", "Invalid value")
})
return error_response(request, 422, "VALIDATION_ERROR", "Request validation failed.", details=details)
@app.exception_handler(StarletteHTTPException)
async def http_exception_handler(request: Request, exc: StarletteHTTPException):
if exc.status_code == 404:
return error_response(request, 404, "ROUTE_NOT_FOUND", "The requested route does not exist.")
if exc.status_code == 405:
return error_response(request, 405, "METHOD_NOT_ALLOWED", "Method not allowed for this route.")
return error_response(request, exc.status_code, "HTTP_ERROR", str(exc.detail))
AI_ERRORS = {
"rate_limited": (429, "AI_RATE_LIMITED", "The AI provider's free quota is used up. Try again later."),
"timeout": (504, "AI_TIMEOUT", "The AI provider took too long to answer."),
"provider": (502, "AI_PROVIDER_ERROR", "The AI provider returned an error."),
}
@app.exception_handler(AiUnavailable)
async def ai_unavailable_handler(request: Request, exc: AiUnavailable):
status, code, message = AI_ERRORS[exc.kind]
headers = {"Retry-After": "30"} if exc.kind == "rate_limited" else None
return error_response(request, status, code, message, headers=headers)
@app.get("/healthz", tags=["system"])
def healthz() -> dict[str, str]:
return {"status": "ok"}
@app.get("/api/v1/protected", tags=["system"])
def protected_route(current_user: User = Depends(get_current_user)):
return {"message": "You are authenticated!", "user_id": str(current_user.id)}
return app
app = create_app() |