Files
operating-room-monitor-server/docs/客户端手术通信接口说明.md

37 KiB
Executable File
Raw Permalink Blame History

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

Changelog

对接方请按部署版本核对本节;已发布路径与字段语义以正文为准,本节仅记录相对上一版的客户端需改动点。

2026-05-26

行为 / 运维

变更
POST /client/surgeries/start 默认 RTSP 开录等待由 45s 调至 90s;客户端 HTTP 超时建议 ≥ 300s
服务端日志 应用日志持久化至 backend/logs/app/server.log7 天轮转/保留access 日志隐藏 GET /health 200 与 pending 轮询 404

2026-05-26

文档

接口 变更 客户端需改动
POST /internal/demo/offline-batch 及配套 GET 新增 §5.7§5.9:链路 3 离线 MP4 上传、耗时轮询、标注视频下载 非 RTSP 集成时可走上传视频路径;仍用 GET /client/surgeries/{surgery_id}/result 查消耗,无需 start / end

2026-05-25

行为对齐(实现已与正文一致)

接口 变更 客户端需改动
GET /client/surgeries/{surgery_id}/result 无明细时的 503 统一返回 detail.code = RESULT_NOT_READYdetail.message 仍为人可读原因) 勿再依赖已废弃的 SURGERY_NOT_STARTEDSURGERY_STARTINGSURGERY_IN_PROGRESS_NO_DETAILSSURGERY_ENDED_NO_CONSUMPTION 等细分码;判断 503 时用 RESULT_NOT_READY
POST .../pending-confirmation/{confirmation_id}/resolve ASR/解析可重试失败(如 VOICE_ASR_FAILED)改回 HTTP 422,不再返回 200 + status: "failed" 删除对 200/status=failed/error_code 的处理;可重试失败按 422 + detail.code 重录上传
POST /client/surgeries/startcandidate_consumables 新增:可仅传产品编码label_id,与 consumable_classifier_labels.yaml 一致) 可传 ["14764-2-4"][{"消耗品编号":"14764-2-4"}];服务端解析为类名后参与推理,响应与其它字段不变

未变更

  • /client/... 路由路径、HTTP 方法、surgery_id 约束、成功体字段名与 §5 各节描述一致。

能力概览

