60 lines
1.5 KiB
Python
60 lines
1.5 KiB
Python
|
|
# ============================================================
|
|||
|
|
# 长任务进度 / Thinking 日志(moduleId: core-progress, 可重生 ✅)
|
|||
|
|
# 同步代码 emit → 网关 SSE 轮询 drain → 前端 Thinking 面板
|
|||
|
|
# ============================================================
|
|||
|
|
from __future__ import annotations
|
|||
|
|
|
|||
|
|
import threading
|
|||
|
|
import time
|
|||
|
|
from collections import deque
|
|||
|
|
from typing import Any
|
|||
|
|
|
|||
|
|
_lock = threading.Lock()
|
|||
|
|
_buf: deque[dict[str, Any]] = deque(maxlen=200)
|
|||
|
|
_active = False
|
|||
|
|
|
|||
|
|
|
|||
|
|
def begin_progress() -> None:
|
|||
|
|
"""一轮对话开始:清空缓冲并启用(跨线程可见)。"""
|
|||
|
|
global _active
|
|||
|
|
with _lock:
|
|||
|
|
_buf.clear()
|
|||
|
|
_active = True
|
|||
|
|
|
|||
|
|
|
|||
|
|
def end_progress() -> None:
|
|||
|
|
global _active
|
|||
|
|
with _lock:
|
|||
|
|
_active = False
|
|||
|
|
|
|||
|
|
|
|||
|
|
def emit_thinking(
|
|||
|
|
step: str,
|
|||
|
|
detail: str = "",
|
|||
|
|
*,
|
|||
|
|
status: str = "running",
|
|||
|
|
pct: float | None = None,
|
|||
|
|
) -> None:
|
|||
|
|
"""推送一条 Thinking 步骤(线程安全,供 SQL 扫描等后台线程调用)。"""
|
|||
|
|
with _lock:
|
|||
|
|
if not _active:
|
|||
|
|
return
|
|||
|
|
ev: dict[str, Any] = {
|
|||
|
|
"type": "thinking",
|
|||
|
|
"step": step,
|
|||
|
|
"detail": detail or "",
|
|||
|
|
"status": status, # running | done | warn
|
|||
|
|
"ts": time.time(),
|
|||
|
|
}
|
|||
|
|
if pct is not None:
|
|||
|
|
ev["pct"] = max(0.0, min(100.0, float(pct)))
|
|||
|
|
_buf.append(ev)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def drain_thinking() -> list[dict[str, Any]]:
|
|||
|
|
"""取出并清空当前缓冲。"""
|
|||
|
|
with _lock:
|
|||
|
|
items = list(_buf)
|
|||
|
|
_buf.clear()
|
|||
|
|
return items
|