main.py 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. """FastAPI 主应用(CORS / health / Swagger / startup)"""
  2. from contextlib import asynccontextmanager
  3. from fastapi import FastAPI
  4. from fastapi.middleware.cors import CORSMiddleware
  5. from ..config import get_settings, print_config, validate_config
  6. from ..utils.logger import get_logger, setup_logging
  7. from .exception_handlers import register_exception_handlers
  8. from .routes import movies, recommend
  9. settings = get_settings()
  10. logger = get_logger("app.api")
  11. OPENAPI_TAGS = [
  12. {"name": "System", "description": "健康检查与服务信息"},
  13. {"name": "Movies", "description": "确定性 TMDB 搜片 / 发现(不经 LLM)"},
  14. {"name": "Recommend", "description": "多智能体智能推荐(HelloAgents + TMDB Tool)"},
  15. ]
  16. @asynccontextmanager
  17. async def lifespan(app: FastAPI):
  18. setup_logging()
  19. logger.info("%s v%s 启动中", settings.app_name, settings.app_version)
  20. print_config()
  21. validate_config()
  22. # 0.0.0.0 仅表示监听所有网卡,浏览器请用 localhost / 127.0.0.1
  23. docs_host = "127.0.0.1" if settings.host in ("0.0.0.0", "::") else settings.host
  24. logger.info("Swagger: http://%s:%s/docs", docs_host, settings.port)
  25. yield
  26. logger.info("应用关闭")
  27. app = FastAPI(
  28. title=settings.app_name,
  29. version=settings.app_version,
  30. description=(
  31. "HelloAgents + TMDB 的 LLM 电影推荐 Demo API。\n\n"
  32. "- **Movies**:确定性片库通道(search / discover)\n"
  33. "- **Recommend**:多智能体推荐(画像 → 检索 → 推荐)\n\n"
  34. "密钥仅通过环境变量配置,详见 `.env.example`。"
  35. ),
  36. docs_url="/docs",
  37. redoc_url="/redoc",
  38. openapi_url="/openapi.json",
  39. openapi_tags=OPENAPI_TAGS,
  40. swagger_ui_parameters={
  41. "docExpansion": "list",
  42. "defaultModelsExpandDepth": 1,
  43. "persistAuthorization": True,
  44. },
  45. lifespan=lifespan,
  46. )
  47. register_exception_handlers(app)
  48. app.add_middleware(
  49. CORSMiddleware,
  50. allow_origins=settings.get_cors_origins_list(),
  51. allow_credentials=True,
  52. allow_methods=["*"],
  53. allow_headers=["*"],
  54. )
  55. app.include_router(movies.router, prefix="/api")
  56. app.include_router(recommend.router, prefix="/api")
  57. @app.get("/", tags=["System"], summary="服务根信息")
  58. async def root():
  59. return {
  60. "name": settings.app_name,
  61. "version": settings.app_version,
  62. "status": "running",
  63. "docs": "/docs",
  64. "redoc": "/redoc",
  65. "openapi": "/openapi.json",
  66. }
  67. @app.get("/health", tags=["System"], summary="健康检查")
  68. async def health():
  69. return {
  70. "status": "healthy",
  71. "service": settings.app_name,
  72. "version": settings.app_version,
  73. "tmdb_configured": settings.has_tmdb_credentials(),
  74. }