能力 说明
探活 GET /health,用于检查进程和数据库状态,详见 5.1 节。
开始手术 POST /client/surgeries/start,只有在开录确认成功后才返回 200链路 1 · 真 RTSP)。
结束手术 POST /client/surgeries/end,只有在停录确认成功后才返回 200(链路 1
上传视频 POST /internal/demo/offline-batch,上传单路 MP4 离线推理(链路 3无需 start / end,不触发语音终端;详见 5.7 节。需运维开启 DEMO_ORCHESTRATOR_ENABLED=true
查询结果 GET /client/surgeries/{surgery_id}/result,至少存在一条消耗明细时返回 200;否则返回 503detail.code 为 RESULT_NOT_READY。链路 1 / 3 共用。
待确认播报 官方浏览器客户端(仓库 clients/voice-confirmation/,可独立部署):同一 WebSocket 上推送 voice_pending(载荷与 GET .../pending-confirmation 成功体一致,另含 type);无队首时 voice_pending_empty不轮询 GET第三方仍可用 GET .../pending-confirmation 拉取队首。链路 3 无待确认。
待确认答复 POST /client/surgeries/{surgery_id}/pending-confirmation/{confirmation_id}/resolve,上传医生答复的 WAV 录音,服务端完成 ASR 后入账或关闭。该录音与播报音频无关。

1. 服务与基础信息

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

局域网部署时API 应监听或发布到可被语音终端访问的地址(例如 0.0.0.0:38080 发布为 http://192.168.1.100:38080)。语音确认页面的 服务端 Base URL 必须填写该 API 根地址;浏览器端会用同一主机和端口生成 WebSocket 地址:ws://192.168.1.100:38080/client/voice-terminals/ws?terminal_id=...。如果语音页与 API 不同源,需配置 CORS 放行语音页来源。

2. 摄像头 ID 与 RTSP

RTSP 地址、账号、口令等由客户端对接工程师提供给服务端运维,运维再写入服务端环境。客户端只在 链路 1POST /client/surgeries/start 中传 camera_ids 与主摄 basket_roi_xyxy链路 3 上传视频不需要 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.mdbackend/docker-compose.yml

3. HTTP 路由一览

序号 方法 路径 说明
1 GET /health 探活
2 POST /client/surgeries/start 开始手术(链路 1
3 POST /client/surgeries/end 结束手术(链路 1
4 GET /client/surgeries/{surgery_id}/result 查询手术结果(链路 1 / 3 共用)
5 GET /client/surgeries/{surgery_id}/pending-confirmation 拉取待确认耗材(链路 1
6 POST /client/surgeries/{surgery_id}/pending-confirmation/{confirmation_id}/resolve 提交医生答复(链路 1
7 POST /internal/demo/offline-batch 链路 3:上传 MP4 离线推理(需 DEMO_ORCHESTRATOR_ENABLED=true
8 GET /internal/demo/offline-batch/{surgery_id}/timing 链路 3查询文本 / 标注视频各阶段耗时
9 GET /internal/demo/offline-batch/{surgery_id}/visualization 链路 3下载标注 MP4可选
10 GET /internal/demo/recording-modes-status 可选:探测链路 3 是否已启用
11 GET /client/voice-terminals/{terminal_id}/assignment 可选:查询当前指派(调试或简易集成;官方浏览器客户端仅用 WebSocket
12 WS /client/voice-terminals/ws?terminal_id=... 语音终端长连接,接收开录/停录指派(推荐;与 clients/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 时序图(链路 1 · 真 RTSP

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

    Client->>Server: POST /client/surgeries/start
    Note over Client,Server: body: surgery_id, camera_ids, basket_roi_xyxy, 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 状态图(链路 1

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

4.3 时序图(链路 3 · 上传 MP4

与 §4.1 并行存在,适用于已有完整术间录像、无需实时拉流与语音待确认的场景。

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

    opt 探测(可选)
        Client->>Server: GET /internal/demo/recording-modes-status
        Server-->>Client: demo_recording_modes_enabled
    end

    Client->>Server: POST /internal/demo/offline-batch
    Note over Client,Server: multipart: surgery_id, video1, candidate_consumables_json, include_visualization
    Server-->>Client: 200 acceptedTSV 推理已完成)

    Client->>Server: GET /client/surgeries/{surgery_id}/result
    Server-->>Client: 200 或 503 RESULT_NOT_READY

    opt include_visualization=true
        loop 直至 video_status=ready 或 failed
            Client->>Server: GET .../offline-batch/{surgery_id}/timing
            Server-->>Client: video_status pending / ready / failed
        end
        Client->>Server: GET .../offline-batch/{surgery_id}/visualization
        Server-->>Client: video/mp4
    end

与链路 1 的差异

项目 链路 1RTSP 链路 3上传 MP4
开录 / 停录 需要 start / end 不需要
语音终端 / 待确认 (结果直接入库)
查结果 GET .../result 同上
服务端开关 RTSP 站点配置 另需 DEMO_ORCHESTRATOR_ENABLED=true

5. 接口详情

路径参数 surgery_id

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

业务错误响应

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

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

§5.7§5.9(链路 3的部分校验失败返回 FastAPI 默认 detail 字符串(无 code 包装),见各节状态码表。

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

业务说明

  • 服务端会为主摄启动 6-4 篮子推流算法,并保留 RTSP 录像任务;只有在确认开录成功(如首帧就绪)后才返回 HTTP 200

  • 本接口同步阻塞直至开录确认;默认 RTSP 等待约 95 秒/次、最多 3 次重试。客户端 HTTP 超时建议 ≥ 300 秒Apipost 等工具默认 3060 秒易触发 ESOCKETTIMEDOUT)。服务端可通过 VIDEO_OPEN_TIMEOUT_SEC 调大(默认 90

  • candidate_consumables 缺省或 [] 时,服务端会展开为 consumable_classifier_labels.yaml 中的全部类名(无有效 yaml 时开录失败)。

  • 非空时,每项可为耗材名称产品编码label_id);编码通过 yaml 解析为类名后再参与推理与白名单。亦支持医院导出对象(见下表)。

  • 41 类完整类名与产品编码对照:见 docs/耗材产品编码与类名对照表.md(须用完整类名或编码,口语简称如「纱布」不会自动映射)。

  • basket_roi_xyxy 为主摄篮子 ROI 的原始像素坐标,必须基于服务端实际算法主摄(默认 RTSP_PRIMARY_CAMERA_ID,常为 or-cam-03)的预览画面标注。

请求体JSON

字段 类型 必填 说明
surgery_id string 6 位数字
camera_ids string[] 至少 1 个;必须与运维配置的摄像头 ID 完全一致,见第 2 节
basket_roi_xyxy number[4] 主摄篮子 ROI格式 [x1,y1,x2,y2],原始像素坐标,要求 x2>x1y2>y1
candidate_consumables string[] 或对象数组 非空时仅这些名称/编码参与自动记账与待确认;缺省或 [] 时使用全部候选。字符串可为类名或 label_id;对象见下

candidate_consumables 数组元素

形式 示例 说明
名称字符串 "医用纱布敷料" 须与 yaml / 模型类名完全一致(见对照表)
编码字符串 "14764-2-4" 与 yaml 中 label_id 一致,服务端解析为类名
导出对象(名称) {"消耗品编号":"14764-2-4","名称":"一次性使用手术单"} 名称(或 name)为准
导出对象(仅编号) {"消耗品编号":"14764-2-4"} 按编号解析为类名

响应体200

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

状态码

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

请求示例

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

仅传产品编码时:

{
  "surgery_id": "123456",
  "camera_ids": ["or-cam-01"],
  "basket_roi_xyxy": [260, 180, 1120, 860],
  "candidate_consumables": ["14764-2-4", "8036-5-22"]
}

响应示例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

  • 上述 503detail.codeRESULT_NOT_READYdetail.message 说明具体原因(如未开始、进行中尚无明细、已结束无消耗等)。

  • 链路 3:离线 batch 完成后结果直接写入数据库,通过本接口查询;无需先调用 start / end。若 batch 识别结果为零条明细,本接口仍返回 503

响应体200

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

details[] 元素

字段 类型 说明
item_id string 物品 ID有 yaml 时多为 label_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 detail.codeRESULT_NOT_READYmessage 为具体原因

响应示例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 无待确认或手术未活跃;detail.code 为 NO_PENDING_CONFIRMATION
422 例如话术为空导致无法 TTSdetail.code 如 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 路径参数
confirmation_id 长度 1 到 128 与 5.5 节响应中的 confirmation_id 一致

请求体multipart

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

业务说明

音频上传至对象存储后执行 ASR 和候选解析。若识别为确认某个候选项则记一条消耗若识别为否认全部候选则不记消耗。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 确认项不存在或手术未活跃;detail.code 如 CONFIRMATION_NOT_FOUND
409 当前确认项已处理过;detail.code 如 CONFIRMATION_ALREADY_RESOLVED
422 空文件、非 .wavVOICE_AUDIO_INVALIDASR/解析可重试失败(如 VOICE_ASR_FAILEDVOICE_TEXT_EMPTYVOICE_PARSE_FAILED)等
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 上传手术视频(链路 3 · 离线 batch

基本信息

项目 内容
方法 POST
路径 /internal/demo/offline-batch
Content-Type multipart/form-data

前置条件

  • 服务端环境变量 DEMO_ORCHESTRATOR_ENABLED=true。未开启时本路径返回 404detailDemo recording modes disabled (set DEMO_ORCHESTRATOR_ENABLED=true).
  • 可先调用 GET /internal/demo/recording-modes-status 查看 demo_recording_modes_enabled 是否为 true(该探测接口始终注册,不依赖上述开关)。

业务说明

  • 上传单路完整 MP4(字段名 video1),服务端调用离线算法包(algorithm_subprocesses/5.15/main.py)完成整段推理,解析 TSV 后将消耗明细直接写入数据库
  • 启动 RTSP 实时会话,调用 start / end触发语音终端或待确认队列。
  • 请求在服务端同步阻塞直至 TSV 推理结束才返回 200;长视频可能耗时较久,客户端应设置足够长的 HTTP 超时。
  • 相同视频内容SHA-256+ 相同候选清单会命中结果缓存(跨 surgery_id 复用),响应 message 中含 cache=hitcache=miss
  • candidate_consumables_json 的语义与 5.2 节 candidate_consumables 一致(名称、产品编码、医院导出对象);缺省 "[]" 时展开为 yaml 全部类名。

请求体multipart

字段名 类型 必填 说明
surgery_id string 6 位数字
video1 file 单路完整 MP4空文件返回 422
candidate_consumables_json string JSON 数组字符串,默认 "[]";格式同 5.2 节候选清单
include_visualization boolean 是否后台生成标注 MP4默认 false。为 true 时响应含 visualization_url,标注视频异步生成,需轮询 5.8 节

响应体200

字段 类型 说明
surgery_id string 与请求一致
status string 成功时为 accepted
message string rows= 行数、`cache=hit
visualization_url string | null include_visualization=true 时为相对路径 /internal/demo/offline-batch/{surgery_id}/visualization;否则为 null
doctor_name string | null 算法输出的医生姓名(若识别到)
doctor_id string | null 医生 ID若识别到
doctor_display string | null 展示用医生信息
text_duration_sec number TSV / 主流程耗时(秒,保留 3 位小数)
video_duration_sec number | null 标注视频耗时;未请求或仍在后台时为 null
total_duration_sec number 已完成阶段的合计耗时(秒)

状态码

HTTP 说明
200 离线推理已完成,结果已入库(可能为零条明细)
404 Demo 模式未启用
422 surgery_id 非 6 位、candidate_consumables_json 非法、video1 为空等
500 上传落盘失败
503 离线 batch 子进程失败;detail 形如 offline batch failed: ...

后续步骤

  1. 调用 GET /client/surgeries/{surgery_id}/result5.4 节)查询消耗明细。
  2. include_visualization=true,轮询 GET .../offline-batch/{surgery_id}/timing5.8 节)直至 video_statusreadyfailed,再 GET .../visualization5.9 节)下载 MP4。

cURL 示例

curl -sS -X POST "http://<主机>:38080/internal/demo/offline-batch" \
  -F "surgery_id=123456" \
  -F "video1=@/path/to/surgery.mp4;type=video/mp4" \
  -F 'candidate_consumables_json=["14764-2-4","8036-5-22"]' \
  -F "include_visualization=true"

响应示例200

{
  "surgery_id": "123456",
  "status": "accepted",
  "message": "非实时精确视频处理完成rows=3 cache=miss医生=张三 (6611);标注视频后台生成中(完成后刷新 visualization URL24 小时内有效)",
  "visualization_url": "/internal/demo/offline-batch/123456/visualization",
  "doctor_name": "张三",
  "doctor_id": "6611",
  "doctor_display": "张三 (6611)",
  "text_duration_sec": 842.5,
  "video_duration_sec": null,
  "total_duration_sec": 842.5
}

5.8 查询离线 batch 各阶段耗时

基本信息

项目 内容
方法 GET
路径 /internal/demo/offline-batch/{surgery_id}/timing
路径参数 surgery_id6 位数字)
请求体

业务说明

  • 在 5.7 节上传完成后可用;用于轮询标注视频是否生成完毕。
  • video_statusskipped(未请求标注视频)、pending(后台生成中)、ready(可下载)、failed(生成失败)。

响应体200

字段 类型 说明
surgery_id string 手术号
text_duration_sec number TSV 主流程耗时(秒)
video_duration_sec number | null 标注视频耗时;未完成时为 null
total_duration_sec number 合计耗时(秒)
video_status string skipped / pending / ready / failed

状态码

HTTP 说明
200 有该 surgery_id 的 timing 记录
404 Demo 未启用,或尚无 timing 记录
422 surgery_id 不符合约束

5.9 获取离线 batch 标注视频

基本信息

项目 内容
方法 GET
路径 /internal/demo/offline-batch/{surgery_id}/visualization
路径参数 surgery_id6 位数字)
请求体

业务说明

  • 仅当 5.7 节 include_visualization=true 且后台生成成功时可用。
  • 响应为 video/mp4 文件流,文件名 {surgery_id}_result_vis.mp4
  • 标注文件默认保留 24 小时VIDEO_BATCH_VIS_TTL_HOURS),过期后返回 404

状态码

HTTP 说明
200 MP4 文件流
404 Demo 未启用、尚未生成或已过期
422 surgery_id 不符合约束

5.10 语音终端 assignmentHTTP可选

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

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

响应 200

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

5.11 语音终端 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由网关或客户端库实现