""" Main FastAPI Application ========================= Application entry point """ import logging from contextlib import asynccontextmanager from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import JSONResponse from app.core.config import settings from app.core.exceptions import ToxicDetectionException from app.models.model_loader import model_loader from app.api.routes import router # Configure logging logging.basicConfig( level=getattr(logging, settings.LOG_LEVEL), format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' ) logger = logging.getLogger(__name__) @asynccontextmanager async def lifespan(app: FastAPI): """ Lifespan events Startup: Load model Shutdown: Cleanup """ # Startup logger.info("Starting up...") try: logger.info("Loading model...") model_loader.load() logger.info("Model loaded successfully") except Exception as e: logger.error(f"Failed to load model: {str(e)}") # Continue anyway - health endpoint will show model not loaded yield # Shutdown logger.info("Shutting down...") # Create FastAPI app app = FastAPI( title=settings.API_TITLE, description=settings.API_DESCRIPTION, version=settings.API_VERSION, lifespan=lifespan, docs_url="/docs", redoc_url="/redoc", openapi_url="/openapi.json" ) # CORS middleware app.add_middleware( CORSMiddleware, allow_origins=settings.ALLOWED_ORIGINS, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Exception handlers @app.exception_handler(ToxicDetectionException) async def toxic_detection_exception_handler(request, exc: ToxicDetectionException): """Handle custom exceptions""" return JSONResponse( status_code=exc.status_code, content={ "success": False, "error": exc.detail, "detail": None } ) @app.exception_handler(Exception) async def general_exception_handler(request, exc: Exception): """Handle general exceptions""" logger.error(f"Unhandled exception: {str(exc)}", exc_info=True) return JSONResponse( status_code=500, content={ "success": False, "error": "Internal server error", "detail": str(exc) if settings.LOG_LEVEL == "DEBUG" else None } ) # Include routers app.include_router(router, prefix="/api/v1", tags=["v1"]) app.include_router(router, prefix="", tags=["root"]) # For direct run if __name__ == "__main__": import uvicorn uvicorn.run( "app.main:app", host=settings.API_HOST, port=settings.API_PORT, reload=settings.API_RELOAD, log_level=settings.LOG_LEVEL.lower() )