""" Main FastAPI application for the Virtual Board Member AI System. """ import logging from contextlib import asynccontextmanager from fastapi import FastAPI, Request, HTTPException, status from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.trustedhost import TrustedHostMiddleware from fastapi.responses import JSONResponse import structlog from app.core.config import settings from app.core.database import engine, Base from app.middleware.tenant import TenantMiddleware from app.api.v1.api import api_router from app.services.vector_service import vector_service from app.core.cache import cache_service from app.core.auth import auth_service # Configure structured logging structlog.configure( processors=[ structlog.stdlib.filter_by_level, structlog.stdlib.add_logger_name, structlog.stdlib.add_log_level, structlog.stdlib.PositionalArgumentsFormatter(), structlog.processors.TimeStamper(fmt="iso"), structlog.processors.StackInfoRenderer(), structlog.processors.format_exc_info, structlog.processors.UnicodeDecoder(), structlog.processors.JSONRenderer() ], context_class=dict, logger_factory=structlog.stdlib.LoggerFactory(), wrapper_class=structlog.stdlib.BoundLogger, cache_logger_on_first_use=True, ) logger = structlog.get_logger() @asynccontextmanager async def lifespan(app: FastAPI): """Application lifespan manager.""" # Startup logger.info("Starting Virtual Board Member AI System") # Initialize database try: Base.metadata.create_all(bind=engine) logger.info("Database tables created/verified") except Exception as e: logger.error(f"Database initialization failed: {e}") raise # Initialize services try: # Initialize vector service if await vector_service.health_check(): logger.info("Vector service initialized successfully") else: logger.warning("Vector service health check failed") # Initialize cache service if cache_service.redis_client: logger.info("Cache service initialized successfully") else: logger.warning("Cache service initialization failed") # Initialize auth service if auth_service.redis_client: logger.info("Auth service initialized successfully") else: logger.warning("Auth service initialization failed") except Exception as e: logger.error(f"Service initialization failed: {e}") raise logger.info("Virtual Board Member AI System started successfully") yield # Shutdown logger.info("Shutting down Virtual Board Member AI System") # Cleanup services try: if vector_service.client: vector_service.client.close() logger.info("Vector service connection closed") if cache_service.redis_client: await cache_service.redis_client.close() logger.info("Cache service connection closed") if auth_service.redis_client: await auth_service.redis_client.close() logger.info("Auth service connection closed") except Exception as e: logger.error(f"Service cleanup failed: {e}") logger.info("Virtual Board Member AI System shutdown complete") # Create FastAPI application app = FastAPI( title=settings.PROJECT_NAME, description="Enterprise-grade AI assistant for board members and executives", version=settings.VERSION, openapi_url=f"{settings.API_V1_STR}/openapi.json", docs_url="/docs", redoc_url="/redoc", lifespan=lifespan ) # Add middleware app.add_middleware( CORSMiddleware, allow_origins=settings.ALLOWED_HOSTS, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) app.add_middleware( TrustedHostMiddleware, allowed_hosts=settings.ALLOWED_HOSTS ) # Add tenant middleware app.add_middleware(TenantMiddleware) # Global exception handler @app.exception_handler(Exception) async def global_exception_handler(request: Request, exc: Exception): """Global exception handler.""" logger.error( "Unhandled exception", path=request.url.path, method=request.method, error=str(exc), exc_info=True ) return JSONResponse( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content={"detail": "Internal server error"} ) # Health check endpoint @app.get("/health") async def health_check(): """Health check endpoint.""" health_status = { "status": "healthy", "version": settings.VERSION, "services": {} } # Check vector service try: vector_healthy = await vector_service.health_check() health_status["services"]["vector"] = "healthy" if vector_healthy else "unhealthy" except Exception as e: logger.error(f"Vector service health check failed: {e}") health_status["services"]["vector"] = "unhealthy" # Check cache service try: cache_healthy = cache_service.redis_client is not None health_status["services"]["cache"] = "healthy" if cache_healthy else "unhealthy" except Exception as e: logger.error(f"Cache service health check failed: {e}") health_status["services"]["cache"] = "unhealthy" # Check auth service try: auth_healthy = auth_service.redis_client is not None health_status["services"]["auth"] = "healthy" if auth_healthy else "unhealthy" except Exception as e: logger.error(f"Auth service health check failed: {e}") health_status["services"]["auth"] = "unhealthy" # Overall health status all_healthy = all( status == "healthy" for status in health_status["services"].values() ) if not all_healthy: health_status["status"] = "degraded" return health_status # Include API router app.include_router(api_router, prefix=settings.API_V1_STR) # Root endpoint @app.get("/") async def root(): """Root endpoint.""" return { "message": "Virtual Board Member AI System", "version": settings.VERSION, "docs": "/docs", "health": "/health" } if __name__ == "__main__": import uvicorn uvicorn.run( "app.main:app", host=settings.HOST, port=settings.PORT, reload=settings.DEBUG, log_level="info" )