main.py 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. import logging
  2. from contextlib import asynccontextmanager
  3. from fastapi import FastAPI, Request
  4. from fastapi.responses import FileResponse
  5. from fastapi.staticfiles import StaticFiles
  6. from app.api import api_router
  7. from app.api.camera import capture_pair_via_mqtt
  8. from app.services import CameraUnavailableError, get_camera_service
  9. from app.core.config import settings
  10. logging.basicConfig(level=logging.INFO)
  11. logger = logging.getLogger(__name__)
  12. settings.static.ensure_directories()
  13. @asynccontextmanager
  14. async def lifespan(_: FastAPI):
  15. """
  16. FastAPI 生命周期管理。
  17. 启动阶段会尝试预热相机,这样第一次请求拍照时更快。
  18. 但这里不会因为相机异常而阻止整个服务启动,
  19. 因为有时你可能还需要先看接口文档、做健康检查或排查环境。
  20. """
  21. camera_service = get_camera_service()
  22. try:
  23. camera_service.initialize()
  24. logger.info("树莓派相机预热完成。")
  25. except CameraUnavailableError as exc:
  26. logger.warning("相机预热失败,拍照接口暂时不可用:%s", exc)
  27. try:
  28. yield
  29. finally:
  30. camera_service.close()
  31. logger.info("相机资源已关闭。")
  32. app = FastAPI(
  33. title=settings.app.title,
  34. version=settings.app.version,
  35. description=settings.app.description,
  36. lifespan=lifespan,
  37. )
  38. app.include_router(api_router, prefix="/api")
  39. app.mount("/static", StaticFiles(directory=str(settings.static.root_dir)), name="static")
  40. @app.get("/", include_in_schema=False)
  41. def read_root() -> FileResponse:
  42. return FileResponse(settings.static.index_path)
  43. @app.api_route("/capture-pair", methods=["GET", "POST"], include_in_schema=False)
  44. def capture_pair_alias(request: Request):
  45. return capture_pair_via_mqtt(request)
  46. @app.get("/health", summary="健康检查")
  47. def health_check() -> dict[str, object]:
  48. """
  49. 健康检查接口。
  50. 这个接口不强依赖相机真实可用,只返回服务当前状态和相机是否已初始化。
  51. 在部署脚本、容器探针或反向代理检查中都比较实用。
  52. """
  53. camera_service = get_camera_service()
  54. return {
  55. "status": "ok",
  56. "camera_initialized": camera_service.is_initialized,
  57. "app_name": settings.app.title,
  58. "app_version": settings.app.version,
  59. }