Files
operating-room-monitor-server/docs/客户端手术通信接口说明.md
Kevin 04866559db feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.

Made-with: Cursor
2026-04-21 18:33:54 +08:00

17 KiB
Raw Blame History

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

本文档描述客户端与手术室监控服务端之间,围绕「单台手术生命周期」进行通信的 HTTP 接口。便于联调、评审与对外同步;与 OpenAPISwagger中的定义一致。


1. 概述

能力 说明
开始手术 请求开始手术;服务端启动摄像头录制,仅在确认开录完成后返回 HTTP 200。
结束手术 请求结束手术;服务端停止摄像头录制,仅在确认停录完成后返回 HTTP 200。
查询结果 根据手术 6 位号查询消耗明细与汇总;仅在已开录且至少已有一条消耗明细后返回 HTTP 200。
待确认耗材 低置信度时服务端排队一条待确认任务客户端拉取话术TTS并在医生确认后回传不阻塞后续视频推理。

约定:

  • 开始 / 结束 使用 POST,请求体为 JSONContent-Type: application/json)。
  • 查询结果 使用 GET无请求体;手术号放在 URL 路径 中(见 4.3),符合「只读资源用 GET」的惯例。
  • 手术标识 **surgery_id**:必须为 恰好 6 位数字(正则 ^\d{6}$),例如 123456

2. 基础信息

项目 说明
协议 HTTP/HTTPS
请求体格式 开始/结束:application/json;查询结果:无 body
响应体格式 JSON
路径前缀 服务端根路径下直接挂载,例如 https://<主机>:<端口>/client/surgeries/...
默认服务端口(开发) 38080(以实际部署为准)

说明: 若生产环境存在网关或反向代理,请将上表中的「主机、端口、是否 HTTPS」替换为对外统一入口地址。


3. 接口列表

序号 方法 路径 说明
1 POST /client/surgeries/start 开始手术
2 POST /client/surgeries/end 结束手术
3 GET /client/surgeries/{surgery_id}/result 查询手术结果
4 GET /client/surgeries/{surgery_id}/pending-confirmation 拉取一条待确认耗材
5 POST /client/surgeries/{surgery_id}/pending-confirmation/{confirmation_id}/resolve 提交医生确认结果

4. 接口详情

4.1 开始手术

用途: 在手术开始时,由客户端向服务端上报手术编号、参与采集的摄像头,以及本台手术可能涉及的耗材清单;服务端启动关联摄像头录制

成功条件HTTP 200 仅在服务端确认摄像头已开始录制之后,才返回 HTTP 200。不得在「仅收到请求、尚未开录」时返回 200。

项目 内容
方法 POST
路径 /client/surgeries/start

请求体字段:

字段名 类型 必填 说明
surgery_id string 手术 6 位号,必须为 6 位数字。
camera_ids string[] 摄像头 ID 列表,至少 1 个元素;须与服务端配置的 RTSP 映射键一致(示例见 app/resources/camera_rtsp_urls.sample.json)。
candidate_consumables string[] 本台手术允许记账的耗材名称清单。为空或未传则不会写入任何消耗(仅拉流推理);非空时自动记账与待确认仅针对清单内名称。

说明: 若该 surgery_id 在服务端仍存在尚未写入数据库的上一台手术内存归档,开始新会话前会先尝试落库;落库失败则返回 503RECORDING_CANNOT_START),避免静默丢失数据。

请求示例:

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

成功响应HTTP 200 表示开录已确认。

字段名 类型 说明
surgery_id string 回显手术 6 位号。
status string 处理状态(例如 accepted 表示开录已确认)。
message string 人类可读的说明文案。

响应示例:

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

