feat: 站点 JSON、语音终端 WebSocket 指派与客户端联调

- 用 OR_SITE_CONFIG_JSON_FILE 统一术间配置(video_rtsp_urls + voice_or_room_bindings)
- VoiceTerminalHub:assignment、WS 推送与 HTTP 查询;开录/停录后 notify
- 一键联调 orchestrate-and-start 与 /client/surgeries/start 共用指派逻辑,修复 demo 路径不发 WS
- 语音桌面端:SIGINT 退出、shutdown 清理、仅 WS 指派、固定 pending 轮询间隔、界面仅保留录音时长
- 新增/调整契约与绑定测试,文档与示例配置同步

Made-with: Cursor
This commit is contained in:
Kevin
2026-04-27 11:21:16 +08:00
parent 4c3f9a367b
commit 6b3adb4ad8
36 changed files with 1194 additions and 162 deletions

View File

@@ -72,9 +72,12 @@ class _StubCameraSessionManager:
)
await self._registry.register(surgery_id, run)
def set_voice_terminal_id(self, surgery_id: str, terminal_id: str | None) -> None:
self._real.set_voice_terminal_id(surgery_id, terminal_id)
async def stop_surgery(
self, surgery_id: str, *, require_active: bool = True
) -> None:
) -> str | None:
run = await self._registry.unregister(surgery_id)
if run is None:
if require_active:
@@ -84,9 +87,11 @@ class _StubCameraSessionManager:
"RECORDING_NOT_STOPPED",
"停录未能完成:当前没有该手术的活跃录制会话。",
)
return
return None
voice_tid = run.state.voice_terminal_id
details = list(run.state.details)
await self._archive.persist_or_archive(surgery_id, details)
return voice_tid
def __getattr__(self, name: str) -> Any:
return getattr(self._real, name)