Spaces:
Sleeping
Sleeping
Download src/chokepoint/api/main.py from YuraBodnar/ChokePointAI: direct link, hf CLI and curl.
- Browser
- Download file 3 kB
-
https://huggingface.co/spaces/YuraBodnar/ChokePointAI/resolve/main/src/chokepoint/api/main.py
- Command line
-
hf download hf://spaces/YuraBodnar/ChokePointAI/src/chokepoint/api/main.py
-
curl -L -o main.py https://huggingface.co/spaces/YuraBodnar/ChokePointAI/resolve/main/src/chokepoint/api/main.py
3 kB
| """FastAPI app factory: lifespan, CORS, error handling, routing, static UI. | |
| See ARCHITECTURE_AND_PLAN.md §3 (System Architecture) and §9 (API Surface). | |
| """ | |
| from __future__ import annotations | |
| from collections.abc import AsyncIterator | |
| from contextlib import asynccontextmanager | |
| from pathlib import Path | |
| from fastapi import FastAPI, Request | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from fastapi.responses import JSONResponse | |
| from fastapi.staticfiles import StaticFiles | |
| from chokepoint.api.middleware import RequestContextMiddleware | |
| from chokepoint.api.routers import health, simulate | |
| from chokepoint.config import get_settings | |
| from chokepoint.logging import configure_logging, get_logger | |
| WEB_DIR = Path(__file__).resolve().parent.parent / "web" | |
| logger = get_logger("chokepoint.api") | |
| async def lifespan(app: FastAPI) -> AsyncIterator[None]: | |
| settings = get_settings() | |
| configure_logging(settings.log_level) | |
| logger.info( | |
| "startup", | |
| extra={ | |
| "method": "-", | |
| "path": "-", | |
| "status_code": 0, | |
| "duration_ms": 0.0, | |
| }, | |
| ) | |
| yield | |
| logger.info( | |
| "shutdown", | |
| extra={ | |
| "method": "-", | |
| "path": "-", | |
| "status_code": 0, | |
| "duration_ms": 0.0, | |
| }, | |
| ) | |
| def create_app() -> FastAPI: | |
| settings = get_settings() | |
| app = FastAPI( | |
| title="ChokePoint AI", | |
| description="Supply Chain Shock Simulator — OSINT-driven cascading impact forecasts.", | |
| version="0.1.0", | |
| lifespan=lifespan, | |
| ) | |
| app.add_middleware(RequestContextMiddleware) | |
| if settings.app_env == "dev": | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| async def unhandled_exception_handler(request: Request, exc: Exception) -> JSONResponse: | |
| request_id = getattr(request.state, "request_id", "unknown") | |
| logger.error( | |
| "unhandled exception", | |
| extra={ | |
| "request_id": request_id, | |
| "method": request.method, | |
| "path": request.url.path, | |
| "status_code": 500, | |
| "duration_ms": 0.0, | |
| }, | |
| exc_info=exc, | |
| ) | |
| return JSONResponse( | |
| status_code=500, | |
| media_type="application/problem+json", | |
| content={ | |
| "type": "about:blank", | |
| "title": "Internal Server Error", | |
| "status": 500, | |
| "detail": "An unexpected error occurred. This has been logged.", | |
| "request_id": request_id, | |
| }, | |
| ) | |
| app.include_router(health.router) | |
| app.include_router(simulate.router) | |
| if WEB_DIR.is_dir(): | |
| app.mount("/", StaticFiles(directory=str(WEB_DIR), html=True), name="web") | |
| return app | |
| app = create_app() | |