import sys from contextlib import asynccontextmanager import uvicorn from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from loguru import logger from app.api import router as api_router from app.config import settings from app.database import check_database, engine from app.dependencies import build_container def configure_logging() -> None: """集中配置 loguru sink;由 create_app 显式调用,避免 import-time 副作用。""" logger.remove() logger.add( sys.stderr, format=( "{time:YYYY-MM-DD HH:mm:ss} | " "{level: <8} | " "{name}:{function} - {message}" ), ) @asynccontextmanager async def lifespan(app: FastAPI): await check_database() logger.info( "Database connection verified; ensure schema is applied with " "`alembic upgrade head` before serving traffic" ) container = build_container(settings) app.state.container = container await container.start() try: yield finally: await container.shutdown() await engine.dispose() logger.info("Database engine disposed") def create_app() -> FastAPI: configure_logging() application = FastAPI( title="Operation Room Monitor", lifespan=lifespan, ) if settings.demo_cors_enabled: origins = settings.parsed_demo_cors_origins() if origins: application.add_middleware( CORSMiddleware, allow_origins=origins, allow_credentials=origins != ["*"], allow_methods=["*"], allow_headers=["*"], ) logger.info("CORS enabled for demo client; origins={}", origins) application.include_router(api_router) if settings.demo_orchestrator_enabled: from app.routers import demo_orch application.include_router(demo_orch.router) logger.info( "Demo orchestrator enabled: POST /internal/demo/orchestrate-and-start", ) else: logger.info( "Demo orchestrator disabled (DEMO_ORCHESTRATOR_ENABLED=false): " "GET /internal/demo/orchestrator-status for status; " "POST /internal/demo/orchestrate-and-start is not registered", ) return application app = create_app() def main() -> None: uvicorn.run( "main:app", host=settings.server_host, port=settings.server_port, reload=False, ) if __name__ == "__main__": main()