Files
operating-room-monitor-server/docs/客户端手术通信接口说明.md
2026-04-28 17:19:25 +08:00

23 KiB
Raw Blame History

手术室监控服务:客户端手术通信接口说明

能力概览

能力 说明
探活 GET /health,用于检查进程和数据库状态,详见 5.1 节。
开始手术 POST /client/surgeries/start,只有在开录确认成功后才返回 200
结束手术 POST /client/surgeries/end,只有在停录确认成功后才返回 200
查询结果 GET /client/surgeries/{surgery_id}/result,至少存在一条消耗明细时返回 200;否则返回 503,常见错误码为 RESULT_NOT_READY
待确认播报 官方浏览器客户端(仓库 web/voice-confirmation/,可独立部署):同一 WebSocket 上推送 voice_pending(载荷与 GET .../pending-confirmation 成功体一致,另含 type);无队首时 voice_pending_empty不轮询 GET第三方仍可用 GET .../pending-confirmation 拉取队首。
待确认答复 POST /client/surgeries/{surgery_id}/pending-confirmation/{confirmation_id}/resolve,上传医生答复的 WAV 录音,服务端完成 ASR 后入账或关闭。该录音与播报音频无关。

1. 服务与基础信息

项目 说明
协议 HTTP/HTTPS
端口 38080,生产环境以实际入口为准
路由 无全局前缀;业务接口位于 /client/...,健康检查位于 /health
start / end 请求体 JSON
resolve 请求体 multipart/form-data,字段名为 audio
在线文档 /docs/redoc
语音确认官方页面 仓库 web/voice-confirmation/(静态资源,与 API 分宿;需为浏览器配置 CORS见该目录 README.md

2. 摄像头 ID 与 RTSP

RTSP 地址、账号、口令等由客户端对接工程师提供给服务端运维,运维再写入服务端环境。客户端只在 POST /client/surgeries/start 中传 camera_ids

camera_id RTSP 备注
or-cam-01 rtsp://admin:Aa183137@192.168.3.2:554/Streaming/Channels/101 测试手术室,主码流 ch.101
or-cam-02 rtsp://admin:Aa183137@192.168.3.3:554/Streaming/Channels/101 同上
or-cam-03 rtsp://admin:Aa183137@192.168.3.4:554/Streaming/Channels/101 同上
or-cam-04 rtsp://admin:Aa183137@192.168.3.5:554/Streaming/Channels/101 同上

Docker 部署API 在容器内拉流时,上表这类术间摄像头局域网 IP通常可继续使用(出站经宿主机路由,须宿主机已能访问该网段)。若 RTSP 实际跑在宿主机本机假流等URL 中的主机应使用 host.docker.internal,勿写 127.0.0.1;详见 docs/video-backends.mddocker-compose.prod.yml

3. HTTP 路由一览

序号 方法 路径 说明
1 GET /health 探活
2 POST /client/surgeries/start 开始手术
3 POST /client/surgeries/end 结束手术
4 GET /client/surgeries/{surgery_id}/result 查询手术结果
5 GET /client/surgeries/{surgery_id}/pending-confirmation 拉取待确认耗材
6 POST /client/surgeries/{surgery_id}/pending-confirmation/{confirmation_id}/resolve 提交医生答复
7 GET /client/voice-terminals/{terminal_id}/assignment 可选:查询当前指派(调试或简易集成;官方浏览器客户端仅用 WebSocket
8 WS /client/voice-terminals/ws?terminal_id=... 语音终端长连接,接收开录/停录指派(推荐;与 web/voice-confirmation 共用)

术间与语音终端绑定(服务端配置)

  • 唯一配置源:环境变量 OR_SITE_CONFIG_JSON_FILE 指向手术室 站点 JSONUTF-8须同时包含 video_rtsp_urlsvoice_or_room_bindings(见仓库 app/resources/or_site_config.sample.json)。voice_or_room_bindings 为数组,每项含 or_room_idcamera_idsvoice_terminal_idcamera_ids 在数组内须唯一,voice_terminal_id 全局唯一。
  • POST /client/surgeries/startHTTP 200 且开录已成功 后:用请求体中的 camera_idsvoice_or_room_bindings 中解析终端(精确匹配术间 camera 集合,或 开录路集为某术间 camera 集合的子集 时匹配该术间);命中则向对应 voice_terminal_id 推送 action":"start"(并更新 assignment未配置站点文件、或数组为空、或未命中则仅打日志不影响 200。
  • POST /client/surgeries/end 在停录 HTTP 200 后:向该手术会话记录的终端推送 action":"end"(并清除 assignment
  • 推送 JSON 形如:{"type":"voice_assignment","action":"start"|"end","surgery_id":"123456"}
  • 待确认队列(与 HTTP GET 成功体对齐):有新队首或队首变化时推送 {"type":"voice_pending", "surgery_id":"...", "confirmation_id":"...", "pending_queue_length":1, "pending_queue_position":1, "pending_cumulative_ordinal":1, "prompt_text":"...", "prompt_audio_mp3_base64":"...", "options":[...], "model_top1_label":"...", "model_top1_confidence":0.0, "created_at":"..."}(字段与 GET /client/surgeries/{surgery_id}/pending-confirmation 的 200 响应相同,并多一个 type。FIFO 无待确认项时推送 {"type":"voice_pending_empty","surgery_id":"123456"}。触发时机包括:开录指派后(后台任务)、视觉入队待确认后、医生 resolve 成功弹出队首后、终端 WebSocket 刚连接且当前已有指派 时(先补发 voice_assignment start再补发队首或 empty
  • 多 worker:当前实现为进程内内存;多 Uvicorn worker 时需 sticky session 或 Redis 等另行同步。

4. 流程

4.1 时序图

sequenceDiagram
    participant Client as 客户端
    participant Server as 服务端

    Client->>Server: POST /client/surgeries/start
    Note over Client,Server: body: surgery_id, camera_ids, candidate_consumables
    Server-->>Client: 200 accepted开录已确认

    par 术中
        loop 轮询结果
            Client->>Server: GET .../result
            Server-->>Client: 200 或 503 RESULT_NOT_READY
        end
        loop 轮询待确认
            Client->>Server: GET .../pending-confirmation
            Server-->>Client: 200 或 404
            opt 有待确认
                Client->>Client: 播放 prompt_audio_mp3_base64
                Client->>Server: POST .../resolvemultipart audio
                Server-->>Client: 200 accepted
            end
        end
    end

    Client->>Server: POST /client/surgeries/end
    Server-->>Client: 200 accepted停录已确认

    Client->>Server: GET .../result
    Server-->>Client: 200持久化后可查时返回

4.2 状态图

flowchart LR
    A[未开始] -->|start 200| B[录制 / 推理中]
    B -->|result 200| C[有消耗数据可查]
    B -->|pending 200| D[待确认]
    D -->|resolve| B
    B -->|end 200| E[已结束]
    E -->|result 200| C

5. 接口详情

路径参数 surgery_id

约束项 说明
长度 固定 6
字符集 仅数字
正则 ^\d{6}$

业务错误响应

多数业务失败在 4xx 或 5xx 下返回如下 JSON

{
  "detail": {
    "code": "错误码字符串",
    "message": "人类可读说明",
    "surgery_id": "123456"
  }
}

5.1 探活

基本信息

项目 内容
方法 GET
路径 /health
请求体

响应说明

HTTP 说明 响应体示例
200 进程正常且数据库可连通 {"status":"ok","database":"connected"}
503 数据库不可用(降级) {"status":"degraded","database":"unavailable"}

5.2 开始手术

基本信息

项目 内容
方法 POST
路径 /client/surgeries/start
Content-Type application/json; charset=utf-8

业务说明

  • 服务端会为 camera_ids 中的每个摄像头建立拉流与推理任务,只有在确认开录成功(如首帧就绪)后才返回 HTTP 200

  • candidate_consumables 为空时,服务端会展开为目录中的全部耗材名。

请求体JSON

字段 类型 必填 说明
surgery_id string 6 位数字
camera_ids string[] 至少 1 个;必须与运维配置的摄像头 ID 完全一致,见第 2 节
candidate_consumables string[] 非空时仅这些名称参与自动记账与待确认;缺省或 [] 时使用全部候选

响应体200

字段 类型 说明
surgery_id string 与请求一致
status string 成功时通常为 accepted
message string 说明文案

状态码

HTTP 说明
200 开录已确认
422 参数校验失败,例如 surgery_id 非 6 位或 camera_ids 为空数组
503 开录未确认或录制子系统故障;detail.code 常见为 RECORDING_CANNOT_START

请求示例

{
  "surgery_id": "123456",
  "camera_ids": ["or-cam-01", "or-cam-02", "or-cam-03", "or-cam-04"],
  "candidate_consumables": ["纱布", "缝线", "止血钳"]
}

响应示例200

{
  "surgery_id": "123456",
  "status": "accepted",
  "message": "摄像头录制已开始,手术已启动。"
}

5.3 结束手术

基本信息

项目 内容
方法 POST
路径 /client/surgeries/end
Content-Type application/json; charset=utf-8

业务说明

停止该 surgery_id 关联的全部摄像头任务,只有在确认停录完成后才返回 200

请求体JSON

字段 类型 必填 说明
surgery_id string 6 位数字

响应体200

字段含义与 5.2 节一致,message 示例为 摄像头录制已停止,手术已结束。

状态码

HTTP 说明
200 停录已确认
422 参数校验失败
503 停录未确认或故障;detail.code 常见为 RECORDING_NOT_STOPPED

请求示例

{
  "surgery_id": "123456"
}

5.4 查询手术结果

基本信息

项目 内容
方法 GET
路径 /client/surgeries/{surgery_id}/result
路径参数 surgery_id
请求体

业务说明

  • 仅当存在至少一条消耗明细时返回 200

  • 无明细(包括已归档但零消耗)、手术未开始、未成功开录或当前尚不可查时,返回 503

  • 上述 503 场景的常见错误码为 RESULT_NOT_READY

响应体200

字段 类型 说明
surgery_id string 手术号
status string 成功时通常为 completed
message string 说明
details array 消耗明细列表,字段见下文
summary array 按 item_id 汇总的结果,字段见下文

details[] 元素

字段 类型 说明
item_id string 物品 ID有目录时多为产品编码否则通常与名称或模型类名一致
item_name string 物品名称
qty integer 本条记录数量,当前恒为 1;一次识别或一次人工确认只追加一条明细
doctor_id string 记账关联的医生或系统标识
timestamp string ISO 8601 时间(date-time

summary[] 元素

字段 类型 说明
item_id string 与明细一致
item_name string 名称,通常取该 item_id 首条明细中的名称
total_quantity integer 该物品在本台手术中的合计数量,>= 0

状态码

HTTP 说明
200 至少有一条明细
422 surgery_id 路径不符合约束
503 RESULT_NOT_READY,当前无可用明细或不可查

响应示例200

{
  "surgery_id": "123456",
  "status": "completed",
  "message": "查询成功。",
  "details": [
    {
      "item_id": "19246-3-14",
      "item_name": "医用纱布敷料",
      "qty": 1,
      "doctor_id": "6611",
      "timestamp": "2026-04-21T10:30:00+08:00"
    }
  ],
  "summary": [
    {
      "item_id": "19246-3-14",
      "item_name": "医用纱布敷料",
      "total_quantity": 1
    }
  ]
}

5.5 拉取待确认耗材

基本信息

项目 内容
方法 GET
路径 /client/surgeries/{surgery_id}/pending-confirmation
路径参数 surgery_id
请求体

业务说明

  • 返回当前 FIFO 队首的一条低置信度识别任务。

  • prompt_audio_mp3_base64 与 prompt_text 内容一致,为标准 Base64 的 MP3 字符串(无换行)。

  • 客户端解码后应按 audio/mpeg 播放。

响应体200

字段 类型 说明
surgery_id string 手术号
confirmation_id string 待确认项 ID提交 5.6 节接口时原样放入路径
pending_queue_length int 当前 FIFO 中仍为 pending 的条数(含本条)
pending_queue_position int 本条在 pending_fifo 中的排队序号1-based队首为 1
pending_cumulative_ordinal int 本场手术中待确认任务累计入队序号(第几条入队)
prompt_text string 播报或展示用语,与 MP3 内容一致
prompt_audio_mp3_base64 string MP3 的 Base64
options array 候选项列表,字段见下文
model_top1_label string 模型原始 Top1 类名,可能不在本台候选内
model_top1_confidence number Top1 置信度
created_at string 创建时间ISO 8601

options[] 元素

字段 类型 说明
label string 展示给医生的选项名称
confidence number 该选项对应的置信度

状态码

HTTP 说明
200 当前有一条待确认
404 无待确认或手术未活跃;常见错误码为 NO_PENDING_CONFIRMATION
422 例如话术为空导致无法 TTS错误码见响应如 TTS_TEXT_EMPTY
503 语音服务未配置或 TTS 失败;例如 BAIDU_NOT_CONFIGUREDTTS_ERROR

5.6 提交待确认结果(医生语音)

基本信息

项目 内容
方法 POST
路径 /client/surgeries/{surgery_id}/pending-confirmation/{confirmation_id}/resolve
Content-Type multipart/form-data

路径参数

参数 约束 说明
surgery_id 6 位数字 同 5.0 节
confirmation_id 长度 1 到 128 与 5.5 节响应中的 confirmation_id 一致

请求体multipart

字段名 类型 必填 说明
audio file 单个 .wav 文件;建议使用 16 kHz 单声道 PCM非 .wav 扩展名会返回 422

业务说明

音频上传至对象存储后执行 ASR 和候选解析。若识别为确认某个候选项,则记一条消耗;若识别为否认全部候选,则不记消耗。

响应体200

字段 类型 说明
surgery_id string 手术号
confirmation_id string 待确认 ID
status string 成功时为 accepted
message string 说明
resolved_label string | null 确认后的耗材名称;否认全部候选时为 null
rejected boolean 是否否认全部候选,不记消耗时为 true
asr_text string | null 语音识别文本
audio_object_key string | null 对象存储中的原始 WAV 键,便于追溯

状态码

HTTP 说明
200 已受理并完成解析
404 确认项不存在或手术未活跃;例如 CONFIRMATION_NOT_FOUND
409 当前确认项已处理过;例如 CONFIRMATION_ALREADY_RESOLVED
422 空文件、非 .wavVOICE_AUDIO_INVALID、ASR/解析失败等,具体错误码见响应
503 MinIO、百度等依赖不可用例如 MINIO_NOT_CONFIGUREDMINIO_UPLOAD_FAILEDBAIDU_NOT_CONFIGURED

cURL 示例

curl -sS -X POST \
  "http://<主机>:38080/client/surgeries/123456/pending-confirmation/<confirmation_id>/resolve" \
  -F "audio=@/path/to/voice.wav;type=audio/wav"

5.7 语音终端 assignmentHTTP可选

路径 GET /client/voice-terminals/{terminal_id}/assignment

仓库内 手术室耗材语音确认浏览器客户端web/voice-confirmation/)仅通过 §5.8 WebSocket 接收指派,不调用本接口。此处供运维脚本、未实现 WS 的第三方临时拉取 active_surgery_id

响应 200

字段 类型 说明
voice_terminal_id string 与路径一致
active_surgery_id string | null 当前指派手术 6 位号;无指派时为 null

5.8 语音终端 WebSocket

路径 GET ws://<主机>:<端口>/client/voice-terminals/ws?terminal_id=<终端ID>HTTPS 部署时使用 wss://

说明

  • 连接成功后,若服务端已有该终端的 assignment会立即收到一条 action":"start" 的 JSON与下文推送格式一致
  • 术中由服务端在 start / end 成功后 向已连接终端推送 JSON{"type":"voice_assignment","action":"start"|"end","surgery_id":"123456"}
  • 客户端可发送任意文本作心跳;服务端当前仅依赖 WebSocket 协议级 ping由网关或客户端库实现