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
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
from datetime import datetime, timezone
|
|
|
|
|
|
2026-04-23 14:24:20 +08:00
|
|
|
from sqlalchemy import func, select
|
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
|
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
|
|
|
|
|
|
from app.db.models import VoiceConfirmationAudit
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class VoiceAuditRepository:
|
|
|
|
|
"""Persist voice confirmation audit rows."""
|
|
|
|
|
|
2026-04-23 14:24:20 +08:00
|
|
|
async def list_by_surgery(
|
|
|
|
|
self,
|
|
|
|
|
session: AsyncSession,
|
|
|
|
|
surgery_id: str,
|
|
|
|
|
*,
|
|
|
|
|
limit: int = 50,
|
|
|
|
|
offset: int = 0,
|
|
|
|
|
) -> tuple[list[VoiceConfirmationAudit], int]:
|
|
|
|
|
"""按手术号分页列出审计行,按 `created_at` 降序(新在前)。"""
|
|
|
|
|
c = select(func.count()).select_from(VoiceConfirmationAudit).where(
|
|
|
|
|
VoiceConfirmationAudit.surgery_id == surgery_id
|
|
|
|
|
)
|
|
|
|
|
total = int((await session.execute(c)).scalar_one())
|
|
|
|
|
q = (
|
|
|
|
|
select(VoiceConfirmationAudit)
|
|
|
|
|
.where(VoiceConfirmationAudit.surgery_id == surgery_id)
|
|
|
|
|
.order_by(VoiceConfirmationAudit.created_at.desc())
|
|
|
|
|
.offset(offset)
|
|
|
|
|
.limit(limit)
|
|
|
|
|
)
|
|
|
|
|
rows = list((await session.execute(q)).scalars().all())
|
|
|
|
|
return rows, total
|
|
|
|
|
|
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
|
|
|
async def save_audit(
|
|
|
|
|
self,
|
|
|
|
|
session: AsyncSession,
|
|
|
|
|
*,
|
|
|
|
|
surgery_id: str,
|
|
|
|
|
confirmation_id: str,
|
|
|
|
|
status: str,
|
|
|
|
|
audio_object_key: str | None,
|
|
|
|
|
audio_content_type: str | None,
|
|
|
|
|
audio_size_bytes: int | None,
|
|
|
|
|
audio_sha256: str | None,
|
|
|
|
|
asr_text: str | None,
|
|
|
|
|
resolved_label: str | None,
|
|
|
|
|
options_snapshot_json: str | None,
|
|
|
|
|
error_message: str | None,
|
|
|
|
|
created_at: datetime | None = None,
|
|
|
|
|
) -> None:
|
|
|
|
|
when = created_at or datetime.now(timezone.utc)
|
|
|
|
|
row = VoiceConfirmationAudit(
|
|
|
|
|
surgery_id=surgery_id,
|
|
|
|
|
confirmation_id=confirmation_id,
|
|
|
|
|
status=status,
|
|
|
|
|
audio_object_key=audio_object_key,
|
|
|
|
|
audio_content_type=audio_content_type,
|
|
|
|
|
audio_size_bytes=audio_size_bytes,
|
|
|
|
|
audio_sha256=audio_sha256,
|
|
|
|
|
asr_text=asr_text,
|
|
|
|
|
resolved_label=resolved_label,
|
|
|
|
|
options_snapshot_json=options_snapshot_json,
|
|
|
|
|
error_message=error_message,
|
|
|
|
|
created_at=when,
|
|
|
|
|
)
|
|
|
|
|
session.add(row)
|
|
|
|
|
await session.flush()
|