Files
DEMO-AGENT/docs/2.功能设计/1.自动汇总.md

598 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 自动汇总文件夹文件目录与页数流程功能设计
## 文档信息
| 项目 | 内容 |
| --- | --- |
| 需求分析文档 | docs/1.需求分析/1.自动汇总.md |
| 功能名称 | 自动汇总文件夹文件目录与页数 |
| 所属模块 | 审核智能体 review_agent |
| 设计日期 | 2026-06-05 |
| 设计版本 | V1.0 |
---
## 一、设计目标
本功能面向试剂盒 NMPA 注册申报资料审核场景,支持用户在 AI 对话页上传压缩包或多个文件由后台异步执行文件汇总工作流自动完成解压、文件清单扫描、页数统计、产品名识别、Markdown 报告生成和 Excel 导出。
前台 AI 对话页需要展示一个工作流卡片,实时呈现“上传中、解压中、扫描中、解析中、识别中、输出中、完成/失败”等节点状态工作流完成后AI 对话框展示 Markdown 简表,并提供 Markdown 报告和 Excel 明细下载链接。上传文件、批次、节点状态、文件明细和导出结果均需要与当前对话绑定,一个对话对应一套文件,不能跨对话串用。
---
## 二、总体架构
### 2.1 架构原则
| 原则 | 说明 |
| --- | --- |
| 对话绑定 | 上传文件、处理批次、结果文件均绑定当前 Conversation |
| 按需加载 | 将文件处理流程拆分为多个可单独执行的 Skill按工作流节点调用 |
| 后台异步 | 用户提交后后台执行工作流,前台通过 SSE 接收状态事件 |
| 失败隔离 | 解压失败导致批次失败;单文件解析失败最多重试 3 次后记录异常并继续 |
| 可迁移 MCP | Demo 阶段使用项目内 Skill 注册与调用,后续可迁移为 MCP Tool |
| 可追溯 | 每个节点状态、文件统计结果、导出文件均持久化入库 |
### 2.2 逻辑架构
```mermaid
flowchart TD
A["AI 对话页"] --> B["上传接收接口"]
B --> C["工作流任务表"]
C --> D["后台工作流执行器"]
D --> E["Skill 注册表"]
E --> F1["上传接收 Skill"]
E --> F2["压缩包解压 Skill"]
E --> F3["文件清单扫描 Skill"]
E --> F4["文档页数统计 Skill"]
E --> F5["产品信息识别 Skill"]
E --> F6["汇总报告生成 Skill"]
E --> F7["Excel 导出 Skill"]
D --> G["数据库存档"]
D --> H["导出文件存储"]
D --> I["SSE 状态事件"]
I --> A
```
### 2.3 技术选型
| 设计项 | Demo 方案 | 后续演进 |
| --- | --- | --- |
| 工作流编排 | 项目内 LangGraph 风格节点图执行器 | 接入 LangGraph |
| Skill 形态 | Python 类或函数注册表,按节点名称动态调用 | 封装为 MCP Tool |
| 后台任务 | Django 后台线程 + 数据库状态 | Celery/RQ + Redis |
| 实时更新 | 沿用现有 SSE 流式能力,新增 workflow 事件 | 独立任务事件通道 |
| 文件存储 | 本地 media 目录 | 对象存储或加密文件服务 |
| Markdown 渲染 | 前端引入安全 Markdown 渲染 | 统一富文本渲染组件 |
---
## 三、工作流设计
### 3.1 节点图
```mermaid
flowchart LR
N1["上传中"] --> N2{"是否压缩包"}
N2 -->|"是"| N3["解压中"]
N2 -->|"否"| N4["扫描中"]
N3 --> N4
N4 --> N5["解析页数中"]
N5 --> N6["识别产品名中"]
N6 --> N7["输出中"]
N7 --> N8["完成"]
N3 -->|"解压失败"| F["失败"]
N7 -->|"导出失败"| F
```
### 3.2 节点定义
| 节点编码 | 节点名称 | 触发 Skill | 成功条件 | 失败处理 |
| --- | --- | --- | --- | --- |
| upload | 上传中 | 上传接收 Skill | 原始文件保存成功,批次创建成功 | 批次失败 |
| extract | 解压中 | 压缩包解压 Skill | zip/rar/7z 等压缩包解压成功 | 批次失败 |
| inventory | 扫描中 | 文件清单扫描 Skill | 生成文件清单 | 批次失败或空文件提示 |
| page_count | 解析页数中 | 文档页数统计 Skill | 支持类型完成页数统计或异常记录 | 单文件失败不阻断 |
| product_detect | 识别产品名中 | 产品信息识别 Skill | 识别到产品名或返回空 | 不阻断 |
| report | 输出中 | 汇总报告生成 Skill | Markdown 报告与对话简表生成成功 | 批次失败 |
| export | 输出中 | Excel 导出 Skill | Excel 明细生成成功 | 批次失败或记录导出异常 |
| completed | 完成 | 工作流执行器 | 所有必需产物完成 | 写入完成状态 |
### 3.3 状态机
| 状态 | 含义 |
| --- | --- |
| pending | 已创建,等待执行 |
| running | 执行中 |
| retrying | 单文件解析失败,正在重试 |
| success | 节点执行成功 |
| failed | 节点或批次失败 |
| skipped | 当前节点不需要执行,例如非压缩包跳过解压 |
---
## 四、Skill 设计
### 4.1 Skill 注册与调用
Demo 阶段在项目内定义 Skill 注册表,工作流执行器根据节点编码按需加载并执行对应 Skill。
```text
WorkflowExecutor
-> 根据当前节点读取 Skill 名称
-> 从 SkillRegistry 获取 Skill
-> 执行 skill.run(context)
-> 写入节点状态与结果
-> 发送 SSE 状态事件
-> 进入下一节点
```
后续 MCP 化时,每个 Skill 可映射为独立 MCP Tool输入输出保持稳定 JSON 契约。
### 4.2 上传接收 Skill
| 项目 | 说明 |
| --- | --- |
| 中文名称 | 上传接收 Skill |
| 职责 | 接收对话页上传的压缩包或多个文件,保存原始文件,创建上传批次 |
| 输入 | conversation_id、user_id、uploaded_files |
| 输出 | batch_id、upload_file_ids、upload_type、original_storage_paths |
| 数据写入 | FileSummaryBatch、FileAttachment、FileSummaryBatchAttachment |
| 关键规则 | 文件必须绑定当前 Conversation同一对话只使用本对话上传的文件 |
### 4.3 压缩包解压 Skill
| 项目 | 说明 |
| --- | --- |
| 中文名称 | 压缩包解压 Skill |
| 职责 | 识别并解压 zip、rar、7z 等常见压缩包,保留目录结构 |
| 输入 | batch_id、source_file_path |
| 输出 | extract_root、extracted_file_count |
| 数据写入 | WorkflowNodeRun、批次工作目录 |
| 关键规则 | 防止路径穿越;解压目录必须限定在批次工作目录内;解压失败批次失败 |
### 4.4 文件清单扫描 Skill
| 项目 | 说明 |
| --- | --- |
| 中文名称 | 文件清单扫描 Skill |
| 职责 | 遍历解压目录或散装文件目录,生成文件清单 |
| 输入 | batch_id、scan_root |
| 输出 | inventory_items |
| 数据写入 | FileSummaryItem |
| 关键规则 | 保留目录层级;散装文件归入同一批次根目录;隐藏文件和空文件可标记跳过 |
### 4.5 文档页数统计 Skill
| 项目 | 说明 |
| --- | --- |
| 中文名称 | 文档页数统计 Skill |
| 职责 | 对支持类型统计页数或数量 |
| 输入 | batch_id、FileSummaryItem 列表 |
| 输出 | page_count、statistics_status、error_message |
| 数据写入 | FileSummaryItem |
| 关键规则 | 支持 pdf、doc、docx、xls、xlsx、ppt、pptx单文件失败最多重试 3 次,仍失败则记录异常并继续 |
页数统计口径:
| 文件类型 | 统计口径 |
| --- | --- |
| pdf | PDF 页面数量 |
| doc/docx | 优先转 PDF 后统计页面数量 |
| xls/xlsx | Demo 阶段按工作表数量统计 |
| ppt/pptx | 按幻灯片数量统计 |
### 4.6 产品信息识别 Skill
| 项目 | 说明 |
| --- | --- |
| 中文名称 | 产品信息识别 Skill |
| 职责 | 尝试识别产品名称,并用于更新对话标题 |
| 输入 | batch_id、文件名、目录名、可读取文本片段 |
| 输出 | product_name、confidence、evidence |
| 数据写入 | FileSummaryBatch.product_name、Conversation.title |
| 关键规则 | 优先从文件名和目录名识别;其次读取文档首页或关键文本;识别失败不阻断流程 |
会话标题规则:
| 场景 | 标题处理 |
| --- | --- |
| 识别到产品名 | 更新为“产品名-文件汇总” |
| 未识别产品名 | 保持原对话标题 |
| 用户已手动命名 | 可保留用户标题,产品名写入批次信息 |
### 4.7 汇总报告生成 Skill
| 项目 | 说明 |
| --- | --- |
| 中文名称 | 汇总报告生成 Skill |
| 职责 | 生成完整 Markdown 报告和对话框展示简表 |
| 输入 | batch_id、统计摘要、文件明细、异常清单 |
| 输出 | markdown_report_path、assistant_markdown_summary |
| 数据写入 | ExportedSummaryFile、Message |
| 关键规则 | Markdown 简表需要适合前端对话框渲染;完整报告包含全部文件明细 |
### 4.8 Excel 导出 Skill
| 项目 | 说明 |
| --- | --- |
| 中文名称 | Excel 导出 Skill |
| 职责 | 生成 Excel 汇总文件 |
| 输入 | batch_id、统计摘要、文件明细 |
| 输出 | excel_path、download_url |
| 数据写入 | ExportedSummaryFile |
| 关键规则 | 至少包含“汇总信息”“文件明细”两个 Sheet |
---
## 五、数据模型设计
### 5.1 FileSummaryBatch
文件汇总批次,表示一次对话内的文件汇总任务。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| id | BigAutoField | 主键 |
| conversation | ForeignKey(Conversation) | 绑定对话 |
| user | ForeignKey(User) | 上传用户 |
| batch_no | CharField | 批次编号 |
| product_name | CharField | 识别出的产品名,可为空 |
| upload_type | CharField | archive、multi_file |
| status | CharField | pending、running、success、failed |
| total_files | Integer | 文件总数 |
| supported_files | Integer | 支持统计的文件数 |
| success_files | Integer | 统计成功数 |
| failed_files | Integer | 统计失败数 |
| unsupported_files | Integer | 不支持文件数 |
| total_pages | Integer | 总页数 |
| work_dir | CharField | 批次工作目录 |
| error_message | TextField | 批次异常说明 |
| created_at | DateTimeField | 创建时间 |
| started_at | DateTimeField | 开始时间 |
| finished_at | DateTimeField | 完成时间 |
### 5.2 FileAttachment
上传原始文件记录。用户上传即存储为 `FileAttachment`,批次启动时再通过 `FileSummaryBatchAttachment` 固化本次使用的附件版本。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| id | BigAutoField | 主键 |
| batch | ForeignKey(FileSummaryBatch) | 所属批次 |
| original_name | CharField | 原始文件名 |
| storage_path | CharField | 保存路径 |
| file_size | BigInteger | 文件大小 |
| content_type | CharField | MIME 类型 |
| created_at | DateTimeField | 上传时间 |
### 5.3 FileSummaryItem
文件明细记录。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| id | BigAutoField | 主键 |
| batch | ForeignKey(FileSummaryBatch) | 所属批次 |
| file_index | Integer | 文件序号 |
| directory_level | CharField | 目录层级 |
| file_name | CharField | 文件名 |
| file_type | CharField | 文件类型 |
| relative_path | CharField | 相对路径 |
| storage_path | CharField | 实际处理路径 |
| page_count | Integer | 页数,可为空 |
| statistics_status | CharField | success、failed、unsupported、skipped |
| retry_count | Integer | 页数统计重试次数 |
| error_message | TextField | 异常说明 |
| created_at | DateTimeField | 创建时间 |
| updated_at | DateTimeField | 更新时间 |
### 5.4 WorkflowNodeRun
工作流节点运行记录。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| id | BigAutoField | 主键 |
| batch | ForeignKey(FileSummaryBatch) | 所属批次 |
| node_code | CharField | 节点编码 |
| node_name | CharField | 节点名称 |
| status | CharField | pending、running、retrying、success、failed、skipped |
| progress | Integer | 进度百分比 |
| message | TextField | 节点提示 |
| started_at | DateTimeField | 开始时间 |
| finished_at | DateTimeField | 完成时间 |
### 5.5 ExportedSummaryFile
导出文件记录。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| id | BigAutoField | 主键 |
| batch | ForeignKey(FileSummaryBatch) | 所属批次 |
| export_type | CharField | markdown、excel |
| file_name | CharField | 文件名 |
| storage_path | CharField | 保存路径 |
| download_url | CharField | 下载链接 |
| status | CharField | success、failed |
| error_message | TextField | 导出异常说明 |
| created_at | DateTimeField | 生成时间 |
---
## 六、后端接口设计
### 6.1 上传并启动工作流
| 项目 | 内容 |
| --- | --- |
| URL | POST /api/review-agent/conversations/{conversation_id}/file-summary/start/ |
| 认证 | 登录用户 |
| 请求类型 | multipart/form-data |
| 请求参数 | files[]、prompt |
| 响应 | batch_id、status、workflow_nodes |
处理逻辑:
```text
校验 conversation 属于当前用户
-> 保存上传文件
-> 创建 FileSummaryBatch
-> 创建 WorkflowNodeRun 初始节点
-> 启动后台线程执行工作流
-> 返回 batch_id 和初始节点状态
```
### 6.2 工作流 SSE 事件流
| 项目 | 内容 |
| --- | --- |
| URL | GET /api/review-agent/file-summary/{batch_id}/events/ |
| 认证 | 登录用户 |
| 响应类型 | text/event-stream |
事件类型:
| 事件 | 说明 |
| --- | --- |
| workflow_started | 工作流开始 |
| node_started | 节点开始 |
| node_progress | 节点进度更新 |
| node_retrying | 单文件解析重试 |
| node_completed | 节点完成 |
| node_failed | 节点失败 |
| workflow_completed | 工作流完成 |
| workflow_failed | 工作流失败 |
示例:
```json
{
"batch_id": 12,
"node_code": "page_count",
"node_name": "解析页数中",
"status": "retrying",
"progress": 42,
"message": "检测报告.pdf 解析失败,正在第 2 次重试"
}
```
### 6.3 查询批次状态
| 项目 | 内容 |
| --- | --- |
| URL | GET /api/review-agent/file-summary/{batch_id}/ |
| 认证 | 登录用户 |
| 响应 | 批次摘要、节点状态、文件简表、导出文件链接 |
用途:
| 场景 | 说明 |
| --- | --- |
| 页面刷新恢复 | 前端重新加载后恢复工作流卡片状态 |
| 历史记录查看 | 从会话历史进入后展示已完成汇总结果 |
### 6.4 下载导出文件
| 项目 | 内容 |
| --- | --- |
| URL | GET /api/review-agent/file-summary/exports/{export_id}/download/ |
| 认证 | 登录用户 |
| 响应 | 文件流 |
权限规则:
```text
export_id -> batch -> conversation -> user
必须等于当前登录用户,才允许下载。
```
---
## 七、前端设计
### 7.1 AI 对话页改造
现有 `templates/home.html``static/js/app.js` 需要增强:
| 改造点 | 说明 |
| --- | --- |
| 附件选择 | 在输入框旁增加文件上传按钮,支持压缩包和多个文件 |
| 工作流卡片 | 用户提交后在对话流中插入工作流状态卡片 |
| SSE 监听 | 监听后台节点事件,实时更新卡片节点状态 |
| Markdown 渲染 | AI 回复支持 Markdown 表格和下载链接渲染 |
| 状态恢复 | 页面刷新后查询批次状态,恢复工作流卡片 |
### 7.2 工作流卡片
卡片包含节点列表:
| 节点 | 前台展示文案 |
| --- | --- |
| upload | 上传中 |
| extract | 解压中 |
| inventory | 扫描中 |
| page_count | 解析页数中 |
| product_detect | 识别产品名中 |
| report/export | 输出中 |
| completed | 已完成 |
节点状态样式:
| 状态 | 展示 |
| --- | --- |
| pending | 灰色等待 |
| running | 高亮进行中 |
| retrying | 黄色重试中 |
| success | 绿色完成 |
| failed | 红色失败 |
| skipped | 灰色跳过 |
### 7.3 对话框结果展示
工作流完成后AI 对话框新增助手消息,内容为 Markdown
```markdown
已完成文件目录与页数汇总。
| 指标 | 数量 |
| --- | --- |
| 文件总数 | 24 |
| 统计成功 | 21 |
| 统计失败 | 2 |
| 不支持 | 1 |
| 总页数 | 386 |
| 序号 | 目录层级 | 文件名 | 类型 | 页数 | 状态 | 异常说明 |
| --- | --- | --- | --- | --- | --- | --- |
| 1 | 注册资料/说明书 | 说明书.docx | docx | 12 | 成功 | |
| 2 | 注册资料/检测报告 | 检测报告.pdf | pdf | 38 | 成功 | |
[下载 Markdown 报告](download-url)
[下载 Excel 明细](download-url)
```
---
## 八、后台服务设计
### 8.1 WorkflowExecutor
负责批次级工作流编排。
| 方法 | 说明 |
| --- | --- |
| start(batch_id) | 启动后台任务 |
| run(batch_id) | 串行执行节点图 |
| run_node(node_code, context) | 执行单个节点 |
| emit_event(batch_id, event_type, payload) | 写入并推送事件 |
| complete(batch_id) | 完成批次 |
| fail(batch_id, error) | 标记批次失败 |
### 8.2 SkillRegistry
负责 Skill 注册与按需加载。
| 方法 | 说明 |
| --- | --- |
| register(name, skill_cls) | 注册 Skill |
| get(name) | 获取 Skill |
| run(name, context) | 执行 Skill |
### 8.3 PageCountService
负责具体文件页数统计。
| 方法 | 说明 |
| --- | --- |
| count_pdf(path) | 统计 PDF 页面数 |
| count_word(path) | doc/docx 转 PDF 后统计页面数 |
| count_excel(path) | 统计工作表数量 |
| count_ppt(path) | 统计幻灯片数量 |
| count_with_retry(item, max_retry=3) | 单文件重试统计 |
### 8.4 ExportService
负责 Markdown 和 Excel 导出。
| 方法 | 说明 |
| --- | --- |
| build_markdown_report(batch) | 生成完整 Markdown 报告 |
| build_chat_summary(batch) | 生成对话简表 |
| build_excel(batch) | 生成 Excel 明细 |
| create_download_record(batch, path, type) | 创建下载记录 |
---
## 九、异常与重试设计
### 9.1 批次级失败
| 场景 | 处理 |
| --- | --- |
| 上传保存失败 | 批次不创建或标记失败 |
| 压缩包无法解压 | 批次失败,工作流终止 |
| 文件清单为空 | 批次失败,提示未检测到可处理文件 |
| 报告导出失败 | 批次失败或标记导出异常 |
### 9.2 文件级失败
| 场景 | 处理 |
| --- | --- |
| 单文件页数解析失败 | 最多重试 3 次 |
| 重试仍失败 | statistics_status=failed记录异常说明继续处理其他文件 |
| 不支持类型 | statistics_status=unsupported不重试 |
| 加密或损坏文件 | statistics_status=failed记录“文件加密或损坏” |
---
## 十、安全设计
| 设计点 | 说明 |
| --- | --- |
| 对话隔离 | 所有批次查询和下载必须校验 conversation.user |
| 防串文件 | 工作流只能读取当前 batch 通过 FileSummaryBatchAttachment 绑定的 FileAttachment |
| 解压安全 | 禁止压缩包内路径跳出批次工作目录 |
| 文件执行安全 | 不执行上传文件中的脚本、宏或外部链接 |
| 下载权限 | 下载接口必须验证当前用户拥有批次所属对话 |
| 存储隔离 | 按 user_id/conversation_id/batch_id 建立存储目录 |
---
## 十一、验收设计
| 序号 | 验收项 | 验收标准 |
| --- | --- | --- |
| 1 | 对话绑定 | A 对话上传的文件不会出现在 B 对话的汇总结果中 |
| 2 | 压缩包处理 | 支持 zip、rar、7z 常见压缩包解压并保留目录结构 |
| 3 | 多文件处理 | 支持一次上传多个散装文件并生成同一批次结果 |
| 4 | 工作流卡片 | 前台能实时展示上传中、解压中、扫描中、解析中、输出中、完成状态 |
| 5 | 解析重试 | 单文件解析失败最多重试 3 次,失败后记录异常并继续 |
| 6 | Markdown 展示 | 对话框能正确渲染 Markdown 表格和下载链接 |
| 7 | 导出下载 | Markdown 报告和 Excel 明细可通过对话框链接下载 |
| 8 | 数据存档 | 数据库保留批次、上传文件、节点状态、文件明细、导出文件记录 |
| 9 | 标题更新 | 识别到产品名后,可将会话标题更新为“产品名-文件汇总” |
---
## 十二、待确认事项
| 序号 | 问题 | 当前建议 | 状态 |
| --- | --- | --- | --- |
| 1 | 是否接入真实 LangGraph 依赖 | Demo 先按 LangGraph 节点图思想自实现轻量编排器 | 待确认 |
| 2 | rar/7z 解压依赖 | 可选 py7zr、rarfile、系统 7z 命令 | 待技术验证 |
| 3 | doc/docx 转 PDF 依赖 | 建议使用 LibreOffice headless | 待技术验证 |
| 4 | 用户手动命名对话时是否允许覆盖 | 建议不覆盖,仅写入产品名字段 | 待确认 |
| 5 | 后台任务是否需要取消能力 | Demo 可不做,正式版建议支持取消 | 待确认 |
---
## 十三、实施建议
1. 先补充数据模型和迁移,建立批次、文件明细、节点状态和导出文件表。
2. 增加上传并启动工作流接口,确保文件和当前对话强绑定。
3. 实现轻量 WorkflowExecutor 和 SkillRegistry先完成 zip、pdf、xlsx、pptx 的主链路。
4. 改造前端对话框,增加附件上传、工作流卡片和 Markdown 渲染。
5. 补齐 doc/docx、rar、7z 等依赖能力,再完善异常重试和下载权限测试。