from __future__ import annotations from datetime import datetime, timezone from sqlalchemy import func, select from sqlalchemy.ext.asyncio import AsyncSession from app.db.models import VoiceConfirmationAudit class VoiceAuditRepository: """Persist voice confirmation audit rows.""" 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 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()