main.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. from __future__ import annotations
  2. from contextlib import asynccontextmanager
  3. from pathlib import Path
  4. from fastapi import FastAPI
  5. from fastapi.middleware.cors import CORSMiddleware
  6. from fastapi.staticfiles import StaticFiles
  7. from sqlalchemy import text
  8. from app import __version__
  9. from app.agents.runtime import get_agent_runtime
  10. from app.api.v1.router import api_router
  11. from app.core.config import settings
  12. from app.core.errors import install_exception_handlers
  13. from app.core.logging import setup_logging
  14. from app.core.middleware import RequestContextMiddleware
  15. from app.db.init_db import init_db
  16. from app.db.session import SessionLocal
  17. PROJECT_ROOT = Path(__file__).resolve().parents[1]
  18. FRONTEND_DIR = PROJECT_ROOT / "frontend"
  19. class FrontendStaticFiles(StaticFiles):
  20. async def get_response(self, path: str, scope):
  21. response = await super().get_response(path, scope)
  22. response.headers["Cache-Control"] = "no-store, no-cache, must-revalidate, max-age=0"
  23. response.headers["Pragma"] = "no-cache"
  24. response.headers["Expires"] = "0"
  25. return response
  26. @asynccontextmanager
  27. async def lifespan(_: FastAPI):
  28. setup_logging()
  29. init_db()
  30. if settings.seed_demo_data:
  31. from app.db.seed import seed_demo_data
  32. with SessionLocal() as db:
  33. seed_demo_data(db)
  34. yield
  35. app = FastAPI(
  36. title=settings.app_name,
  37. version=__version__,
  38. description=(
  39. "基于 FastAPI 与 DeepAgent 的矿山通防业务智能管控平台后端。"
  40. "普通业务数据通过 REST API 管理,诊断、评价和知识问答通过 DeepAgent 工作流增强。"
  41. ),
  42. lifespan=lifespan,
  43. docs_url="/docs",
  44. redoc_url="/redoc",
  45. openapi_url="/openapi.json",
  46. )
  47. app.add_middleware(
  48. CORSMiddleware,
  49. allow_origins=settings.cors_origin_list,
  50. allow_credentials=True,
  51. allow_methods=["*"],
  52. allow_headers=["*"],
  53. )
  54. app.add_middleware(RequestContextMiddleware)
  55. install_exception_handlers(app)
  56. app.include_router(api_router, prefix=settings.api_v1_prefix)
  57. if FRONTEND_DIR.is_dir():
  58. app.mount(
  59. "/app",
  60. FrontendStaticFiles(directory=FRONTEND_DIR, html=True),
  61. name="frontend",
  62. )
  63. @app.get("/", tags=["系统"], summary="服务入口")
  64. def root() -> dict:
  65. return {
  66. "name": settings.app_name,
  67. "version": __version__,
  68. "docs": "/docs",
  69. "api": settings.api_v1_prefix,
  70. "app": "/app/",
  71. }
  72. @app.get("/health", tags=["系统"], summary="服务健康检查")
  73. def health() -> dict:
  74. database_status = "ok"
  75. database_error = ""
  76. try:
  77. with SessionLocal() as db:
  78. db.execute(text("SELECT 1"))
  79. except Exception as exc: # pragma: no cover - depends on external DB
  80. database_status = "error"
  81. database_error = f"{type(exc).__name__}: {exc}"
  82. return {
  83. "status": "ok" if database_status == "ok" else "down",
  84. "version": __version__,
  85. "environment": settings.app_env,
  86. "database": {
  87. "dialect": settings.database_dialect,
  88. "status": database_status,
  89. "error": database_error,
  90. },
  91. "agent": get_agent_runtime().describe(),
  92. }
  93. if __name__ == "__main__":
  94. import uvicorn
  95. uvicorn.run(
  96. "app.main:app",
  97. host=settings.host,
  98. port=settings.port,
  99. reload=settings.debug,
  100. )