import logging from contextlib import asynccontextmanager from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles from app.core.config import settings from app.core.db import ensure_indexes from app.routers import alerts, auth, devices, keys, policy, reviews, screenshots logger = logging.getLogger(__name__) @asynccontextmanager async def lifespan(app: FastAPI): """Lifespan context manager for startup/shutdown events.""" # Startup await ensure_indexes() if settings.warmup_game_models: try: from app.services import classifier warmup = getattr(classifier, "warmup_game_classifiers", None) if callable(warmup): warmup() else: logger.warning("game-classifier warmup skipped: missing warmup_game_classifiers") except Exception as exc: logger.warning("game-classifier warmup skipped: %s", exc) yield # Shutdown (cleanup if needed) app = FastAPI(title=settings.app_name, lifespan=lifespan) app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) app.include_router(auth.router, prefix=settings.api_prefix) app.include_router(devices.router, prefix=settings.api_prefix) app.include_router(policy.router, prefix=settings.api_prefix) app.include_router(screenshots.router, prefix=settings.api_prefix) app.include_router(keys.router, prefix=settings.api_prefix) app.include_router(alerts.router, prefix=settings.api_prefix) app.include_router(reviews.router, prefix=settings.api_prefix) app.mount(settings.media_prefix, StaticFiles(directory=settings.storage_dir), name="media") @app.get("/health") def health() -> dict[str, str]: return {"status": "ok"} if __name__ == "__main__": import uvicorn uvicorn.run( "app.main:app", host="0.0.0.0", port=7860, reload=False, )