重试: 开录调用失败时,服务端会按配置自动重试若干次(间隔若干秒);全部尝试仍失败后再返回 HTTP 503。环境变量:SURGERY_RECORDING_MAX_ATTEMPTS(默认 3含首次SURGERY_RECORDING_RETRY_DELAY_SECONDS(默认 1.0)。

失败响应HTTP 503 重试用尽仍无法在约定条件下确认开录时返回。响应体见 §5.2OpenAPI 模型 SurgeryClientErrorResponse,错误码示例:RECORDING_CANNOT_STARTdetail.message 中会注明已重试次数。


4.2 结束手术

用途: 在手术结束时,由客户端请求服务端结束该 surgery_id 对应手术:服务端须停止关联摄像头的录制

成功条件HTTP 200 仅在服务端确认所有关联摄像头已停止录制之后,才返回 HTTP 200。不得在「仅收到请求、尚未停录」时返回 200。

项目 内容
方法 POST
路径 /client/surgeries/end

请求体字段:

字段名 类型 必填 说明
surgery_id string 手术 6 位号,必须为 6 位数字。

请求示例:

{
  "surgery_id": "123456"
}

成功响应HTTP 200 表示停录已完成。

字段名 类型 说明
surgery_id string 回显手术 6 位号。
status string 处理状态(例如 accepted 表示停录已确认)。
message string 人类可读的说明文案。

响应示例:

{
  "surgery_id": "123456",
  "status": "accepted",
  "message": "摄像头录制已停止,手术已结束。"
}

重试: 停录调用失败时,服务端会按配置自动重试(与开始手术相同的环境变量);全部尝试仍失败后再返回 HTTP 503

失败响应HTTP 503 重试用尽仍无法确认停录完成时返回。响应体见 §5.2(错误码示例:RECORDING_NOT_STOPPEDdetail.message 中会注明已重试次数。


4.3 查询手术结果

用途: 根据 surgery_id 查询该台手术下耗材消耗明细及按物品汇总。

成功条件HTTP 200 仅在已开录至少已有一条消耗明细(自动识别或医生确认)之后返回 HTTP 200details / summary。若已开录但尚无明细,返回 503(见 §5.2,错误码 RESULT_NOT_READY)。

项目 内容
方法 GET
路径 /client/surgeries/{surgery_id}/result

路径参数:

参数名 类型 必填 说明
surgery_id string 手术 6 位号,必须为 6 位数字,出现在 URL 路径中。

请求示例:

GET /client/surgeries/123456/result HTTP/1.1
Host: <主机>:<端口>

(浏览器或客户端直接访问完整 URL 即可,例如 https://<主机>:<端口>/client/surgeries/123456/result。)

成功响应HTTP 200

字段名 类型 说明
surgery_id string 手术 6 位号。
status string 成功时一般为 completed(以服务端约定为准)。
message string 说明信息。
details 数组 消耗明细:按事件发生,可能有多行;每行含物品、数量、医生、时间。
summary 数组 按物品汇总:同一 item_iddetailsquantity 的合计,便于客户端直接展示总计。

**details[] 中每一项(明细行):**

字段名 类型 必填 说明
item_id string 物品 ID。
item_name string 物品名称。
quantity integer 本条记录对应的消耗数量(非负整数)。
doctor_id string 医生 ID。
timestamp string 记录时间,ISO 8601JSON 中为 ISO 格式字符串,与 OpenAPI 中 date-time 一致)。
source string vision 自动识别;voice 医生通过待确认接口确认。

**summary[] 中每一项(汇总行):**

字段名 类型 必填 说明
item_id string 物品 ID。
item_name string 物品名称(与明细中该 ID 首次出现时的名称一致,具体规则以服务端为准)。
total_quantity integer 该物品在本台手术中的消耗数量合计

约定: summary 应由服务端根据 detailsitem_id 汇总得到,保证与明细一致。

响应示例:

{
  "surgery_id": "123456",
  "status": "completed",
  "message": "查询成功。",
  "details": [
    {
      "item_id": "HC001",
      "item_name": "纱布",
      "quantity": 2,
      "doctor_id": "D1001",
      "timestamp": "2026-04-21T10:30:00+08:00"
    },
    {
      "item_id": "HC001",
      "item_name": "纱布",
      "quantity": 1,
      "doctor_id": "D1002",
      "timestamp": "2026-04-21T11:05:00+08:00"
    },
    {
      "item_id": "HC002",
      "item_name": "缝线",
      "quantity": 1,
      "doctor_id": "D1001",
      "timestamp": "2026-04-21T10:45:00+08:00"
    }
  ],
  "summary": [
    { "item_id": "HC001", "item_name": "纱布", "total_quantity": 3 },
    { "item_id": "HC002", "item_name": "缝线", "total_quantity": 1 }
  ]
}

4.4 拉取待确认耗材

用途: 当模型置信度不足但存在候选时,服务端将任务放入 FIFO 队列。客户端轮询本接口获取队首一条待确认项,使用 prompt_text 进行 TTS 播报,并由医生口述选择;服务端视频推理不等待本步骤

成功条件HTTP 200 当前手术进行中且队列非空。

失败HTTP 404 无待确认项或手术未在进行。detail.code 示例:NO_PENDING_CONFIRMATION

项目 内容
方法 GET
路径 /client/surgeries/{surgery_id}/pending-confirmation

响应字段(节选): confirmation_idprompt_textoptions[]label + confidence)、model_top1_labelmodel_top1_confidencecreated_at


4.5 提交耗材确认结果

用途: 客户端采集医生回答的 WAV 音频并上传;服务端将音频存入 MinIO、调用百度 ASR 识别、解析 4.4 返回的候选项;确认则记一条 source=voice 的消耗明细,否认则关闭该待确认项且不记账。

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

请求体multipart

字段 类型 必填 说明
audio 文件 医生语音 .wav;建议 16 kHz 单声道 PCM其他格式服务端可尝试用 ffmpeg 转码。

成功响应HTTP 200 SurgeryPendingConfirmationResolveResponseresolved_labelrejectedasr_textaudio_object_key 等(与 OpenAPI 一致)。

错误: 404(项不存在或手术未活跃)、409(已处理)、422(空文件、非 .wav、ASR/解析失败等业务码见 detail.code)、503MinIO/百度未配置或上传失败等)。

