"""FastAPI 服务入口。 该模块负责: 1. 从环境变量加载配置; 2. 初始化测高服务; 3. 注册生命周期事件与 HTTP 路由; 4. 启动 Uvicorn 服务。 """ import os import uvicorn from fastapi import FastAPI, HTTPException from fastapi.staticfiles import StaticFiles from api_config import ApiConfig from cargo_service import CargoHeightService from request_logging import setup_request_logging # 读取配置并创建核心服务实例。 config = ApiConfig.from_env() service = CargoHeightService(config) # 创建 Web 应用对象。 app = FastAPI(title="Cargo Height API") # 安装请求日志中间件,用于记录每次 API 调用的响应与耗时。 setup_request_logging( app, max_response_len=config.request_log_max_len, max_bytes=config.request_log_max_bytes, backup_count=config.request_log_backup_count, ) # 暴露本地样例图片目录,便于通过 HTTP 直接访问保存的测量图像。 sample_images_dir = os.path.join(os.getcwd(), "sample_images") os.makedirs(sample_images_dir, exist_ok=True) app.mount("/sample_images", StaticFiles(directory=sample_images_dir), name="sample_images") @app.on_event("startup") def on_startup() -> None: """应用启动时初始化相机管线与滤波器等资源。""" service.startup() @app.on_event("shutdown") def on_shutdown() -> None: """应用关闭时释放相机资源,避免设备占用。""" service.shutdown() @app.get("/height") def get_height(): """执行一次测高流程并返回结果。 返回值中包含: - `height_mm`: 估计高度(毫米); - `samples`: 本次采样的原始距离列表; - `image_paths`: 相关彩色图与深度标注图路径。 """ result = service.measure_height() if result is None: # 采样不足时返回 503,表示服务暂时无法给出有效结果。 raise HTTPException(status_code=503, detail="Insufficient valid samples from depth camera") return result @app.get("/health") def health(): """健康检查接口,用于探活。""" return {"status": "ok"} def main() -> None: """启动 Uvicorn 服务器。""" uvicorn.run("api:app", host=config.api_host, port=config.api_port, log_level="info") if __name__ == "__main__": main()