Files
operating-room-monitor-server/backend/app/services/offline_batch_timing.py
Kevin d6f4590969 Clarify surgery result errors and expose offline batch timing.
Return specific codes when results are unavailable (not started vs in progress vs ended empty), block duplicate starts with SURGERY_ALREADY_RECORDING, and show text/video/total durations in the demo client.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 14:01:25 +08:00

73 lines
2.0 KiB
Python

"""离线 batch 各阶段耗时(进程内缓存,供 demo 客户端轮询)。"""
from __future__ import annotations
from dataclasses import dataclass
from threading import Lock
from typing import Literal
VideoStatus = Literal["skipped", "pending", "ready", "failed"]
@dataclass
class OfflineBatchTimingRecord:
surgery_id: str
text_duration_sec: float
video_status: VideoStatus = "skipped"
video_duration_sec: float | None = None
@property
def total_duration_sec(self) -> float:
total = self.text_duration_sec
if self.video_duration_sec is not None:
total += self.video_duration_sec
return total
_lock = Lock()
_records: dict[str, OfflineBatchTimingRecord] = {}
def set_text_timing(*, surgery_id: str, text_duration_sec: float, include_video: bool) -> None:
with _lock:
_records[surgery_id] = OfflineBatchTimingRecord(
surgery_id=surgery_id,
text_duration_sec=text_duration_sec,
video_status="pending" if include_video else "skipped",
)
def mark_video_ready(*, surgery_id: str, video_duration_sec: float) -> None:
with _lock:
rec = _records.get(surgery_id)
if rec is None:
return
rec.video_status = "ready"
rec.video_duration_sec = video_duration_sec
def mark_video_failed(*, surgery_id: str) -> None:
with _lock:
rec = _records.get(surgery_id)
if rec is None:
return
rec.video_status = "failed"
def get_timing(surgery_id: str) -> OfflineBatchTimingRecord | None:
with _lock:
rec = _records.get(surgery_id)
if rec is None:
return None
return OfflineBatchTimingRecord(
surgery_id=rec.surgery_id,
text_duration_sec=rec.text_duration_sec,
video_status=rec.video_status,
video_duration_sec=rec.video_duration_sec,
)
def clear_timing(surgery_id: str) -> None:
with _lock:
_records.pop(surgery_id, None)