feat: 语音确认、联调与运维增强
- 语音:序数解析(第一个/第二个等)、解析失败计数与 API detail.retry_remaining; 百度 ASR 固定 dev_pid 为普通话;SurgeryPipelineError 支持 extra 并入 HTTP detail。 - Demo:demo 路由与假 RTSP、客户端 index 与 README;BackendResolver 与配置调整。 - 可观测:消耗 TSV 日志、语音文件日志、终端 Markdown 辅助;相关测试与依赖更新。 - 注意:.env 仍被 gitignore,本地密钥不会进入本提交。 Made-with: Cursor
This commit is contained in:
@@ -6,10 +6,77 @@
|
||||
|
||||
```
|
||||
scripts/demo_client/
|
||||
server.py # 基于 stdlib 的静态服务器;额外暴露 /labels.json
|
||||
index.html # 单文件页面(原生 JS,零构建依赖)
|
||||
server.py # 基于 stdlib 的静态服务器;额外暴露 /labels.json
|
||||
index.html # 单文件页面(原生 JS,零构建依赖)
|
||||
fake_rtsp_from_file.py # 无真摄像头时:把本地视频循环发布为 RTSP(ffmpeg + Docker MediaMTX)
|
||||
```
|
||||
|
||||
## 调试:无真实摄像头,用录好的视频模拟 RTSP
|
||||
|
||||
监控服务**只从 RTSP URL 拉流**(`cv2.VideoCapture`),**没有**「上传视频文件」的 HTTP 接口;在不改 Python 后端的前提下,只能让「摄像头地址」指向一个**真实可连的 RTSP 源。
|
||||
|
||||
推荐做法:在**本机**把视频文件用 **ffmpeg** 推到本机上的 **RTSP 服务**(脚本用 Docker 启动 [MediaMTX](https://github.com/bluenviron/mediamtx)),得到 `rtsp://127.0.0.1:<端口>/<路径>`,再通过**环境变量**告诉后端(**只改配置,不改仓库里的后端代码**):
|
||||
|
||||
**单路**(一个文件、一个 `camera_id`,兼容旧命令):
|
||||
|
||||
```bash
|
||||
# 依赖:ffmpeg、Docker(首次会拉取 bluenviron/mediamtx)
|
||||
cd /path/to/operation-room-monitor-server
|
||||
python3 scripts/demo_client/fake_rtsp_from_file.py /path/to/recording.mp4 --port 18554 --path demo
|
||||
```
|
||||
|
||||
**两路**(两路不同视频、两个 `camera_id`;**一个** MediaMTX、**两路** ffmpeg;每路用不同的 `RTSP_PATH`):
|
||||
|
||||
```bash
|
||||
python3 scripts/demo_client/fake_rtsp_from_file.py --port 18554 \
|
||||
--stream 'or-cam-01|./a.mp4|demo1' \
|
||||
--stream 'or-cam-02|./b.mp4|demo2'
|
||||
```
|
||||
|
||||
`--stream` 格式为 `CAMERA_ID|文件路径|RTSP_PATH`(竖线分隔,整条加引号),生成的 `VIDEO_RTSP_URLS_JSON` 会同时包含 `or-cam-01` 与 `or-cam-02`。
|
||||
|
||||
在**另一终端**启动监控服务前 `source` 或手动 `export` 上述变量,使 `POST /client/surgeries/start` 里使用的 `camera_ids`(如 `or-cam-01,or-cam-02`)能解析到对应 URL。Demo 页里「将 camera_id 填到开始手术」可一键同步两路 id。
|
||||
|
||||
### 监控在 Docker、假 RTSP 在宿主机(推荐联调拓扑)
|
||||
|
||||
常见安排是:**假摄像头脚本**(`fake_rtsp_from_file.py` + ffmpeg + MediaMTX)在**宿主机**终端里跑,推流地址是 `rtsp://127.0.0.1:<端口>/...`;**监控 API 服务**在 **Docker 容器**里跑,容器里的进程要访问宿主机上的 RTSP,应使用:
|
||||
|
||||
- **macOS / Windows Docker Desktop**:`rtsp://host.docker.internal:<端口>/<路径>`
|
||||
- **Linux**:`host.docker.internal` 可能未预置,可任选其一:
|
||||
- 给该服务容器加 `--add-host=host.docker.internal:host-gateway`(Docker 20.10+),或
|
||||
- 直接把 URL 写成宿主在 **docker0/桥接网** 上可达的局域网 IP(如 `192.168.x.x`),保证从容器内 `curl`/`ffprobe` 能通
|
||||
|
||||
`docker-compose` 里可将 `VIDEO_RTSP_URLS_JSON` 写进 `environment:` 或 env 文件;**不要**在仅容器可解析的配置里写 `127.0.0.1` 去指宿主机上的 RTSP(`127.0.0.1` 在容器内是容器自己)。
|
||||
|
||||
若监控与假 RTSP **都在宿主机同一系统**里直接跑(非容器),则用 `rtsp://127.0.0.1:...` 即可;否则应使用上面「容器连宿主」的写法。
|
||||
|
||||
发布失败时,可尝试把输入转码后再推流(示例,需自行调整):
|
||||
|
||||
```bash
|
||||
ffmpeg -re -stream_loop -1 -i recording.mp4 -c:v libx264 -pix_fmt yuv420p -f rtsp -rtsp_transport tcp rtsp://127.0.0.1:18554/demo
|
||||
```
|
||||
|
||||
(仍须先自行启动 MediaMTX 或等价 RTSP 服务端。)
|
||||
|
||||
Demo 页面「调试:两路视频」中可用 **选择视频** / **拖放** 为路1/路2 指定文件,并配合下面 **一键开录** 上传,无需在页面里手抄 `python3` / `export` 命令。若必须完全手跑 `fake_rtsp_from_file.py`,请在上文命令示例与 `export VIDEO_RTSP_URLS_JSON=...` 方式自行在终端完成。
|
||||
|
||||
## 一键开录(不再手抄命令)
|
||||
|
||||
在 §4.1 勾选 **「一键联调」** 后,在「调试」里为**路1/路2**各选一段视频,再点 **开始手术**,浏览器会把两路视频 **multipart 上传到监控 API**(`POST /internal/demo/orchestrate-and-start`),由服务进程依次:
|
||||
|
||||
1. 落盘两路视频到临时目录
|
||||
2. 用 Docker 起 MediaMTX、两路 ffmpeg 推 RTSP(与 `fake_rtsp_from_file.py` 等效)
|
||||
3. 把 `{"or-cam-01":"rtsp://127.0.0.1:…","or-cam-02":"rtsp://127.0.0.1:…"}` 写入 `VIDEO_RTSP_URLS_JSON_FILE`(与开录/拉流同进程,固定本机回环;`DEMO_ORCHESTRATOR_RTSP_JSON_HOST` 仅影响你**手配**假流、给另一进程读 JSON 的用法)
|
||||
4. 调用与普通开录相同逻辑
|
||||
|
||||
**需同时满足**:
|
||||
|
||||
- `.env` 中 `DEMO_ORCHESTRATOR_ENABLED=true`(并重启 API)
|
||||
- 已设置 `VIDEO_RTSP_URLS_JSON_FILE` 指向**可写**的 JSON 文件;Docker 中请用 **bind-mount** 到容器内同一路径
|
||||
- **运行 `main.py` 的进程**能执行本机 `docker` 与 `ffmpeg`(与手动跑 `fake_rtsp_from_file` 相同)。**仅将 API 放 Docker、且不挂载** ` /var/run/docker.sock` 时,容器内往往无法为你在宿主机起 MediaMTX,此时请继续用手动假流方式。
|
||||
|
||||
由于每次解析都会重新读取 `video_rtsp_url_map()`,覆盖 JSON 后**无需重启**主服务即可被下一次开录用到。
|
||||
|
||||
## 运行方式
|
||||
|
||||
```bash
|
||||
@@ -35,6 +102,7 @@ open http://localhost:38081/
|
||||
- §4.3 `GET /client/surgeries/{id}/result` — 以表格渲染 `details` 与 `summary`
|
||||
- §4.4 `GET /client/surgeries/{id}/pending-confirmation` — 支持手动拉取与 2s 自动轮询
|
||||
- §4.5 `POST .../resolve` — 本地麦克风录音 → 16 kHz 单声道 WAV → `multipart/form-data` 上传
|
||||
- **调试:无摄像头** — 两路视频选择与 `camera_id`;一键联调见上文;手跑假流见 `fake_rtsp_from_file.py` 与本文「调试:无真实摄像头」
|
||||
|
||||
右侧「响应日志」按时间倒序展示每次请求的 method/url/status/body,便于联调截图。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user