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:
@@ -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 8601,date-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},
|
||||
],
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user