- 新增 Alembic 初始迁移、领域明细模型及归档持久化与重试链路\n- 拆分视频会话注册表、分类处理、推理时间窗聚合与流处理\n- 消耗日志:TSV/Markdown 含 top2/top3;item_id 优先产品编码;待确认记「待确认」行,语音确认后落正式行并更新汇总\n- 待确认时内存/DB 明细为占位行,确认后替换;拒绝时移除占位\n- 分类 probs 先 detach/cpu 再转 NumPy,修复 MPS/CUDA 上推理被静默跳过\n- 补充集成测试、归档与设备张量等单测 Made-with: Cursor
82 lines
2.8 KiB
Python
82 lines
2.8 KiB
Python
from __future__ import annotations
|
||
|
||
from datetime import datetime, timezone
|
||
|
||
from sqlalchemy import delete, select
|
||
from sqlalchemy.ext.asyncio import AsyncSession
|
||
|
||
from app.db.models import SurgeryFinalResult, SurgeryResultDetailRow
|
||
from app.domain.consumption import SurgeryConsumptionStored
|
||
|
||
|
||
class SurgeryResultRepository:
|
||
"""持久化 / 读取手术结束后的最终结果(仅客户端返回结构)。"""
|
||
|
||
async def save_final_result(
|
||
self,
|
||
session: AsyncSession,
|
||
*,
|
||
surgery_id: str,
|
||
details: list[SurgeryConsumptionStored],
|
||
completed_at: datetime | None = None,
|
||
) -> None:
|
||
when = completed_at or datetime.now(timezone.utc)
|
||
await session.execute(
|
||
delete(SurgeryResultDetailRow).where(
|
||
SurgeryResultDetailRow.surgery_id == surgery_id
|
||
)
|
||
)
|
||
await session.execute(
|
||
delete(SurgeryFinalResult).where(SurgeryFinalResult.surgery_id == surgery_id)
|
||
)
|
||
row = SurgeryFinalResult(surgery_id=surgery_id, completed_at=when)
|
||
session.add(row)
|
||
for d in details:
|
||
session.add(
|
||
SurgeryResultDetailRow(
|
||
surgery_id=surgery_id,
|
||
item_id=d.item_id,
|
||
item_name=d.item_name,
|
||
quantity=d.qty,
|
||
doctor_id=d.doctor_id,
|
||
recorded_at=d.timestamp,
|
||
source=d.source,
|
||
)
|
||
)
|
||
await session.flush()
|
||
|
||
async def load_final_details(
|
||
self, session: AsyncSession, surgery_id: str
|
||
) -> list[SurgeryConsumptionStored] | None:
|
||
"""返回领域对象列表(含 source);HTTP 层的转换由 pipeline 负责。"""
|
||
res = await session.execute(
|
||
select(SurgeryFinalResult).where(SurgeryFinalResult.surgery_id == surgery_id)
|
||
)
|
||
meta = res.scalar_one_or_none()
|
||
if meta is None:
|
||
return None
|
||
q = await session.execute(
|
||
select(SurgeryResultDetailRow)
|
||
.where(SurgeryResultDetailRow.surgery_id == surgery_id)
|
||
.order_by(SurgeryResultDetailRow.id)
|
||
)
|
||
rows = q.scalars().all()
|
||
out: list[SurgeryConsumptionStored] = []
|
||
for r in rows:
|
||
pend: str | None = None
|
||
iid = r.item_id
|
||
if iid.startswith("pending:"):
|
||
pend = iid.removeprefix("pending:")
|
||
out.append(
|
||
SurgeryConsumptionStored(
|
||
item_id=r.item_id,
|
||
item_name=r.item_name,
|
||
qty=r.quantity,
|
||
doctor_id=r.doctor_id,
|
||
timestamp=r.recorded_at,
|
||
source=r.source,
|
||
pending_confirmation_id=pend,
|
||
)
|
||
)
|
||
return out
|