说明: 人工追问的 TTS 播报由客户端根据 4.4 的 prompt_text 完成;服务端不要求部署扬声器/麦克风。


5. 错误与校验

5.1 参数校验HTTP 422

当参数不符合约束时(例如 surgery_id 不是 6 位数字、开始手术时 camera_ids 为空数组等),服务端通常返回 HTTP 422,响应体为 FastAPI/Pydantic 风格的校验错误详情。

建议在客户端侧对 surgery_id 先做本地校验,减少无效请求。

5.2 业务未就绪HTTP 503

成功条件未满足(开录/停录未确认、或查询结果时算法结果尚未就绪)时,服务端返回 HTTP 503,响应体为 JSON**detail 为对象**(与 OpenAPI 中的 **SurgeryClientErrorResponse** / **SurgeryClientErrorDetail** 一致):

字段 类型 说明
detail.code string 业务错误码,如 RECORDING_CANNOT_STARTRECORDING_NOT_STOPPEDRESULT_NOT_READY
detail.message string 人类可读说明。
detail.surgery_id string 手术 6 位号。

示例:

{
  "detail": {
    "code": "RESULT_NOT_READY",
    "message": "仅在已开录且算法已产生可查询的实时计算结果后返回 HTTP 200当前条件不满足。",
    "surgery_id": "123456"
  }
}

6. 实现与演进说明(给阅读者)

  • 开始 / 结束 / 查询结果 与录制、算法流水线的具体绑定以实现为准;未满足约定条件时不返回 200(见各节成功条件),与 OpenAPI/docs/openapi.json 中声明的 200 / 503 / 422 一致。
  • 人工确认由客户端完成 TTS 与拾音ASR服务端只提供结构化候选与话术不要求部署环境具备扬声器/麦克风。
  • 接入真实子系统后,仍应保持:成功响应体与 SurgeryApiResponseSurgeryResultResponse 模型一致503 与 SurgeryClientErrorResponse 一致。

联调时请以 OpenAPI 文档(如 /docs)为准,本文档与之同步维护。


7. 文档修订

版本 日期 说明
1.6 2026-04-21 待确认耗材接口;候选清单硬约束;查询结果需至少一条明细;客户端侧人工确认。
1.5 2026-04-21 开始/结束手术:录制流水线失败时重试,仍失败再 503可配置 SURGERY_RECORDING_*。
1.4 2026-04-21 与 OpenAPI 对齐:开始/结束/查询的 200/503 条件及 SurgeryClientErrorResponse
1.3 2026-04-21 结束手术:仅在实际停录确认后返回 HTTP 200否则 503。
1.2 2026-04-21 查询结果响应增加 details(物品 id/名称/数量/医生/时间)与 summary(按物品汇总)。
1.1 2026-04-21 查询结果改为 GET /client/surgeries/{surgery_id}/result
1.0 2026-04-21 初版,POST /client/surgeries/startPOST /client/surgeries/end