feat: 手术视频消耗、待确认与持久化改造

- 新增 Alembic 初始迁移、领域明细模型及归档持久化与重试链路\n- 拆分视频会话注册表、分类处理、推理时间窗聚合与流处理\n- 消耗日志:TSV/Markdown 含 top2/top3;item_id 优先产品编码;待确认记「待确认」行,语音确认后落正式行并更新汇总\n- 待确认时内存/DB 明细为占位行,确认后替换;拒绝时移除占位\n- 分类 probs 先 detach/cpu 再转 NumPy,修复 MPS/CUDA 上推理被静默跳过\n- 补充集成测试、归档与设备张量等单测

Made-with: Cursor
This commit is contained in:
Kevin
2026-04-23 20:42:21 +08:00
parent 69980d8073
commit 3d7bd70355
55 changed files with 4544 additions and 2050 deletions

View File

@@ -1,6 +1,5 @@
from __future__ import annotations
from dataclasses import dataclass
from datetime import datetime
from pydantic import BaseModel, ConfigDict, Field
@@ -35,9 +34,10 @@ class SurgeryStartRequest(BaseModel):
candidate_consumables: list[str] = Field(
default_factory=list,
description=(
"本次手术可能使用到的耗材清单"
"服务端仅对该清单内的耗材做自动记账与待确认追问"
"若为空则不会写入任何消耗(仅拉流推理)。"
"本次手术可能使用到的耗材子集(可选)"
"非空时仅对该清单内名称做自动记账与待确认追问"
"缺省或空数组时,使用服务端配置的耗材目录 Excel 全部商品名;"
"未配置目录则使用分类模型全部类名。"
),
)
@@ -101,32 +101,14 @@ class SurgeryConsumptionDetail(BaseModel):
),
)
item_name: str = Field(description="物品名称(分类或确认后的展示名)。")
qty: int = Field(ge=0, description="本条记录对应的消耗数量。")
qty: int = Field(
ge=0,
description="本条记录对应的消耗数量;当前一次识别或一次人工确认仅追加一条明细,因此固定为 1。",
)
doctor_id: str = Field(description="医生 ID。")
timestamp: datetime = Field(description="记录时间ISO 8601date-time")
@dataclass
class SurgeryConsumptionStored:
"""内存 / 数据库持久化用的明细行(含 source仅服务端内部使用不随 HTTP 返回)。"""
item_id: str
item_name: str
qty: int
doctor_id: str
timestamp: datetime
source: str = "vision"
def as_response(self) -> SurgeryConsumptionDetail:
return SurgeryConsumptionDetail(
item_id=self.item_id,
item_name=self.item_name,
qty=self.qty,
doctor_id=self.doctor_id,
timestamp=self.timestamp,
)
class SurgeryConsumptionSummary(BaseModel):
"""按物品汇总该手术下该物品消耗数量合计item_id、item_name、total_quantity"""
@@ -222,7 +204,7 @@ class SurgeryResultResponse(BaseModel):
{
"item_id": "HC001",
"item_name": "纱布",
"qty": 2,
"qty": 1,
"doctor_id": "D1001",
"timestamp": "2026-04-21T10:30:00+08:00",
},
@@ -242,7 +224,7 @@ class SurgeryResultResponse(BaseModel):
},
],
"summary": [
{"item_id": "HC001", "item_name": "纱布", "total_quantity": 3},
{"item_id": "HC001", "item_name": "纱布", "total_quantity": 2},
{"item_id": "HC002", "item_name": "缝线", "total_quantity": 1},
],
}