File size: 3,450 Bytes
793e953 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | """
转写进度追踪器(内存级 + 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
|