"""Main FastAPI application for the multi-utility server.""" import time from contextlib import asynccontextmanager from fastapi import FastAPI, Request from fastapi.responses import JSONResponse from fastapi.middleware.cors import CORSMiddleware from slowapi import _rate_limit_exceeded_handler from slowapi.errors import RateLimitExceeded from app.core.config import settings from app.core.logging import setup_logging, get_logger from app.core.exceptions import MultiUtilityServerException from app.middleware import APIKeyMiddleware, limiter from app.apis.subtitles.router import router as subtitles_router from app.apis.embeddings.router import router as embeddings_router setup_logging() logger = get_logger(__name__) @asynccontextmanager async def lifespan(app: FastAPI): """Application lifespan manager.""" logger.info("Starting multi-utility server...") logger.info(f"Log level: {settings.log_level}") logger.info(f"API keys configured: {len(settings.api_keys_set)}") logger.info(f"CORS origins: {settings.cors_origins_list}") yield logger.info("Shutting down multi-utility server...") app = FastAPI( title="Multi-Utility Server", description="Centralized FastAPI server providing reusable APIs for different projects", version="1.0.0", docs_url="/docs", redoc_url="/redoc", lifespan=lifespan ) app.state.limiter = limiter app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler) app.add_middleware( CORSMiddleware, allow_origins=settings.cors_origins_list, allow_credentials=True if settings.cors_origins else False, allow_methods=["GET", "POST", "PUT", "DELETE"], allow_headers=["*"], ) app.add_middleware(APIKeyMiddleware) @app.exception_handler(MultiUtilityServerException) async def custom_exception_handler(request: Request, exc: MultiUtilityServerException): """Handle custom application exceptions.""" logger.error(f"Application error: {exc.message}") return JSONResponse( status_code=exc.status_code, content={"status": "error", "message": exc.message} ) @app.exception_handler(Exception) async def global_exception_handler(request: Request, exc: Exception): """Handle unexpected exceptions.""" logger.error(f"Unexpected error: {str(exc)}", exc_info=True) return JSONResponse( status_code=500, content={"status": "error", "message": "An unexpected error occurred"} ) @app.middleware("http") async def log_requests(request: Request, call_next): """Log all HTTP requests.""" start_time = time.time() logger.info(f"Request: {request.method} {request.url.path}") response = await call_next(request) process_time = time.time() - start_time logger.info( f"Response: {response.status_code} | " f"Time: {process_time:.4f}s | " f"Path: {request.url.path}" ) return response @app.head("/health") @app.get("/health") async def health_check(): """Health check endpoint.""" return { "status": "healthy", "service": "multi-utility-server", "version": "1.0.0" } @app.get("/") async def root(): """Root endpoint with API information.""" return { "message": "Multi-Utility FastAPI Server", "version": "1.0.0", "docs": "/docs", "health": "/health", "apis": { "subtitles": "/api/v1/subtitles", "embeddings": "/api/v1/embeddings" } } app.include_router(subtitles_router) app.include_router(embeddings_router) if __name__ == "__main__": import uvicorn uvicorn.run( "app.main:app", host=settings.host, port=settings.port, reload=settings.reload, log_level=settings.log_level.lower() )