"""FastAPI application entrypoint.""" from contextlib import asynccontextmanager from fastapi import FastAPI, Request from fastapi.encoders import jsonable_encoder from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import JSONResponse from loguru import logger from app.api.models import ErrorResponse from app.api.routes import api_router from app.config.logging import setup_logging from app.config.settings import settings from app.shared.bootstrap import cleanup_runtime_dependencies, preload_runtime_dependencies from app.shared.errors import VectorStoreSchemaError # Keep module behavior explicit so the backend flow stays easy to audit. setup_logging(level="INFO" if not settings.debug else "DEBUG") @asynccontextmanager async def lifespan(app: FastAPI): """Application lifecycle hooks.""" logger.info(f"启动 {settings.app_name} v{settings.app_version}") logger.info(f"调试模式: {settings.debug}") logger.info("预加载LLM客户端...") preload_runtime_dependencies() yield logger.info("应用关闭,执行清理...") cleanup_runtime_dependencies() app = FastAPI( title=settings.app_name, description=( "AI+合规智能中枢 - 法律法规文档解析入库功能\n\n" "支持PDF/DOCX文档解析、智能分块、向量嵌入、Milvus存储" ), version=settings.app_version, lifespan=lifespan, docs_url="/docs", redoc_url="/redoc", ) app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) app.include_router(api_router, prefix="/api/v1") @app.exception_handler(VectorStoreSchemaError) async def vector_store_schema_exception_handler(request: Request, exc: VectorStoreSchemaError): """Return a stable JSON response for vector store schema/runtime errors.""" logger.error(f"向量库 schema 异常: {exc}") return JSONResponse( status_code=500, content=jsonable_encoder( ErrorResponse( error="VectorStoreSchemaError", message=str(exc), ) ), ) @app.exception_handler(Exception) async def global_exception_handler(request: Request, exc: Exception): """Global exception handler.""" logger.error(f"未处理的异常: {exc}") return JSONResponse( status_code=500, content=jsonable_encoder( ErrorResponse( error="InternalServerError", message=str(exc), ) ), ) @app.get("/health", tags=["health"]) async def health_check(): """Health check endpoint.""" return { "status": "healthy", "app": settings.app_name, "version": settings.app_version, } @app.get("/", tags=["root"]) async def root(): """Root endpoint.""" return { "message": f"Welcome to {settings.app_name}", "version": settings.app_version, "docs": "/docs", "health": "/health", } if __name__ == "__main__": import uvicorn uvicorn.run( "app.api.main:app", host=settings.api_host, port=settings.api_port, reload=settings.debug, log_level="info", )