Files
Auto-Finance/src/web/static/js/sse.js
T
2026-06-15 10:39:01 +08:00

144 lines
3.9 KiB
JavaScript

/**
* SSE 连接管理
*
* 封装 EventSource 的创建、事件注册和 done 事件处理,避免重复代码。
*/
import { App } from './state.js';
import {
removeTypingIndicator,
setFileProcessing,
setFileDone,
setFileCached,
setFileError,
handleLLMStream,
addChatMessage,
showStatus,
} from './chat.js';
import { handleAgentEvent } from './agent.js';
/**
* 创建 SSE 连接并返回 EventSource 实例
*
* @param {string} sessionId - 会话 ID
* @param {Object} options - 选项配置
* @param {Function} options.onDone - done 事件处理器
* @param {boolean} options.handleFileProgress - 是否处理文件进度事件 (默认 true)
* @param {boolean} options.handleLLMStream - 是否处理 LLM 流式事件 (默认 true)
* @param {boolean} options.handleAgentEvents - 是否处理 Agent 事件 (默认 true)
* @returns {EventSource}
*/
export function createSSEConnection(sessionId, options = {}) {
const {
onDone,
handleFileProgress = true,
handleLLMStream: handleStream = true,
handleAgentEvents = true,
} = options;
const es = new EventSource(`/api/logs/${sessionId}`);
es.addEventListener('message', e => {
try {
const msg = JSON.parse(e.data);
// 文件进度事件
if (handleFileProgress && msg.type === 'file_progress') {
const filename = msg.file;
switch (msg.status) {
case 'processing':
setFileProcessing(filename);
break;
case 'done':
setFileDone(filename, msg.summary || {});
break;
case 'cached':
setFileCached(filename);
break;
case 'error':
setFileError(filename, msg.error);
break;
}
return;
}
// LLM 流式事件
if (handleStream && msg.type === 'llm_stream') {
handleLLMStream(msg);
return;
}
// Agent 事件
if (handleAgentEvents && msg.type && msg.type.startsWith('agent_')) {
handleAgentEvent(msg);
return;
}
// 完成事件
if (msg.type === 'done') {
es.close();
if (onDone) {
onDone(msg.result);
}
return;
}
} catch (err) {
// 普通日志行,忽略
}
});
es.onerror = () => {
es.close();
removeTypingIndicator();
App.isProcessing = false;
App.processState = 'done';
addChatMessage('连接中断,请刷新页面重试', 'error');
};
return es;
}
/**
* 处理 done 事件的通用逻辑 (根据 result 内容更新 UI 状态)
*
* @param {Object} result - done 事件的结果对象
*/
export function handleDoneResult(result) {
App.isProcessing = false;
if (App.forceSubmitting) {
App.forceSubmitting = false;
App.lastProcessedFileCount = App.allFiles.length;
if (result.ok) {
addChatMessage('提交完成!', 'done');
} else {
addChatMessage(`提交失败:${result.error || '未知错误'}`, 'error');
}
return;
}
if (result.waiting_for_supplement) {
App.processState = 'awaiting_supplement';
showStatus('信息不完整,请补充上传相关材料');
addChatMessage(
'您可通过上传区补充文件,或直接输入文字说明补充信息,或输入"直接提交"跳过校验',
'system'
);
} else {
App.processState = 'done';
App.lastProcessedFileCount = App.allFiles.length;
if (result.ok) {
if (result.agent_ready) {
if (result.submit_ok !== false) {
addChatMessage('信息完整,已自动提交到财务系统', 'done');
} else {
addChatMessage(`校验通过但提交失败:${result.submit_error || '未知错误'}`, 'error');
}
} else if (result.invoice_count) {
addChatMessage(`处理完成!共提取 ${result.invoice_count} 张发票数据`, 'done');
}
} else {
addChatMessage(`处理失败:${result.error || '未知错误'}`, 'error');
}
}
}