- 语音:序数解析(第一个/第二个等)、解析失败计数与 API detail.retry_remaining; 百度 ASR 固定 dev_pid 为普通话;SurgeryPipelineError 支持 extra 并入 HTTP detail。 - Demo:demo 路由与假 RTSP、客户端 index 与 README;BackendResolver 与配置调整。 - 可观测:消耗 TSV 日志、语音文件日志、终端 Markdown 辅助;相关测试与依赖更新。 - 注意:.env 仍被 gitignore,本地密钥不会进入本提交。 Made-with: Cursor
80 lines
2.2 KiB
Python
80 lines
2.2 KiB
Python
import sys
|
|
from contextlib import asynccontextmanager
|
|
|
|
import uvicorn
|
|
from fastapi import FastAPI
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
from loguru import logger
|
|
|
|
from app.api import router as api_router
|
|
from app.config import settings
|
|
from app.database import check_database, engine, init_db_schema
|
|
from app.dependencies import camera_session_manager
|
|
|
|
logger.remove()
|
|
logger.add(
|
|
sys.stderr,
|
|
format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan> - <level>{message}</level>",
|
|
)
|
|
|
|
|
|
@asynccontextmanager
|
|
async def lifespan(app: FastAPI):
|
|
await check_database()
|
|
await init_db_schema()
|
|
logger.info("Database connection verified and schema ensured")
|
|
await camera_session_manager.start_archive_retry_loop()
|
|
yield
|
|
await camera_session_manager.shutdown()
|
|
await engine.dispose()
|
|
logger.info("Database engine disposed")
|
|
|
|
|
|
def create_app() -> FastAPI:
|
|
application = FastAPI(
|
|
title="Operation Room Monitor",
|
|
lifespan=lifespan,
|
|
)
|
|
if settings.demo_cors_enabled:
|
|
origins = settings.parsed_demo_cors_origins()
|
|
if origins:
|
|
application.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origins=origins,
|
|
allow_credentials=origins != ["*"],
|
|
allow_methods=["*"],
|
|
allow_headers=["*"],
|
|
)
|
|
logger.info("CORS enabled for demo client; origins={}", origins)
|
|
application.include_router(api_router)
|
|
if settings.demo_orchestrator_enabled:
|
|
from app.routers import demo_orch
|
|
|
|
application.include_router(demo_orch.router)
|
|
logger.info(
|
|
"Demo orchestrator enabled: POST /internal/demo/orchestrate-and-start",
|
|
)
|
|
else:
|
|
logger.info(
|
|
"Demo orchestrator disabled (DEMO_ORCHESTRATOR_ENABLED=false): "
|
|
"GET /internal/demo/orchestrator-status for status; "
|
|
"POST /internal/demo/orchestrate-and-start is not registered",
|
|
)
|
|
return application
|
|
|
|
|
|
app = create_app()
|
|
|
|
|
|
def main() -> None:
|
|
uvicorn.run(
|
|
"main:app",
|
|
host="0.0.0.0",
|
|
port=38080,
|
|
reload=True,
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|