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

@@ -5,7 +5,7 @@
## 环境
- Python **3.13+**(与主项目一致)
- 安装可选依赖组 `**voice-client`**PySide6、httpx、numpy、sounddevice
- 安装可选依赖组 **voice-client**PySide6、httpx、numpy、sounddevice、websocket-client
```bash
cd /path/to/operation-room-monitor-server
@@ -38,7 +38,15 @@ start_voice_confirmation_client.bat
uv run --group voice-client voice-confirmation-client
```
在界面中填写 **服务端 Base URL**、**6 位手术号**,点击 **开始监控**
**术间 / 摄像头 / 语音终端对应关系**只在服务端 `**OR_SITE_CONFIG_JSON_FILE`** 里维护一份(`voice_or_room_bindings`);桌面程序不读该文件
本机要做的只有两件事:**服务端 Base URL**,以及 **本机语音终端 ID**(须等于 JSON 里某条 `voice_terminal_id`)。**手术号不在客户端输入**:勾选 **启用服务端自动指派** 后,开录/停录仅通过 **WebSocket** `voice_assignment` 下发(断线后自动重连,不用 HTTP 轮询);界面只读展示当前手术号;停录后自动停止。可用 **停止监控(本机)** 做本地紧急中断。
可选:用环境变量 `**VOICE_TERMINAL_ID`** 预填界面里的「本机语音终端 ID」仅客户端进程使用**不要**写进监控服务的 `.env`)。
## 日志loguru
客户端使用 **loguru****右侧日志区**与**启动终端 stderr** 会同时输出。开录无反应时请看是否出现「本机语音终端 ID 为空」、`WebSocket 已连接``收到 voice_assignment start`、或反复「WebSocket 断开」等行。
## 音频说明
@@ -76,5 +84,5 @@ uv run --group voice-client-build python scripts/build_voice_client.py
## 与浏览器 Demo 的差异
- 浏览器 Demo`scripts/demo_client/`)默认 **10 秒** 轮询;本客户端默认 **5 秒**,可在界面修改。
- 本客户端无「开始/结束手术」按钮;手术需由既有流程或他端调用 `POST /client/surgeries/start` 启动。
- 本客户端无「开始/结束手术」按钮;手术需由既有流程或他端调用 `POST /client/surgeries/start` 启动;若启用自动指派,开录成功后本机将自动开始待确认轮询