实现Agent对话,合格自动提交,不合格补充材料的能力
This commit is contained in:
@@ -0,0 +1,186 @@
|
||||
---
|
||||
last_reviewed: 2026-06-16
|
||||
---
|
||||
|
||||
# src/web/static/js — 前端逻辑模块
|
||||
|
||||
## 概述
|
||||
|
||||
财务报销自动化系统的前端入口脚本,按功能拆分为多个模块文件,通过 `App` 共享状态对象通信。采用原生 JavaScript 编写,通过 HTTP 请求与 Flask 后端通信,使用 SSE 接收处理进度。
|
||||
|
||||
## 文件结构
|
||||
|
||||
| 文件 | 职责 |
|
||||
|------|------|
|
||||
| `state.js` | 全局状态管理 (`App` 对象,含处理状态机) |
|
||||
| `utils.js` | 工具函数 (HTML 转义、会话管理) |
|
||||
| `chat.js` | 聊天窗口消息管理(含文件消息、处理进度、三点动画、LLM 流式气泡) |
|
||||
| `upload.js` | 文件上传(含拖拽、config.json 解析) |
|
||||
| `config.js` | 配置收集与校验(基于状态机的自动触发) |
|
||||
| `process.js` | 发票处理流程与 SSE 监听(含 file_progress、llm_stream 事件处理) |
|
||||
| `agent.js` | Agent 交互(含 supplement 流程、强制提交、用户文字补充、自动提交) |
|
||||
| `sync.js` | 移动端同步轮询(状态感知模式) |
|
||||
| `index.js` | 入口初始化 |
|
||||
|
||||
## 加载顺序
|
||||
|
||||
```
|
||||
state.js → utils.js → chat.js → upload.js → config.js → process.js → sync.js → index.js
|
||||
```
|
||||
|
||||
## 模块依赖关系
|
||||
|
||||
```
|
||||
state.js (无依赖)
|
||||
│
|
||||
├── utils.js ────────────────┐
|
||||
│ │
|
||||
├── chat.js ─────────────────┐ │
|
||||
│ │ │
|
||||
├── upload.js ──────────────┐ │ │
|
||||
│ │ │ │
|
||||
├── config.js ─────────────┐ │ │ │
|
||||
│ │ │ │ │
|
||||
├── process.js ───────────┐ │ │ │ │
|
||||
│ │ │ │ │ │
|
||||
├── sync.js ──────────┐ │ │ │ │ │
|
||||
│ │ │ │ │ │ │
|
||||
└── index.js ────────┘ │ │ │ │ │ │
|
||||
```
|
||||
|
||||
## 处理状态机
|
||||
|
||||
`App.processState` 控制何时触发自动处理,避免重复执行:
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> idle
|
||||
|
||||
idle --> processing: 配置完整 + 有文件
|
||||
processing --> done: 处理完成
|
||||
processing --> awaiting_supplement: Agent 要求补充材料
|
||||
|
||||
done --> idle: 有新文件 / forceStart = true
|
||||
done --> done: 无新文件(保持,不重复)
|
||||
|
||||
awaiting_supplement --> idle: 用户补充文件(只上传新文件)
|
||||
|
||||
idle --> processing: idle + newFilenames > 0(走 supplement 流程)
|
||||
idle --> awaiting_files: AI 判断文件不足(未来功能)
|
||||
awaiting_files --> idle: 用户补充文件
|
||||
awaiting_files --> processing: 用户说"直接开始" (forceStart = true)
|
||||
```
|
||||
|
||||
状态字段说明:
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `processState` | string | 当前处理状态:idle / processing / done / awaiting_files / awaiting_supplement |
|
||||
| `lastProcessedFileCount` | number | 上次处理时的文件数,用于检测是否有新文件 |
|
||||
| `forceStart` | boolean | 用户强制开始标记(兼容"文件不足也要处理"的场景) |
|
||||
| `newFilenames` | array | 待补充上传的文件名列表,用于区分首次处理和补充处理 |
|
||||
|
||||
## 核心流程
|
||||
|
||||
### 1. 文件上传
|
||||
|
||||
```
|
||||
用户上传文件 → addFileMessage() → 注册到 App.fileMessageMap → promptMissingConfig()
|
||||
→ processState 为 done 时重置为 idle(支持增量上传后重新处理)
|
||||
```
|
||||
|
||||
### 2. 配置收集
|
||||
|
||||
```
|
||||
promptMissingConfig() → 检查 CONFIG_FIELDS → 有缺失则提示 → 用户输入 → sendUserMessage() → 递归直到完整
|
||||
```
|
||||
|
||||
### 3. 自动触发检查 (checkAutoStart)
|
||||
|
||||
```
|
||||
checkAutoStart() → 状态机判断:
|
||||
- processing → 跳过
|
||||
- done + 无新文件 → 跳过(修复重复执行问题)
|
||||
- done + 有新文件 → 走 supplement 流程(不再走 startProcess)
|
||||
- idle + newFilenames > 0 → 走 supplement 流程
|
||||
- idle + 配置完整 + 有文件 → 走 startProcess(首次处理)
|
||||
- awaiting_files + forceStart → 触发
|
||||
```
|
||||
|
||||
### 4. 发票处理(首次)
|
||||
|
||||
```
|
||||
startProcess() → ensureSession → 上传全部文件 → /api/agent/process → SSE 监听
|
||||
→ 收到 file_progress(processing) → setFileProcessing()(三点动画)
|
||||
→ 收到 file_progress(done) → setFileDone()(展示提取摘要)
|
||||
→ 收到 file_progress(cached) → setFileCached()
|
||||
→ 收到 file_progress(error) → setFileError()
|
||||
→ 收到 llm_stream(start) → handleLLMStream() 创建流式气泡
|
||||
→ 收到 llm_stream(chunk) → handleLLMStream() 逐字追加 AI 输出
|
||||
→ 收到 llm_stream(end) → handleLLMStream() 关闭流式气泡
|
||||
→ 收到 done → 设置 processState = 'done' + 记录文件数 → 显示汇总结果
|
||||
```
|
||||
|
||||
### 5. 补充文件处理(新增)
|
||||
|
||||
当 Agent 返回 `awaiting_supplement` 状态时,用户补充文件的流程:
|
||||
|
||||
```
|
||||
用户上传补充文件
|
||||
→ handleFiles() 检测 processState === 'awaiting_supplement'
|
||||
→ _uploadNewFiles() 只上传新文件(不再重新上传所有文件)
|
||||
→ App.newFilenames = [新文件名列表]
|
||||
→ App.processState = 'idle'
|
||||
→ syncFiles() 3 秒后触发 checkAutoStart()
|
||||
→ checkAutoStart() 检测到 idle + newFilenames > 0
|
||||
→ handleSupplementUpload(filenames)
|
||||
→ POST /api/agent/supplement/(后端会重新 extract_invoices,旧文件走缓存)
|
||||
→ 新文件走 LLM 提取,旧文件命中 JSON 缓存直接返回
|
||||
→ run_agent_round() 重新分析
|
||||
→ SSE 返回 done → 根据结果进入 awaiting_supplement 或 done 状态
|
||||
```
|
||||
|
||||
**关键区别**:补充文件走 `/api/agent/supplement/` 而非 `/api/agent/process/`,后者在已有 agent_session 时会跳过提取阶段。
|
||||
|
||||
## 数据流
|
||||
|
||||
### 配置数据流
|
||||
|
||||
```
|
||||
config.json → parseConfigFile → App.sessionConfig → startProcess → /api/agent/process
|
||||
```
|
||||
|
||||
### 发票数据流(首次处理)
|
||||
|
||||
```
|
||||
发票文件 → startProcess → /api/upload → /api/agent/process → SSE file_events.log → 文件消息实时更新
|
||||
```
|
||||
|
||||
### 发票数据流(补充文件)
|
||||
|
||||
```
|
||||
新发票文件 → _uploadNewFiles() → /api/upload → /api/agent/supplement
|
||||
→ extract_invoices()(旧文件走缓存,新文件走 LLM)
|
||||
→ run_agent_round() → SSE file_events.log → 文件消息实时更新
|
||||
```
|
||||
|
||||
### 文件消息状态机
|
||||
|
||||
```
|
||||
addFileMessage(filename)
|
||||
→ file_progress(processing) → 三点动画(同一行)
|
||||
→ file_progress(done/cached/error) → 详情展开 + 状态图标
|
||||
```
|
||||
|
||||
## 变更记录
|
||||
|
||||
- **2026-06-16**:修复补充文件重复上传问题 — 新增 `newFilenames` 状态字段,补充文件时只上传新文件并走 `/api/agent/supplement/` 接口。`upload.js` 新增 `_uploadNewFiles()` 辅助函数。`config.js` 的 `checkAutoStart()` 在 `done` 和 `idle` 状态下有 `newFilenames` 时走 supplement 流程而非 `startProcess()`
|
||||
- **2026-06-16**:新增 LLM 流式思考展示 — `chat.js` 新增 `handleLLMStream` 状态机(start/chunk/end/error 四阶段),`process.js` 的 SSE 监听增加 `llm_stream` 事件分支,AI 思考过程以聊天气泡逐字展示
|
||||
- **2026-06-16**:引入处理状态机 — 新增 `processState` / `lastProcessedFileCount` / `forceStart` 状态字段,修复 `syncFiles` 轮询每 3 秒重复触发处理的 bug。`checkAutoStart` 改为基于状态机判断,done 状态下只有检测到新文件才重新触发。为未来 AI 判断文件是否充足预留了 `awaiting_files` 状态和 `forceStart` 标记
|
||||
- **2026-06-12**:上传区域可折叠 — 新增 `toggleUploadPanel()` 函数,配合 CSS `max-height` 动画实现面板收起/展开
|
||||
- **2026-06-12**:文件消息框对齐到用户侧 — `addFileMessage` 的 wrapper 新增 `user` 类,上传的文件消息显示在右侧(用户侧),与 agent 消息区分
|
||||
- **2026-06-12**:配置完成增加互动提示 — `promptMissingConfig` 在配置完整时发送系统消息告知用户即将开始处理发票
|
||||
- **2026-06-14**:新增文件进度实时反馈 — 后端 extractor 在每处理一个文件时产生 SSE 进度事件,前端根据文件名定位 DOM 并更新状态(处理中三点动画、完成摘要展示、缓存/错误状态)
|
||||
- **2026-06-14**:移除发票编辑和财务提交流程 — 删除 table.js、financial.js 及相关 HTML 区域,后续开发不再支持手动编辑发票信息
|
||||
- **2026-06-12**:模块拆分重构 — 将 index.js (625 行) 拆分为 10 个独立模块,引入 `App` 共享状态对象
|
||||
- **2026-06-12**:修复配置收集流程的异步时序问题 — parseConfigFile 改为 Promise,拆分 checkAutoStart 为静默检查/配置提示两个函数
|
||||
Reference in New Issue
Block a user