Files
operating-room-monitor-server/app/db/models.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
3.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from __future__ import annotations
from datetime import datetime
from sqlalchemy import DateTime, ForeignKey, Integer, String, Text, func
from sqlalchemy.orm import Mapped, mapped_column, relationship
from app.db.base import Base
class SurgeryFinalResult(Base):
"""一台手术结束后的最终结果元数据(明细在子表)。"""
__tablename__ = "surgery_final_results"
surgery_id: Mapped[str] = mapped_column(String(6), primary_key=True)
completed_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), server_default=func.now(), nullable=False
)
details: Mapped[list["SurgeryResultDetailRow"]] = relationship(
"SurgeryResultDetailRow",
back_populates="surgery",
cascade="all, delete-orphan",
passive_deletes=True,
)
class SurgeryResultDetailRow(Base):
"""客户端查询用的耗材消耗明细行。"""
__tablename__ = "surgery_result_details"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
surgery_id: Mapped[str] = mapped_column(
String(6),
ForeignKey("surgery_final_results.surgery_id", ondelete="CASCADE"),
index=True,
nullable=False,
)
item_id: Mapped[str] = mapped_column(String(256), nullable=False)
item_name: Mapped[str] = mapped_column(String(256), nullable=False)
quantity: Mapped[int] = mapped_column(Integer, nullable=False)
doctor_id: Mapped[str] = mapped_column(String(128), nullable=False)
recorded_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False)
#: 可选:来源标记,如 vision / voice便于排查客户端可忽略。
source: Mapped[str] = mapped_column(String(32), default="vision", nullable=False)
surgery: Mapped["SurgeryFinalResult"] = relationship(
"SurgeryFinalResult", back_populates="details"
)
class VoiceConfirmationAudit(Base):
"""医生语音确认上传原始音频对象键、ASR 文本与解析结果(追溯)。"""
__tablename__ = "voice_confirmation_audits"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
surgery_id: Mapped[str] = mapped_column(String(6), index=True, nullable=False)
confirmation_id: Mapped[str] = mapped_column(String(128), index=True, nullable=False)
#: recognized | rejected | asr_failed | parse_failed | invalid_audio | upload_failed
status: Mapped[str] = mapped_column(String(32), nullable=False)
audio_object_key: Mapped[str | None] = mapped_column(String(512), nullable=True)
audio_content_type: Mapped[str | None] = mapped_column(String(128), nullable=True)
audio_size_bytes: Mapped[int | None] = mapped_column(Integer, nullable=True)
audio_sha256: Mapped[str | None] = mapped_column(String(64), nullable=True)
asr_text: Mapped[str | None] = mapped_column(String(2048), nullable=True)
resolved_label: Mapped[str | None] = mapped_column(String(256), nullable=True)
options_snapshot_json: Mapped[str | None] = mapped_column(Text, nullable=True)
error_message: Mapped[str | None] = mapped_column(String(1024), nullable=True)
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), server_default=func.now(), nullable=False
)