Files
operating-room-monitor-server/app/repositories/surgery_results.py
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

74 lines
2.4 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.schemas import SurgeryConsumptionDetail
class SurgeryResultRepository:
"""持久化 / 读取手术结束后的最终结果(仅客户端返回结构)。"""
async def save_final_result(
self,
session: AsyncSession,
*,
surgery_id: str,
details: list[SurgeryConsumptionDetail],
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.quantity,
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[SurgeryConsumptionDetail] | None:
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()
return [
SurgeryConsumptionDetail(
item_id=r.item_id,
item_name=r.item_name,
quantity=r.quantity,
doctor_id=r.doctor_id,
timestamp=r.recorded_at,
source=r.source,
)
for r in rows
]