""" 转写进度追踪器(内存级 + DB 状态) 为每个问诊维护: - stage (preparing | uploading | transcribing | extracting | generating | done | error) - percent (0-100) - message (人类可读描述) - engine (实际使用的引擎名称) - updated_at 提供线程安全的更新与查询接口,供前端轮询。 """ import threading import time from dataclasses import dataclass, asdict from typing import Optional @dataclass class ProgressState: """单个问诊的进度状态""" consultation_id: str stage: str = "preparing" # preparing | uploading | transcribing | extracting | generating | done | error percent: int = 0 # 0-100 message: str = "准备中" # 人类可读 engine: str = "xunfei_llm" # 当前实际使用的引擎 error: Optional[str] = None # 错误信息(如有) updated_at: float = 0.0 # 上次更新时间戳 class ProgressTracker: """内存级进度追踪器(线程安全)""" def __init__(self) -> None: self._states: dict[str, ProgressState] = {} self._lock = threading.Lock() def init(self, consultation_id: str, engine: str = "xunfei_llm") -> ProgressState: """初始化/重置一个问诊的进度""" with self._lock: state = ProgressState( consultation_id=consultation_id, stage="preparing", percent=0, message="准备中…", engine=engine, updated_at=time.time(), ) self._states[consultation_id] = state return state def update( self, consultation_id: str, *, stage: Optional[str] = None, percent: Optional[int] = None, message: Optional[str] = None, error: Optional[str] = None, ) -> ProgressState: """更新进度状态""" with self._lock: state = self._states.get(consultation_id) if state is None: state = ProgressState(consultation_id=consultation_id) self._states[consultation_id] = state if stage is not None: state.stage = stage if percent is not None: state.percent = max(state.percent, min(percent, 100)) if message is not None: state.message = message if error is not None: state.error = error state.stage = "error" state.updated_at = time.time() return state def get(self, consultation_id: str) -> Optional[dict]: """获取进度状态(用于 API 返回)""" with self._lock: state = self._states.get(consultation_id) if state is None: return None return asdict(state) def clear(self, consultation_id: str) -> None: """清理进度记录""" with self._lock: self._states.pop(consultation_id, None) # ================================================================ # 全局单例 # ================================================================ _tracker: Optional[ProgressTracker] = None def get_progress_tracker() -> ProgressTracker: """获取全局进度追踪器(单例)""" global _tracker if _tracker is None: _tracker = ProgressTracker() return _tracker