feat: 5-issue fix — OCR image parse bug + Vue frontend feature parity + streaming UX
Fix 1 (CRITICAL): file_parser.py suffix normalization ".jpg", api_server.py Path.suffix Fix 2: Sidebar version history download, ProcessSection replaces old components Fix 3: OCR content/position layer structured logging in agent/nodes.py Fix 4: collapsible process sections with per-section stream routing + auto-fold Fix 5: agent_complete total_duration_ms, SummaryCard duration display - backend/file_parser.py: normalize suffix to always include leading dot - api_server.py: step_index in node_start, total_duration_ms in agent_complete - agent/nodes.py: _log_ocr_layers() for [内容层]/[位置层]/[合并] logging - frontend: ProcessSection.vue (NEW), chat.ts sections model, Sidebar versions - CLAUDE.md: updated component list and v6 changelog
This commit is contained in:
+9
-1
@@ -103,15 +103,19 @@ UPLOADS_DIR = Path(os.getenv("UPLOADS_DIR", "./uploads"))
|
||||
|
||||
# 当前请求的事件队列(单个用户桌面应用,无并发问题)
|
||||
_current_event_queue: Optional[queue.Queue] = None
|
||||
_step_counter: int = 0
|
||||
|
||||
|
||||
def _on_node_start(node_name: str):
|
||||
"""全局 node_start 回调 — 将事件推入当前请求的事件队列。"""
|
||||
global _step_counter
|
||||
q = _current_event_queue
|
||||
if q is not None:
|
||||
_step_counter += 1
|
||||
q.put(("node_start", {
|
||||
"node": node_name,
|
||||
"label": NODE_LABELS.get(node_name, node_name),
|
||||
"step_index": _step_counter,
|
||||
}))
|
||||
|
||||
|
||||
@@ -176,8 +180,10 @@ def _run_graph_sync(agent_state: AgentState, event_q: queue.Queue):
|
||||
|
||||
async def _sse_generator(agent_state: AgentState) -> str:
|
||||
"""SSE 事件生成器 —— 在后台线程运行图,异步产出 SSE 字符串。"""
|
||||
global _current_event_queue
|
||||
global _current_event_queue, _step_counter
|
||||
|
||||
_step_counter = 0
|
||||
t_start = time.time()
|
||||
event_q: queue.Queue = queue.Queue()
|
||||
_current_event_queue = event_q
|
||||
|
||||
@@ -198,6 +204,7 @@ async def _sse_generator(agent_state: AgentState) -> str:
|
||||
kind = item[0]
|
||||
if kind == "done":
|
||||
_current_event_queue = None
|
||||
total_ms = round((time.time() - t_start) * 1000)
|
||||
yield _sse_line("agent_complete", {
|
||||
"reason": "done",
|
||||
"intent": agent_state.get("intent", ""),
|
||||
@@ -206,6 +213,7 @@ async def _sse_generator(agent_state: AgentState) -> str:
|
||||
"error_msg": agent_state.get("error_msg", ""),
|
||||
"natural_explanation": agent_state.get("natural_explanation", ""),
|
||||
"retry_count": agent_state.get("retry_count", 0),
|
||||
"total_duration_ms": total_ms,
|
||||
"ocr_extraction_result": agent_state.get("ocr_extraction_result", {}),
|
||||
})
|
||||
await future
|
||||
|
||||
Reference in New Issue
Block a user