diff --git a/docs/1.需求分析/3.产品关键信息提取与申报文件自动填表.md b/docs/1.需求分析/3.产品关键信息提取与申报文件自动填表.md new file mode 100644 index 0000000..7bc7049 --- /dev/null +++ b/docs/1.需求分析/3.产品关键信息提取与申报文件自动填表.md @@ -0,0 +1,394 @@ +# 产品关键信息提取与申报文件自动填表需求分析 + +## 文档信息 + +| 项目 | 内容 | +| --- | --- | +| 原始材料 | docs/原始材料/【模拟题二】试剂盒临床注册文件准备与审核Agent.docx | +| 法规模板来源 | docs/原始材料/关于公布体外诊断试剂注册申报资料要求和批准证明文件格式的公告 | +| 功能主题 | 从产品文件中提取关键信息并自动填写至指定申报模板 | +| 分析日期 | 2026-06-07 | +| 分析版本 | V1.0 | + +--- + +## 一、需求背景 + +试剂盒及体外诊断试剂注册申报过程中,注册人员需要将同一批产品关键信息重复填写到注册证格式文件、变更注册或备案文件、安全和性能基本原则清单等申报材料中。人工复制粘贴容易出现字段遗漏、表述不一致、来源不可追溯和模板误改等问题。 + +原始任务中的第 3 条能力要求系统能够“从产品文件中提取关键信息并自动填写至目标文件”。本功能目标是:系统基于用户上传的产品说明书、产品技术要求、检测报告、性能研究资料等文件,自动抽取产品名称、检测靶标、适用范围、储存条件、性能指标等核心信息,复制指定法规模板生成可填写副本,将抽取结果写入模板,并输出 Word 与 PDF 两种下载文件。 + +本功能是前两批能力的后续增强:依赖第一批文件汇总结果定位产品文件,复用第二批文本抽取、适用条件确认和一致性核查能力,同时新增“模板识别、字段映射、模板填充、冲突高亮、PDF 转换、来源追溯”能力。 + +--- + +## 二、需求范围 + +### 2.1 本期范围 + +| 序号 | 范围项 | 说明 | +| --- | --- | --- | +| 1 | 目标模板复制 | 从原始法规资料中复制指定模板,不覆盖原始文件 | +| 2 | 注册类型选择 | 首次注册填写注册证格式;变更注册或备案填写变更注册(备案)文件格式 | +| 3 | 安全和性能基本原则清单填写 | 无论首次注册或变更注册,均生成并填写安全和性能基本原则清单 | +| 4 | 产品信息提取 | 从产品说明书、产品技术要求、检测报告、性能研究资料等文件中抽取模板所需字段 | +| 5 | 模板字段识别 | 读取目标模板中的表格、段落、占位栏位和清单条目,建立字段映射 | +| 6 | 自动填入模板 | 将抽取字段写入模板副本,缺失字段保持留空 | +| 7 | 冲突标记 | 同一字段在多个文件中不一致时,按说明书为准填写,并在模板中黄色底色、红色字体标记 | +| 8 | 冲突摘要展示 | AI 对话框展示冲突字段、采用值、冲突来源和待用户下载确认提示 | +| 9 | Word 导出 | 输出填好的 `.docx` 或可编辑 Word 文件 | +| 10 | PDF 导出 | 将填好的 Word 转换为 PDF,尽量保持原 Word 模板版式一致,可用于正式提交前预览 | +| 11 | 来源追溯 | 允许额外输出字段来源追溯清单,记录字段来源文件、文本片段、冲突状态和填入目标 | + +### 2.2 非本期范围 + +| 序号 | 范围项 | 说明 | +| --- | --- | --- | +| 1 | 直接覆盖原始法规模板 | 原始材料只作为模板来源,不允许被改写 | +| 2 | 自动代替人工最终确认 | 系统生成带标记文件,用户自行下载核对确认 | +| 3 | 在线提交 NMPA 系统 | 本期只生成申报文件,不对接外部申报系统 | +| 4 | 全部法规表单覆盖 | 本期仅覆盖用户指定的三个目标模板 | +| 5 | 复杂版式人工校订 | 系统尽量保持模板版式,复杂错位仍需人工最终复核 | + +--- + +## 三、目标模板 + +本期一共处理三个目标模板。用户此前重复提到“体外诊断试剂安全和性能基本原则清单”,经确认属于误填,实际只有一个该清单模板。 + +| 序号 | 模板名称 | 原始文件 | 使用条件 | 输出要求 | +| --- | --- | --- | --- | --- | +| 1 | 中华人民共和国医疗器械注册证(体外诊断试剂)(格式) | 中华人民共和国医疗器械注册证(体外诊断试剂)(格式).docx | 首次注册 | Word + PDF | +| 2 | 中华人民共和国医疗器械变更注册(备案)文件(体外诊断试剂)(格式) | 中华人民共和国医疗器械变更注册(备案)文件(体外诊断试剂)(格式).doc | 变更注册或备案 | Word + PDF | +| 3 | 体外诊断试剂安全和性能基本原则清单 | 体外诊断试剂安全和性能基本原则清单.doc | 首次注册、变更注册、备案均适用 | Word + PDF | + +### 3.1 已识别注册证模板字段 + +从 `中华人民共和国医疗器械注册证(体外诊断试剂)(格式).docx` 中已识别到以下表格栏目: + +| 字段 | 填写规则 | +| --- | --- | +| 注册人名称 | 从申请人、注册人、企业信息类文件中抽取 | +| 注册人住所 | 从申请人、注册人、企业信息类文件中抽取 | +| 生产地址 | 从注册资料、说明书、质量体系或生产信息文件中抽取 | +| 代理人名称 | 进口体外诊断试剂适用,境内产品可留空 | +| 代理人住所 | 进口体外诊断试剂适用,境内产品可留空 | +| 产品名称 | 优先取说明书字段 | +| 包装规格 | 对应型号规格、包装规格 | +| 主要组成成分 | 优先取说明书和产品技术要求 | +| 预期用途 | 对应适用范围、预期用途 | +| 产品储存条件及有效期 | 对应储存条件、有效期 | +| 附件 | 默认包含产品技术要求、说明书,可根据实际文件匹配补充 | +| 其他内容 | 未识别或需人工确认时留空 | +| 备注 | 未识别或需人工确认时留空 | + +### 3.2 模板解析约束 + +变更注册(备案)文件格式和安全和性能基本原则清单当前为 `.doc` 格式。系统实施时需要支持以下任一方案: + +| 方案 | 说明 | +| --- | --- | +| LibreOffice 转换 | 使用 LibreOffice/soffice 将 `.doc` 转为 `.docx` 后识别和填写 | +| 预转换模板 | 项目内预先保存经人工确认的 `.docx` 模板副本 | +| OOXML/COM 方案 | 在 Windows 环境通过 Office 自动化读取和转换模板 | + +无论采用哪种方式,转换后的模板必须保留原文件表格结构、分页、字体和版式,PDF 导出需以填好的 Word 为来源。 + +--- + +## 四、用户角色与使用场景 + +| 角色 | 诉求 | 典型场景 | +| --- | --- | --- | +| 注册人员 | 减少重复填表,提高字段一致性 | 上传注册资料包后生成已填注册证格式和基本原则清单 | +| 变更注册负责人 | 根据变更类型生成变更注册或备案文件 | 上传变更资料后生成已填变更注册(备案)文件 | +| 审核人员 | 快速定位字段来源和冲突 | 下载带冲突高亮的 Word/PDF,并查看 AI 对话框冲突摘要 | +| 系统管理员 | 维护模板版本和转换能力 | 更新法规模板、检查 PDF 转换服务和导出记录 | + +--- + +## 五、业务流程分析 + +### 5.1 主流程 + +```text +用户上传产品注册资料 +-> 系统执行文件目录与页数汇总 +-> 系统执行法规核查前置文本抽取 +-> 系统识别注册类型:首次注册、变更注册或备案 +-> 系统选择本次适用目标模板 +-> 系统复制原始模板到批次工作目录 +-> 系统读取目标模板栏目和清单条目 +-> 系统从产品文件中抽取模板所需字段 +-> 系统按字段优先级合并抽取结果 +-> 如字段存在跨文件冲突,系统按说明书为准填入,并做黄色底色、红色字体标记 +-> 缺失字段保持留空 +-> 系统逐条判断安全和性能基本原则清单的适用性、符合性证据和证明文件位置 +-> 系统生成已填 Word 文件 +-> 系统将已填 Word 转换为 PDF +-> 系统生成来源追溯清单 +-> AI 对话框展示生成结果、冲突字段摘要和下载链接 +-> 用户下载 Word/PDF 自行确认 +``` + +### 5.2 注册类型分支 + +| 注册类型 | 生成文件 | +| --- | --- | +| 首次注册 | 注册证格式 Word/PDF;安全和性能基本原则清单 Word/PDF | +| 变更注册 | 变更注册(备案)文件 Word/PDF;安全和性能基本原则清单 Word/PDF | +| 备案 | 变更注册(备案)文件 Word/PDF;安全和性能基本原则清单 Word/PDF | +| 注册类型无法识别 | AI 对话框提示待确认;默认不生成注册证或变更文件,只可生成带待确认标记的草稿版本 | + +### 5.3 异常流程 + +| 异常场景 | 处理方式 | +| --- | --- | +| 模板文件不存在 | 批次标记失败,对话框提示缺少目标模板 | +| `.doc` 模板无法转换 | 对应模板导出失败,其他模板继续生成 | +| 字段未提取到 | 目标栏位留空,来源追溯清单记录为空 | +| 字段冲突 | 按说明书为准填入,模板内高亮标记,对话框展示冲突摘要 | +| PDF 转换失败 | 保留 Word 下载,提示 PDF 生成失败原因 | +| 模板版式明显错位 | 标记为需人工复核,不阻断 Word 文件下载 | + +--- + +## 六、信息提取与字段规则 + +### 6.1 字段范围 + +字段范围不固定写死,应以三个目标模板的实际栏目和清单条目为准动态建立。Demo 阶段优先覆盖以下字段: + +| 字段 | 说明 | +| --- | --- | +| 产品名称 | 产品标准名称 | +| 检测靶标 | 被检测物、基因、抗原、抗体、病原体或生物标志物 | +| 适用范围/预期用途 | 适用人群、样本类型、检测目的、临床用途 | +| 储存条件 | 温度、避光、防潮等保存条件 | +| 性能指标 | 分析灵敏度、特异性、重复性、准确度、检出限等 | +| 型号规格/包装规格 | 规格型号、包装规格、人份数或测试数 | +| 样本类型 | 血清、血浆、全血、咽拭子等 | +| 有效期 | 产品有效期或稳定性期限 | +| 主要组成成分 | 试剂、校准品、质控品、耗材等组成 | +| 检验原理 | 反应原理、方法学或检测平台 | +| 注册人/申请人 | 注册申请主体 | +| 生产地址 | 生产场所地址 | + +### 6.2 来源文件优先级 + +| 优先级 | 文件类型 | 说明 | +| --- | --- | --- | +| 1 | 说明书 | 字段冲突时默认以说明书为准 | +| 2 | 产品技术要求 | 用于补充性能指标、检验方法、组成成分等字段 | +| 3 | 注册检验报告/检测报告 | 用于补充性能指标、样本信息、检验依据和结论 | +| 4 | 性能研究资料 | 用于补充安全和性能基本原则清单证据 | +| 5 | 其他注册资料 | 用于补充申请人、生产地址、附件清单等信息 | + +### 6.3 冲突处理规则 + +| 场景 | 处理方式 | +| --- | --- | +| 说明书与其他文件字段不一致 | 按说明书值填入模板 | +| 多个非说明书文件不一致,说明书缺失 | 目标字段留空或取最高优先级来源,具体规则由实现阶段配置 | +| 字段被高亮标记 | 黄色底色、红色字体,提示用户下载后确认 | +| AI 对话框展示 | 展示字段名、采用值、冲突值、来源文件和目标模板 | + +--- + +## 七、安全和性能基本原则清单填写规则 + +安全和性能基本原则清单不只填写基础产品信息,还需要根据产品文件内容逐条判断清单条目的适用性、符合性证据和证明文件位置。 + +| 填写项 | 规则 | +| --- | --- | +| 适用/不适用 | 根据产品特性、检测方法、样本类型、是否含仪器/软件/灭菌/生物材料等信息判断 | +| 符合性说明 | 从产品技术要求、说明书、风险管理、性能研究、稳定性研究等文件中提取证据摘要 | +| 证明文件位置 | 填写证据文件名、章节、页码或可定位文本片段 | +| 无法判断 | 留空或标记待人工确认,来源追溯清单记录原因 | +| 冲突证据 | 如不同文件对同一条款适用性或证据描述冲突,保留高亮并在对话框列出 | + +逐条判断结果需要可追溯,不能只输出“适用”或“不适用”结论。 + +--- + +## 八、输出要求 + +### 8.1 文件命名 + +文件命名规则: + +```text +批次号-产品名称-注册证格式.docx +批次号-产品名称-注册证格式.pdf +批次号-产品名称-变更注册备案文件.docx +批次号-产品名称-变更注册备案文件.pdf +批次号-产品名称-安全和性能基本原则清单.docx +批次号-产品名称-安全和性能基本原则清单.pdf +批次号-产品名称-字段来源追溯清单.xlsx +``` + +产品名称为空时,可使用 `未识别产品名称` 作为文件名占位。 + +### 8.2 AI 对话框摘要 + +AI 对话框应展示生成结果、下载链接和冲突字段摘要。 + +```markdown +已生成申报模板自动填表文件。 + +| 文件 | Word | PDF | +| --- | --- | --- | +| 注册证格式 | 下载 | 下载 | +| 安全和性能基本原则清单 | 下载 | 下载 | + +| 冲突字段 | 采用值 | 冲突来源 | 处理 | +| --- | --- | --- | --- | +| 储存条件 | 2-8℃保存 | 产品技术要求:-20℃保存 | 已按说明书填入,并在模板中高亮 | +``` + +### 8.3 Word 输出 + +| 要求 | 说明 | +| --- | --- | +| 模板副本 | 从原始法规模板复制生成,不覆盖原始文件 | +| 版式保持 | 保留原模板表格、段落、分页、字体和标题结构 | +| 冲突高亮 | 黄色底色、红色字体 | +| 缺失字段 | 留空,不填“待补充” | +| 可编辑 | 用户可下载后继续人工修改 | + +### 8.4 PDF 输出 + +| 要求 | 说明 | +| --- | --- | +| 来源 | 由填好的 Word 转换生成 | +| 版式 | 尽量与原 Word 模板一致 | +| 用途 | 可作为正式提交前预览 | +| 失败处理 | PDF 失败不影响 Word 下载 | + +### 8.5 来源追溯清单 + +来源追溯清单允许额外生成,建议至少包含: + +| 字段 | 说明 | +| --- | --- | +| 目标模板 | 字段填入哪个模板 | +| 目标栏位/条目 | 字段对应的表格栏位或清单条目 | +| 填入值 | 实际写入模板的值 | +| 来源文件 | 取值来源文件 | +| 来源片段 | 支撑取值的文本片段 | +| 是否冲突 | 是/否 | +| 冲突值 | 其他文件中的不同值 | +| 处理方式 | 采用说明书、留空、高亮、待人工确认等 | + +--- + +## 九、功能模块梳理 + +| 序号 | 功能名称 | 功能描述 | 优先级 | +| --- | --- | --- | --- | +| 1 | 模板管理 | 维护三个目标模板路径、版本和适用注册类型 | P0 | +| 2 | 模板副本生成 | 将原始模板复制到批次工作目录 | P0 | +| 3 | 模板结构识别 | 识别模板中的表格字段、段落占位、清单条目 | P0 | +| 4 | 产品字段抽取 | 从上传文件中抽取模板所需产品字段 | P0 | +| 5 | 字段合并与冲突检测 | 按说明书优先级合并字段,并识别跨文件冲突 | P0 | +| 6 | Word 模板填充 | 将字段写入 Word 模板副本 | P0 | +| 7 | 冲突高亮 | 对冲突字段应用黄色底色和红色字体 | P0 | +| 8 | 基本原则逐条判断 | 判断安全和性能条目的适用性、符合性证据和证明文件位置 | P0 | +| 9 | PDF 转换 | 将填好的 Word 转为 PDF | P0 | +| 10 | 下载链接生成 | 在 AI 对话框提供 Word/PDF 下载链接 | P0 | +| 11 | 来源追溯清单导出 | 输出字段来源、冲突和填入目标 | P1 | +| 12 | 版式 QA | 对 Word/PDF 版式进行自动或人工可见检查 | P1 | + +--- + +## 十、数据实体分析 + +| 实体名称 | 字段说明 | 关联实体 | +| --- | --- | --- | +| 自动填表批次 | 批次编号、用户、会话、注册类型、产品名称、状态、错误信息、创建时间、完成时间 | 文件汇总批次、法规核查批次 | +| 模板副本 | 模板名称、模板类型、原始模板路径、副本路径、模板版本、适用条件 | 自动填表批次 | +| 提取字段 | 字段名、填入值、来源文件、来源片段、来源优先级、是否冲突、冲突详情 | 自动填表批次 | +| 填表结果文件 | 文件类型、文件名、Word 路径、PDF 路径、下载状态 | 自动填表批次 | +| 清单条目判断 | 条目编号、条目内容、适用性、符合性证据、证明文件位置、判断来源 | 自动填表批次 | + +--- + +## 十一、非功能性需求 + +### 11.1 可追溯性 + +| 要求 | 说明 | +| --- | --- | +| 字段来源可追溯 | 每个填入字段应能追溯到来源文件和文本片段 | +| 模板版本可追溯 | 每次生成记录原始模板文件名、版本和路径 | +| 冲突处理可追溯 | 冲突字段记录采用值、冲突值和处理规则 | +| 输出文件可追溯 | Word/PDF 文件关联批次、用户和会话 | + +### 11.2 安全要求 + +| 要求 | 说明 | +| --- | --- | +| 原始模板保护 | 不允许覆盖或修改原始法规资料目录中的模板 | +| 下载权限 | Word/PDF/追溯清单仅允许当前会话授权用户下载 | +| 敏感信息保护 | 对话框只展示必要冲突摘要,不展示大段敏感原文 | +| 文件隔离 | 不同用户、不同批次的模板副本和导出文件隔离存储 | + +### 11.3 版式要求 + +| 要求 | 说明 | +| --- | --- | +| Word 版式 | 尽量保持原模板表格、字体、分页和段落结构 | +| PDF 版式 | 与填好后的 Word 一致,可用于正式提交前预览 | +| 高亮可见 | 冲突字段在 Word 和 PDF 中均应能被用户识别 | +| 缺失字段不污染模板 | 未提取字段留空,不填入系统提示语 | + +### 11.4 性能要求 + +| 场景 | 要求 | +| --- | --- | +| 小批次资料 | 50 个文件以内,应在 1 分钟内完成字段抽取和模板生成 | +| 中等批次资料 | 200 个文件以内支持后台异步处理和进度提示 | +| 单个模板失败 | 不影响其他适用模板生成 | +| 单个字段失败 | 不影响整份模板生成,字段留空并记录原因 | + +--- + +## 十二、待后续确认事项 + +| 序号 | 待确认项 | 当前建议 | +| --- | --- | --- | +| 1 | `.doc` 模板转换方案 | 优先使用 LibreOffice/soffice 转 docx;无法部署时预置人工确认版 docx 模板 | +| 2 | 变更注册(备案)文件字段清单 | 需在模板可解析后补充字段映射 | +| 3 | 安全和性能基本原则清单条目结构 | 需在模板可解析后拆解条目编号、要求、适用性和证据栏 | +| 4 | 说明书识别规则 | 需明确如何从上传资料中判定哪份文件是说明书 | +| 5 | PDF 转换质量标准 | 需明确是否要求逐页渲染检查、页数一致和关键表格不跨页错位 | +| 6 | 注册类型无法识别时是否允许生成草稿 | 建议允许生成安全和性能基本原则清单,注册证或变更文件等待确认 | + +--- + +## 十三、验收标准 + +| 序号 | 验收项 | 验收标准 | +| --- | --- | --- | +| 1 | 模板复制 | 系统生成模板副本,不修改原始法规模板 | +| 2 | 首次注册文件选择 | 首次注册场景生成注册证格式和安全和性能基本原则清单 | +| 3 | 变更注册/备案文件选择 | 变更注册或备案场景生成变更注册(备案)文件和安全和性能基本原则清单 | +| 4 | 字段自动填写 | 产品名称、预期用途、储存条件、包装规格等字段能自动写入对应栏目 | +| 5 | 缺失字段留空 | 未提取到的字段保持空白 | +| 6 | 冲突字段高亮 | 字段冲突时按说明书值填入,并在 Word/PDF 中黄色底色、红色字体标记 | +| 7 | 冲突摘要展示 | AI 对话框展示冲突字段、采用值、冲突来源和处理方式 | +| 8 | 基本原则清单判断 | 系统能逐条输出适用/不适用、符合性证据和证明文件位置 | +| 9 | Word 下载 | 对话框提供填好后的 Word 下载链接 | +| 10 | PDF 下载 | 对话框提供由 Word 转换生成的 PDF 下载链接 | +| 11 | 来源追溯 | 可导出字段来源追溯清单,记录字段来源和冲突情况 | +| 12 | 异常不中断 | 单个字段、单个模板或 PDF 转换失败时,其他结果仍可正常输出 | + +--- + +## 十四、下一步建议 + +1. 将两个 `.doc` 原始模板转换为可解析的 `.docx` 工作模板,并人工确认版式无明显变化。 +2. 拆解三个模板的字段、表格和清单条目,形成模板字段映射配置。 +3. 扩展产品信息抽取字段,优先覆盖注册证模板已识别字段和安全和性能基本原则清单证据字段。 +4. 设计冲突高亮写入规则,确保 Word 与 PDF 中均可见。 +5. 接入 Word 到 PDF 转换能力,并建立页数、版式和关键表格的转换质量检查。 diff --git a/docs/2.功能设计/3.产品关键信息提取与申报文件自动填表.md b/docs/2.功能设计/3.产品关键信息提取与申报文件自动填表.md new file mode 100644 index 0000000..b4efdc4 --- /dev/null +++ b/docs/2.功能设计/3.产品关键信息提取与申报文件自动填表.md @@ -0,0 +1,816 @@ +# 产品关键信息提取与申报文件自动填表功能设计 + +## 文档信息 + +| 项目 | 内容 | +| --- | --- | +| 需求分析文档 | docs/1.需求分析/3.产品关键信息提取与申报文件自动填表.md | +| 依赖功能设计 | docs/2.功能设计/1.自动汇总.md;docs/2.功能设计/2.NMPA注册资料法规核查与整改闭环.md | +| 功能名称 | 产品关键信息提取与申报文件自动填表 | +| 所属模块 | 审核智能体 review_agent | +| 设计日期 | 2026-06-07 | +| 设计版本 | V1.0 | + +--- + +## 一、设计目标 + +本功能作为独立工作流 `application_form_fill` 建设,由用户在 AI 对话中触发,例如“帮我填注册证”“给我这个内容对应的表格”“为我该方案生成申报模板”“生成安全和性能基本原则清单”“把产品信息填到申报模板里”等。用户可以明确指定目标模板;未指定时,系统根据识别出的注册类型生成当前注册类型适用的全部模板。 + +本功能复用第一批文件汇总结果作为文件来源,复用第二批法规核查中的文本抽取、适用条件识别、LLM 调用、飞书通知和导出下载能力,但拥有独立批次、独立工作流卡片和独立过程产物。系统复制原始法规模板到批次工作目录,不覆盖原始文件;随后按模板配置识别应填字段,使用规则/正则抽取与 LLM 结构化抽取并行处理,合并字段、识别冲突、写入 Word 模板,并在 AI 对话框和飞书通知中提示生成结果与冲突摘要。 + +Demo 阶段优先保证 Word 模板自动填写和下载。PDF 转换作为待办增强项:功能设计保留 PDF 导出节点和数据结构,实施时可先返回 Word 与追溯清单,并在待办清单记录 PDF 转换能力。 + +--- + +## 二、与既有功能的关系 + +### 2.1 复用边界 + +| 能力 | 处理方式 | 现有代码/模型 | +| --- | --- | --- | +| 对话与用户权限 | 复用 | `Conversation`、`Message` | +| 附件上传与文件绑定 | 复用 | `FileAttachment`、`FileSummaryBatchAttachment` | +| 文件汇总与页数统计 | 复用 | `FileSummaryBatch`、`FileSummaryItem`、`file_summary.workflow` | +| 文本抽取 | 复用并扩展 | `regulatory_review/services/text_extract.py`、`rag_index.py` | +| 适用条件候选 | 复用并扩展 | `regulatory_review/services/info_extract.py` | +| LLM 调用 | 复用 | `review_agent/llm.py`、`regulatory_review/services/llm_review.py` | +| 导出记录与下载 | 扩展复用 | `ExportedSummaryFile` | +| 过程产物 | 复用 | `RegulatoryArtifact` 或新增填表过程产物 | +| 飞书通知 | 复用并扩展 | `regulatory_review/services/feishu_notifier.py` | +| SSE 工作流事件 | 复用 | `WorkflowNodeRun`、`WorkflowEvent` | + +### 2.2 新增边界 + +| 能力 | 说明 | +| --- | --- | +| 独立填表批次 | 新增 `ApplicationFormFillBatch`,不强绑法规核查批次 | +| 模板配置 | 新增 YAML 配置,维护模板路径、适用条件、字段映射和输出规则 | +| 模板选择 | 根据用户指定模板和注册类型选择生成范围 | +| 规则/正则与 LLM 并行抽取 | 两路抽取并行执行,最后统一合并 | +| 字段冲突归并 | 按来源文件优先级处理,说明书优先;冲突字段高亮 | +| Word 模板填充 | 使用 `python-docx` 对 `.docx` 表格、段落和占位字段写入 | +| `.doc` 模板转换 | 使用 LibreOffice/soffice 或预转换 `.docx` 模板 | +| 字段来源追溯 | 输出 Excel/JSON 追溯清单,记录抽取、合并和冲突证据 | + +--- + +## 三、总体架构 + +### 3.1 架构原则 + +| 原则 | 说明 | +| --- | --- | +| 独立工作流 | 填表流程拥有独立批次、节点和卡片,workflow_type 为 `application_form_fill` | +| 复用文件汇总 | 填表不重新实现上传扫描,默认使用当前对话最近成功的 `FileSummaryBatch` | +| 用户指令优先 | 用户明确指定模板或注册类型时,优先使用用户指令 | +| 配置驱动 | 模板路径、字段映射、适用条件和输出规则写入 YAML 配置 | +| Word 优先 | Demo 阶段优先生成可编辑 Word,PDF 作为增强项进入待办 | +| 可追溯 | 规则抽取、LLM 抽取、合并结果、冲突列表和来源证据均留底 | +| 失败隔离 | 单字段、单模板或 PDF 转换失败不影响其他模板输出 | +| 通知可控 | 填表完成后可通过飞书通知上传人,通知内容只包含摘要和下载提示 | + +### 3.2 逻辑架构 + +```mermaid +flowchart TD + A["AI 对话页"] --> B["意图识别 application_form_fill"] + B --> C{"本次消息是否带附件"} + C -->|"是"| D["先执行文件汇总工作流"] + C -->|"否"| E["查找最近成功 FileSummaryBatch"] + D --> E + E --> F["ApplicationFormFillBatch"] + F --> G["FormFillWorkflowExecutor"] + G --> H["模板配置 YAML"] + G --> I["模板选择服务"] + G --> J["文本抽取服务"] + J --> K1["规则/正则抽取"] + J --> K2["LLM 结构化抽取"] + K1 --> L["字段合并与冲突归并"] + K2 --> L + L --> M["Word 模板填充服务"] + M --> N["追溯清单导出"] + M --> O["PDF 转换服务 P1"] + N --> P["ExportedSummaryFile"] + O --> P + G --> Q["WorkflowEvent/SSE"] + Q --> R["自动填表工作流卡片"] + G --> S["FeishuNotifier"] + S --> T["上传人通知"] +``` + +### 3.3 技术选型 + +| 设计项 | Demo 方案 | 后续演进 | +| --- | --- | --- | +| Web 框架 | Django,沿用当前 `review_agent` 应用 | 保持 Django,必要时拆分独立 app | +| 工作流编排 | 新增轻量 `FormFillWorkflowExecutor` | 接入 LangGraph 子图 | +| 后台执行 | Django 后台线程,沿用现有工作流方式 | Celery/RQ + Redis | +| 工作流状态 | `WorkflowNodeRun` + `WorkflowEvent`,新增 workflow_type | 独立工作流事件中心 | +| 模板配置 | YAML,建议路径 `review_agent/application_form_fill/templates/application_form_templates_v1.yaml` | 数据库模板管理后台 | +| Word 处理 | `python-docx` 写入 `.docx` 表格和段落,高亮冲突字段 | OOXML 精细 patch、内容控件 SDT | +| `.doc` 转换 | LibreOffice/soffice headless 转 `.docx`;无法部署时预置 `.docx` 工作模板 | 模板入库前统一转换和人工校验 | +| PDF 导出 | P1 待办:LibreOffice/soffice headless 转 PDF | 逐页渲染 QA、版式差异检测 | +| Excel 追溯清单 | `openpyxl` | 增加多 Sheet 审核视图 | +| 文本抽取 | 复用 `text_extract.py`、`rag_index.py` | OCR、文档文本缓存 | +| 字段抽取 | 规则/正则与 LLM 结构化抽取并行,合并后输出 | 可配置抽取器和置信度模型 | +| 飞书通知 | 复用 `FeishuNotifier`,Demo 可 mock 或 CLI | 飞书 Webhook/API | + +--- + +## 四、触发与模板选择设计 + +### 4.1 意图识别 + +填表工作流通过用户对话触发。意图识别可先采用关键词规则,必要时调用现有 LLM 路由能力。 + +| 触发表达 | 触发结果 | +| --- | --- | +| 帮我填注册证 | 触发填表,指定注册证格式 | +| 给我这个内容对应的表格 | 触发填表,未指定模板 | +| 为我该方案生成申报模板 | 触发填表,未指定模板 | +| 生成安全和性能基本原则清单 | 触发填表,指定安全和性能基本原则清单 | +| 把产品信息填到申报模板里 | 触发填表,未指定模板 | +| 只生成变更注册备案文件 | 触发填表,指定变更注册(备案)文件 | + +### 4.2 文件来源选择 + +| 场景 | 处理方式 | +| --- | --- | +| 本次消息带新附件 | 先自动执行文件汇总,汇总成功后启动填表 | +| 本次消息无附件 | 默认使用当前对话最近一次成功 `FileSummaryBatch` | +| 无成功汇总批次 | 对话框提示用户先上传资料或补充附件 | +| 用户明确指定历史批次 | 校验批次属于当前对话和当前用户后使用 | + +### 4.3 注册类型识别优先级 + +注册类型用于决定默认生成哪些模板。优先级如下: + +```text +用户话语明确指定 +-> 当前对话已确认的法规核查条件 +-> 上传文件内容抽取结果 +-> 无法识别 +``` + +### 4.4 模板选择规则 + +| 场景 | 生成模板 | +| --- | --- | +| 用户未指定模板,注册类型为首次注册 | 注册证格式;安全和性能基本原则清单 | +| 用户未指定模板,注册类型为变更注册或备案 | 变更注册(备案)文件;安全和性能基本原则清单 | +| 用户未指定模板,注册类型无法识别 | 安全和性能基本原则清单;注册证/变更文件进入待确认提示 | +| 用户明确指定模板且与注册类型一致 | 只生成用户指定模板 | +| 用户明确指定模板但与注册类型不一致 | 允许生成,并在摘要和追溯清单提示“与识别注册类型不一致,需人工确认” | +| 用户指定“全部模板” | 生成三个目标模板,并提示用户核对注册类型适用性 | + +--- + +## 五、工作流设计 + +### 5.1 节点图 + +```mermaid +flowchart LR + N1["准备资料"] --> N2["选择模板"] + N2 --> N3["复制模板"] + N3 --> N4["抽取字段"] + N4 --> N5["冲突归并"] + N5 --> N6["填写 Word"] + N6 --> N7["转换 PDF P1"] + N6 --> N8["追溯清单"] + N7 --> N9["输出下载"] + N8 --> N9 + N9 --> N10["飞书通知"] + N10 --> N11["完成"] +``` + +### 5.2 节点定义 + +| 节点编码 | 节点名称 | 触发服务 | 成功条件 | 失败处理 | +| --- | --- | --- | --- | --- | +| prepare | 准备资料 | `FormFillWorkflowExecutor` | 找到或生成成功的 `FileSummaryBatch` | 无文件汇总则暂停提示上传 | +| template_select | 选择模板 | `TemplateSelectionService` | 输出本次目标模板列表 | 无适用模板则失败 | +| template_copy | 复制模板 | `TemplateRepository` | 模板副本进入批次工作目录 | 单模板失败不影响其他模板 | +| field_extract | 抽取字段 | `FieldExtractionService` | 规则/正则与 LLM 结果留底 | 单文件失败记录并继续 | +| conflict_merge | 冲突归并 | `FieldMergeService` | 输出最终字段和冲突列表 | 无字段时仍生成空模板 | +| word_fill | 填写 Word | `WordTemplateFillService` | 生成填好后的 Word 文件 | 单模板失败记录失败 | +| pdf_convert | 转换 PDF | `PdfConversionService` | P1:生成 PDF 文件 | PDF 失败标记 partial_success | +| trace_export | 追溯清单 | `TraceabilityExportService` | 生成 Excel/JSON 追溯清单 | 失败不影响 Word | +| output_export | 输出下载 | `FormFillExportService` | 写入 `ExportedSummaryFile` 并生成下载链接 | 关键 Word 失败则批次失败 | +| notify | 飞书通知 | `FeishuNotifier` | 通知上传人生成完成 | 通知失败不影响下载 | +| completed | 完成 | 工作流执行器 | 更新批次状态和对话消息 | - | + +### 5.3 状态设计 + +| 状态 | 含义 | +| --- | --- | +| pending | 已创建,等待执行 | +| running | 执行中 | +| waiting_user | 缺少文件或关键条件,等待用户补充 | +| success | Word 和必要追溯产物生成成功 | +| partial_success | Word 已生成,但部分模板、PDF、追溯清单或通知失败 | +| failed | 所有目标 Word 模板均生成失败 | +| skipped | 当前节点不适用,例如 Demo 阶段跳过 PDF | + +--- + +## 六、模板配置设计 + +### 6.1 配置文件路径 + +建议新增: + +```text +review_agent/application_form_fill/templates/application_form_templates_v1.yaml +``` + +### 6.2 配置结构 + +```yaml +version: application_form_templates_v1 +source_dir: docs/0.原始材料/关于公布体外诊断试剂注册申报资料要求和批准证明文件格式的公告 +templates: + - code: registration_certificate + name: 中华人民共和国医疗器械注册证(体外诊断试剂)(格式) + source_file: 中华人民共和国医疗器械注册证(体外诊断试剂)(格式).docx + output_label: 注册证格式 + applies_when: + registration_type: ["首次注册"] + file_format: docx + fields: + - key: product_name + label: 产品名称 + target: + type: table_row + row_label: 产品名称 + sources: ["说明书", "产品技术要求", "注册检验报告"] + - key: package_specification + label: 包装规格 + target: + type: table_row + row_label: 包装规格 + sources: ["说明书", "产品技术要求"] +``` + +### 6.3 模板配置项 + +| 配置项 | 说明 | +| --- | --- | +| code | 模板编码,用于用户指定和导出分类 | +| name | 模板中文名称 | +| source_file | 原始模板文件名 | +| working_template | 可选,预转换 `.docx` 工作模板 | +| output_label | 文件命名中的模板标签 | +| applies_when | 默认适用注册类型 | +| fields | 字段映射列表 | +| checklist_items | 安全和性能基本原则清单条目映射 | +| conversion | `.doc` 转 `.docx` 和 PDF 的转换策略 | + +### 6.4 已知模板字段 + +注册证格式当前已从 `.docx` 表格识别到以下字段:注册人名称、注册人住所、生产地址、代理人名称、代理人住所、产品名称、包装规格、主要组成成分、预期用途、产品储存条件及有效期、附件、其他内容、备注。 + +变更注册(备案)文件和安全和性能基本原则清单当前为 `.doc`,实施前需通过 LibreOffice/soffice 转换或预置人工确认版 `.docx` 工作模板,再补齐字段映射。 + +--- + +## 七、字段抽取与合并设计 + +### 7.1 三层提取链路 + +```text +模板字段配置 +-> 文档字段候选提取 +-> 规则/正则抽取与 LLM 结构化抽取并行 +-> 字段归一化 +-> 来源优先级合并 +-> 冲突识别 +-> 最终字段包 +``` + +### 7.2 规则/正则抽取 + +| 能力 | 说明 | +| --- | --- | +| 标签字段识别 | 识别 `产品名称:`、`预期用途:`、`储存条件:` 等标签行 | +| 表格字段识别 | 从 Word/Excel 表格中识别左侧字段名、右侧字段值 | +| 章节范围识别 | 从说明书、产品技术要求中按章节提取连续文本 | +| 文件类型识别 | 根据文件名、目录名和首页标题判断说明书、产品技术要求、检验报告 | +| 证据片段截取 | 保存字段前后上下文,用于追溯清单 | + +### 7.3 LLM 结构化抽取 + +LLM 输入为模板字段清单、文件上下文和候选文本片段,输出严格 JSON: + +```json +{ + "fields": [ + { + "key": "storage_condition", + "label": "产品储存条件及有效期", + "value": "2-8℃保存,有效期12个月", + "source_file": "说明书.docx", + "evidence": "产品储存条件:2-8℃保存...", + "confidence": 0.86 + } + ], + "checklist_items": [ + { + "item_code": "A1", + "applicability": "适用", + "compliance_evidence": "产品技术要求中规定了性能指标和检验方法", + "proof_location": "产品技术要求.docx 第2章" + } + ] +} +``` + +### 7.4 并行合并规则 + +| 场景 | 处理规则 | +| --- | --- | +| 规则和 LLM 值一致 | 合并为同一字段,提高置信度 | +| 规则和 LLM 值不一致,但来源文件不同 | 按来源文件优先级处理,说明书优先 | +| 规则和 LLM 值不一致,来源文件相同 | 标记冲突,模板中高亮 | +| 说明书与其他文件冲突 | 采用说明书值,黄色底色、红色字体标记 | +| 说明书缺失,多个来源冲突 | 取最高优先级文件值并标记冲突;无法判断则留空 | +| 字段缺失 | 模板留空,追溯清单记录未提取 | + +### 7.5 过程产物留底 + +字段抽取结果保存为 `field_extract_result.json`,至少包含: + +| 内容 | 说明 | +| --- | --- | +| regex_results | 规则/正则抽取结果 | +| llm_results | LLM 结构化抽取结果 | +| merged_fields | 合并后的最终字段 | +| conflicts | 冲突字段列表 | +| source_evidence | 来源文件和文本片段 | +| selected_templates | 本次选择的模板 | + +--- + +## 八、安全和性能基本原则清单设计 + +### 8.1 判断策略 + +安全和性能基本原则清单采用“候选判断 + 高置信度写入”策略。 + +| 步骤 | 说明 | +| --- | --- | +| 条目拆解 | 从模板配置中读取条目编号、原则内容、适用性栏、证据栏、证明文件位置栏 | +| 候选判断 | 规则和 LLM 均可给出适用/不适用候选 | +| 证据匹配 | 从产品技术要求、说明书、性能研究、稳定性研究、风险管理资料中匹配证明文件 | +| 高置信度写入 | 仅将高置信度判断写入 Word | +| 低置信度留空 | 证据不足或判断不一致时 Word 留空,追溯清单记录候选判断 | +| 冲突提示 | 冲突条目在对话框和追溯清单中提示,不强行填入 | + +### 8.2 输出字段 + +| 字段 | 说明 | +| --- | --- | +| 条目编号 | 基本原则清单中的条目编码 | +| 条目内容 | 原始原则或要求 | +| 适用性 | 适用/不适用,低置信度留空 | +| 符合性证据 | 高置信度证据摘要 | +| 证明文件位置 | 文件名、章节、页码或文本定位 | +| 置信度 | 用于判断是否写入 Word | +| 候选来源 | 规则、LLM 或两者一致 | + +--- + +## 九、Word 与 PDF 生成设计 + +### 9.1 Word 模板填充 + +| 能力 | 说明 | +| --- | --- | +| 模板副本 | 原始模板复制到批次工作目录后再写入 | +| 表格行填充 | 根据行首字段名定位目标单元格 | +| 段落占位填充 | 支持 `{{field_key}}` 等占位符 | +| 清单条目填充 | 按条目编号和配置列写入适用性、证据和证明位置 | +| 冲突高亮 | 冲突字段使用黄色底色和红色字体 | +| 缺失字段 | 保持空白,不写“待补充” | +| 版式保持 | 尽量不改变表格结构、分页和字体 | + +### 9.2 PDF 转换 + +PDF 转换作为 P1 待办增强项设计: + +| 阶段 | 处理 | +| --- | --- | +| Demo 主链路 | 优先生成 Word,不因 PDF 能力缺失阻断工作流 | +| P1 增强 | 使用 LibreOffice/soffice headless 将 Word 转为 PDF | +| 失败处理 | Word 已生成但 PDF 失败时,批次状态为 `partial_success` | +| QA 增强 | 后续增加 PDF 页数非 0、逐页截图或版式差异检查 | + +--- + +## 十、输出与下载设计 + +### 10.1 输出文件 + +| 文件 | Demo 阶段 | P1/P2 | +| --- | --- | --- | +| 填好后的 Word | 必须生成 | 持续支持 | +| PDF 预览 | 待办增强 | LibreOffice 转换生成 | +| 字段来源追溯清单 Excel | 允许生成,建议实现 | 增加多 Sheet | +| 字段抽取 JSON | 过程产物留底 | 支持下载或调试查看 | + +### 10.2 文件命名 + +```text +批次号-产品名称-注册证格式.docx +批次号-产品名称-注册证格式.pdf +批次号-产品名称-变更注册备案文件.docx +批次号-产品名称-变更注册备案文件.pdf +批次号-产品名称-安全和性能基本原则清单.docx +批次号-产品名称-安全和性能基本原则清单.pdf +批次号-产品名称-字段来源追溯清单.xlsx +``` + +### 10.3 ExportedSummaryFile 扩展 + +继续复用 `ExportedSummaryFile`,但需要扩展 `ExportType`: + +| export_type | 说明 | +| --- | --- | +| markdown | 既有 Markdown 报告 | +| excel | Excel 追溯清单 | +| json | 字段抽取 JSON 或结果包 | +| word | 填好的 Word 文件,新增 | +| pdf | Word 转换后的 PDF,新增 | + +填表工作流导出记录建议: + +| 字段 | 值 | +| --- | --- | +| workflow_type | `application_form_fill` | +| workflow_batch_id | `ApplicationFormFillBatch.id` | +| export_category | `filled_template`、`traceability`、`extract_result` | +| export_type | `word`、`pdf`、`excel`、`json` | + +导出服务入参应包含目标输出类型列表,例如: + +```json +{ + "output_types": ["word", "pdf", "excel"], + "template_codes": ["registration_certificate", "essential_principles"] +} +``` + +系统根据入参决定生成哪些类型的内容。 + +--- + +## 十一、数据模型设计 + +### 11.1 ApplicationFormFillBatch + +新增自动填表批次表。 + +| 字段 | 类型 | 说明 | +| --- | --- | --- | +| id | BigAutoField | 主键 | +| conversation | ForeignKey(Conversation) | 绑定对话 | +| user | ForeignKey(User) | 发起用户 | +| source_summary_batch | ForeignKey(FileSummaryBatch) | 文件来源批次 | +| source_regulatory_batch | ForeignKey(RegulatoryReviewBatch, null=True) | 可选,复用已确认法规条件 | +| batch_no | CharField | 填表批次号,如 AFF-YYYYMMDDHHMMSS | +| status | CharField | pending、running、waiting_user、success、partial_success、failed | +| trigger_message | ForeignKey(Message, null=True) | 触发消息 | +| requested_templates | JSONField | 用户指定模板 | +| selected_templates | JSONField | 实际生成模板 | +| output_types | JSONField | 请求输出类型,如 word、pdf、excel | +| registration_type | CharField | 注册类型 | +| product_name | CharField | 产品名称 | +| conflict_summary | JSONField | 冲突摘要 | +| risk_notes | JSONField | 不适用模板、低置信度等提示 | +| work_dir | CharField | 批次工作目录 | +| error_message | TextField | 异常说明 | +| created_at | DateTimeField | 创建时间 | +| started_at | DateTimeField | 开始时间 | +| finished_at | DateTimeField | 完成时间 | + +### 11.2 ApplicationFormFillArtifact + +可新增独立过程产物表,也可复用 `RegulatoryArtifact`。考虑到这是独立工作流,建议新增轻量产物表,结构与 `RegulatoryArtifact` 保持一致。 + +| 字段 | 类型 | 说明 | +| --- | --- | --- | +| id | BigAutoField | 主键 | +| batch | ForeignKey(ApplicationFormFillBatch) | 所属填表批次 | +| artifact_type | CharField | template_copy、field_extract_result、merged_fields、traceability、notification_record | +| file_format | CharField | json、excel、docx、pdf | +| name | CharField | 产物名称 | +| storage_path | CharField | 存储路径 | +| metadata | JSONField | 模板编码、输出类型、生成状态等 | +| content_hash | CharField | 文件 hash | +| created_at | DateTimeField | 创建时间 | + +### 11.3 与既有模型关系 + +```text +Conversation 1:N ApplicationFormFillBatch +FileSummaryBatch 1:N ApplicationFormFillBatch +RegulatoryReviewBatch 0:N ApplicationFormFillBatch +ApplicationFormFillBatch 1:N ApplicationFormFillArtifact +ApplicationFormFillBatch 1:N WorkflowNodeRun +ApplicationFormFillBatch 1:N ExportedSummaryFile +``` + +--- + +## 十二、后端服务设计 + +### 12.1 FormFillWorkflowExecutor + +| 方法 | 说明 | +| --- | --- | +| run(batch) | 串行执行自动填表节点 | +| run_node(node) | 执行单节点并记录进度 | +| resolve_source_summary_batch() | 根据本次附件或最近成功批次确定来源 | +| emit_event() | 写入 `WorkflowEvent` | +| complete_or_partial() | 根据 Word/PDF/通知结果更新批次状态 | + +### 12.2 TemplateSelectionService + +| 方法 | 说明 | +| --- | --- | +| parse_requested_templates(message) | 从用户话语中识别指定模板 | +| detect_registration_type() | 按用户话语、法规确认条件、文件抽取识别注册类型 | +| select_templates() | 根据注册类型和用户指令输出模板列表 | + +### 12.3 TemplateRepository + +| 方法 | 说明 | +| --- | --- | +| load_config() | 读取 YAML 模板配置 | +| resolve_source_template(code) | 找到原始模板或预转换模板 | +| copy_to_work_dir(code, batch) | 复制模板到批次目录 | +| convert_doc_to_docx(path) | `.doc` 转 `.docx` | + +### 12.4 FieldExtractionService + +| 方法 | 说明 | +| --- | --- | +| extract_by_rules(texts, template_fields) | 规则/正则抽取 | +| extract_by_llm(texts, template_fields) | LLM 结构化抽取 | +| run_parallel() | 并行执行两路抽取 | +| save_extract_artifact() | 保存 `field_extract_result.json` | + +### 12.5 FieldMergeService + +| 方法 | 说明 | +| --- | --- | +| normalize_fields() | 字段名、单位、空白和同义词归一 | +| rank_sources() | 按说明书、产品技术要求、检验报告等来源排序 | +| merge() | 输出最终字段 | +| detect_conflicts() | 输出冲突列表和高亮标记 | + +### 12.6 WordTemplateFillService + +| 方法 | 说明 | +| --- | --- | +| fill_table_rows() | 根据行名定位表格单元格并写入 | +| fill_placeholders() | 替换段落占位符 | +| fill_checklist_items() | 写入安全和性能基本原则清单 | +| apply_conflict_highlight() | 黄底红字标记冲突字段 | +| save_docx() | 保存填好后的 Word | + +### 12.7 TraceabilityExportService + +| 方法 | 说明 | +| --- | --- | +| build_excel() | 生成字段来源追溯清单 | +| build_json() | 生成结构化追溯 JSON | +| create_export_records() | 写入 `ExportedSummaryFile` | + +### 12.8 FormFillNotifier + +复用或包装 `FeishuNotifier`。 + +| 通知场景 | 说明 | +| --- | --- | +| 填表成功 | 通知上传人文件已生成 | +| 部分成功 | 通知 Word 已生成,但 PDF/部分模板失败 | +| 冲突字段存在 | 通知中提示存在冲突字段,需下载核对 | +| 失败 | 可选通知失败原因,Demo 可只在对话框展示 | + +--- + +## 十三、接口设计 + +### 13.1 发起自动填表 + +| 项目 | 内容 | +| --- | --- | +| URL | POST /api/review-agent/application-form-fill/start/ | +| 认证 | 登录用户 | +| 请求 | conversation_id、message_id、file_summary_batch_id 可选、template_codes 可选、output_types 可选 | +| 响应 | batch_id、workflow_type、status、selected_templates | + +处理规则: + +```text +校验 conversation 属于当前用户 +-> 如本次消息带附件,先执行文件汇总 +-> 否则查找当前对话最近成功 FileSummaryBatch +-> 创建 ApplicationFormFillBatch +-> 初始化 WorkflowNodeRun +-> 启动 FormFillWorkflowExecutor +-> 返回工作流卡片初始状态 +``` + +### 13.2 查询自动填表状态 + +| 项目 | 内容 | +| --- | --- | +| URL | GET /api/review-agent/application-form-fill/{batch_id}/ | +| 认证 | 登录用户 | +| 响应 | 批次状态、节点状态、选择模板、冲突摘要、导出文件 | + +### 13.3 下载导出文件 + +继续复用: + +| 项目 | 内容 | +| --- | --- | +| URL | GET /api/review-agent/file-summary/exports/{export_id}/download/ | +| 认证 | 登录用户 | +| 响应 | 文件流 | + +权限规则: + +```text +export_id -> workflow_type/workflow_batch_id -> ApplicationFormFillBatch -> conversation -> user +必须等于当前登录用户,才允许下载。 +``` + +--- + +## 十四、前端设计 + +### 14.1 自动填表工作流卡片 + +前端新增独立卡片类型 `application_form_fill`,展示节点: + +| 节点 | 展示文案 | +| --- | --- | +| prepare | 准备资料 | +| template_select | 选择模板 | +| template_copy | 复制模板 | +| field_extract | 抽取字段 | +| conflict_merge | 冲突归并 | +| word_fill | 填写 Word | +| pdf_convert | 转换 PDF | +| output_export | 输出下载 | +| notify | 飞书通知 | +| completed | 已完成 | + +### 14.2 对话框结果展示 + +工作流完成后,AI 对话框展示 Markdown 摘要: + +```markdown +已生成申报模板自动填表文件。 + +| 文件 | Word | PDF | +| --- | --- | --- | +| 注册证格式 | 下载 | 待生成 | +| 安全和性能基本原则清单 | 下载 | 待生成 | + +| 冲突字段 | 采用值 | 冲突来源 | 处理 | +| --- | --- | --- | --- | +| 储存条件 | 2-8℃保存 | 产品技术要求:-20℃保存 | 已按说明书填入,并在模板中高亮 | + +[下载字段来源追溯清单](download-url) +``` + +### 14.3 指定模板交互 + +用户可以通过自然语言指定模板。前端无需额外表单,后端意图识别后在卡片中展示本次选择模板。 + +--- + +## 十五、事件设计 + +### 15.1 SSE 事件结构 + +```json +{ + "event": "workflow", + "workflow_type": "application_form_fill", + "batch_id": 3001, + "conversation_id": 1001, + "node_code": "field_extract", + "node_group": "form_fill", + "status": "running", + "progress": 55, + "message": "正在并行抽取模板字段", + "payload": { + "selected_templates": ["registration_certificate", "essential_principles"], + "processed_files": 8, + "total_files": 20 + } +} +``` + +### 15.2 节点进度 + +| 节点 | 进度口径 | +| --- | --- | +| 准备资料 | 是否找到来源批次 | +| 选择模板 | 模板数量 | +| 复制模板 | 已复制模板数/总模板数 | +| 抽取字段 | 已处理文件数/总文件数 | +| 冲突归并 | 字段数量和冲突数量 | +| 填写 Word | 已生成 Word 数/目标 Word 数 | +| 转换 PDF | 已生成 PDF 数/目标 PDF 数 | +| 输出下载 | 已创建下载记录数 | +| 飞书通知 | 通知状态 | + +--- + +## 十六、异常与降级设计 + +| 场景 | 处理 | +| --- | --- | +| 无成功文件汇总批次 | 进入 waiting_user,提示上传资料 | +| 新附件汇总失败 | 填表工作流不启动或标记失败 | +| 用户指定不适用模板 | 允许生成,摘要提示需人工确认 | +| `.doc` 转换失败 | 该模板失败,其他模板继续 | +| 单字段缺失 | Word 留空,追溯清单记录未提取 | +| 规则和 LLM 冲突 | 按来源优先级合并,冲突高亮 | +| 所有 Word 生成失败 | 批次 failed | +| 部分 Word 生成失败 | 批次 partial_success | +| PDF 转换失败 | 批次 partial_success,保留 Word 下载 | +| 飞书通知失败 | 不影响文件下载,记录通知失败 | + +--- + +## 十七、安全设计 + +| 设计点 | 说明 | +| --- | --- | +| 原始模板保护 | 只读原始模板,所有写入发生在批次工作目录副本 | +| 对话隔离 | 填表批次必须绑定当前 Conversation | +| 文件读取权限 | 只能读取关联 `FileSummaryBatch` 下的文件 | +| 下载权限 | 根据 workflow_type 和 workflow_batch_id 校验当前用户 | +| LLM 输入控制 | 只传必要文本片段和字段上下文,避免发送整包敏感资料 | +| 飞书脱敏 | 通知仅包含生成状态、模板名称、冲突数量和系统内下载提示 | +| 命令调用安全 | LibreOffice/飞书 CLI 使用结构化参数,不拼接用户输入 | + +--- + +## 十八、验收设计 + +| 序号 | 验收项 | 验收标准 | +| --- | --- | --- | +| 1 | 意图触发 | 用户说“帮我填注册证”等语句可触发 `application_form_fill` | +| 2 | 指定模板 | 用户指定模板时只生成指定模板 | +| 3 | 默认模板 | 未指定模板时按注册类型生成适用的全部模板 | +| 4 | 新附件串联 | 本次消息带附件时先自动汇总,再执行填表 | +| 5 | 最近批次复用 | 无附件时复用当前对话最近成功文件汇总批次 | +| 6 | 工作流卡片 | 前端展示准备资料、选择模板、复制模板、抽取字段、填写 Word 等节点 | +| 7 | 字段并行抽取 | 规则/正则和 LLM 抽取结果均进入过程产物 | +| 8 | 冲突归并 | 说明书优先,冲突字段在 Word 中黄底红字 | +| 9 | 缺失字段 | 未提取字段在 Word 中留空 | +| 10 | 基本原则清单 | 高置信度条目写入,低置信度候选留在追溯清单 | +| 11 | Word 下载 | 对话框提供填好后的 Word 下载链接 | +| 12 | PDF 待办 | Demo 阶段 PDF 可展示为待生成,不阻断 Word | +| 13 | 追溯清单 | 生成字段来源追溯清单,包含规则、LLM、合并和冲突信息 | +| 14 | 飞书通知 | 填表完成后可通知上传人,失败不影响下载 | +| 15 | 权限隔离 | A 对话生成的 Word/追溯清单不能被 B 对话访问 | + +--- + +## 十九、实施建议 + +1. 新增 `ApplicationFormFillBatch` 和 `ApplicationFormFillArtifact` 数据模型,扩展 `ExportedSummaryFile.ExportType` 支持 `word`、`pdf`。 +2. 新增模板配置 `application_form_templates_v1.yaml`,先录入注册证格式 `.docx` 的已识别字段。 +3. 将两个 `.doc` 模板转换为 `.docx` 工作模板,或在配置中标记为待转换模板。 +4. 实现 `TemplateSelectionService`,支持用户指定模板、注册类型识别和默认模板选择。 +5. 实现规则/正则与 LLM 并行字段抽取,并保存 `field_extract_result.json`。 +6. 实现 `FieldMergeService`,按说明书优先规则处理冲突。 +7. 实现 `WordTemplateFillService`,优先支持表格行填充和冲突高亮。 +8. 实现追溯清单 Excel 导出和 Word 下载记录。 +9. 改造前端工作流卡片,新增 `application_form_fill` 类型。 +10. 接入飞书通知摘要。 +11. 将 PDF 转换、逐页版式 QA 和更完整的 `.doc` 模板转换纳入后续待办。 + +--- + +## 二十、待办与待确认事项 + +| 序号 | 项目 | 当前建议 | +| --- | --- | --- | +| 1 | PDF 转换 | 放入待办,Demo 优先 Word 下载 | +| 2 | `.doc` 模板转换 | 优先 LibreOffice/soffice;不可用时预置 `.docx` 工作模板 | +| 3 | 安全和性能基本原则清单条目拆解 | 需转换模板后补齐 YAML 条目配置 | +| 4 | LLM 结构化抽取提示词 | 需约束输出 JSON schema 和置信度 | +| 5 | 飞书通知渠道 | Demo 可 mock 或 CLI,正式版接 Webhook/API | +| 6 | 低置信度阈值 | 建议功能实现阶段先配置为 0.75 | +| 7 | 版式验证 | P1 增加 PDF 页数检查和逐页截图 QA | diff --git a/docs/3.详细设计/3.产品关键信息提取与申报文件自动填表.md b/docs/3.详细设计/3.产品关键信息提取与申报文件自动填表.md new file mode 100644 index 0000000..fa88fe7 --- /dev/null +++ b/docs/3.详细设计/3.产品关键信息提取与申报文件自动填表.md @@ -0,0 +1,790 @@ +# 产品关键信息提取与申报文件自动填表详细设计 + +## 文档信息 + +| 项目 | 内容 | +| --- | --- | +| 需求分析文档 | docs/1.需求分析/3.产品关键信息提取与申报文件自动填表.md | +| 功能设计文档 | docs/2.功能设计/3.产品关键信息提取与申报文件自动填表.md | +| 数据库设计文档 | docs/4.数据库设计/3.产品关键信息提取与申报文件自动填表.md | +| 依赖详细设计 | docs/3.详细设计/1.自动汇总.md;docs/3.详细设计/2.NMPA注册资料法规核查与整改闭环.md | +| 功能名称 | 产品关键信息提取与申报文件自动填表 | +| 所属模块 | 审核智能体 review_agent | +| 设计日期 | 2026-06-07 | +| 设计版本 | V1.0 | + +--- + +## 一、详细设计目标 + +本详细设计用于指导“产品关键信息提取与申报文件自动填表”功能开发落地,覆盖代码结构、数据库模型、模板配置、独立工作流、字段抽取、字段合并、Word 模板填充、追溯清单导出、飞书通知、接口契约、前端卡片、异常降级和测试建议。 + +核心约束: + +| 约束 | 说明 | +| --- | --- | +| 独立工作流 | 使用 `workflow_type=application_form_fill`,拥有独立批次和卡片 | +| 对话触发 | 由用户自然语言触发,可指定模板;未指定时按注册类型选择适用模板 | +| 文件来源复用 | 默认使用当前对话最近成功的 `FileSummaryBatch`;本次带附件时先执行自动汇总 | +| 模板配置驱动 | 模板路径、字段映射、适用条件写入 `application_form_fill/templates/application_form_templates_v1.yaml` | +| Word 优先 | Demo 阶段主链路只要求生成 Word 和追溯清单 | +| PDF 待办 | PDF 转换节点保留,但本期可标记 skipped 并写入待办计划 | +| 抽取并行 | 规则/正则抽取与 LLM 结构化抽取并行执行,再统一合并 | +| 冲突可见 | 说明书优先;冲突字段写入 Word 时黄底红字,并在对话框展示摘要 | +| 过程留底 | 规则抽取、LLM 抽取、合并结果、冲突和追溯清单均保存产物 | +| 飞书通知 | 填表完成后通知上传人,通知失败不阻断下载 | + +--- + +## 二、代码结构设计 + +### 2.1 目录结构 + +第三批独立为 `review_agent/application_form_fill/` 模块。Django 模型仍集中在 `review_agent/models.py`,业务服务放入独立模块。 + +```text +review_agent/ + models.py + services.py + skill_router.py + application_form_fill/ + __init__.py + constants.py + schemas.py + storage.py + workflow.py + views.py + services/ + __init__.py + template_config.py + template_select.py + template_repository.py + field_extract.py + field_merge.py + word_fill.py + traceability_export.py + notifier.py + templates/ + application_form_templates_v1.yaml + prompts/ + field_extract.md + checklist_extract.md +``` + +### 2.2 文件职责 + +| 文件 | 职责 | +| --- | --- | +| application_form_fill/constants.py | 工作流节点、模板编码、状态、输出类型常量 | +| application_form_fill/schemas.py | FormFillContext、TemplateSpec、ExtractedField、MergedField 等 dataclass | +| application_form_fill/storage.py | 批次工作目录、模板副本、产物保存、hash 计算 | +| application_form_fill/workflow.py | FormFillWorkflowExecutor,串行执行独立填表工作流 | +| application_form_fill/views.py | 启动、状态查询、后续可选下载或重试接口 | +| services/template_config.py | 读取和校验 YAML 模板配置 | +| services/template_select.py | 解析用户指定模板、识别注册类型、选择模板 | +| services/template_repository.py | 定位原始模板、复制模板、`.doc` 转 `.docx` 预留 | +| services/field_extract.py | 规则/正则与 LLM 并行字段抽取 | +| services/field_merge.py | 字段归一化、来源排序、冲突识别、最终字段输出 | +| services/word_fill.py | 使用 `python-docx` 写入 Word 表格、段落和高亮 | +| services/traceability_export.py | 生成 Excel/JSON 追溯清单,创建导出记录 | +| services/notifier.py | 包装飞书通知,生成通知记录 | +| prompts/field_extract.md | LLM 字段抽取提示词 | +| prompts/checklist_extract.md | 安全和性能基本原则清单条目判断提示词 | + +--- + +## 三、依赖设计 + +### 3.1 Python 依赖 + +| 依赖 | 用途 | 当前项目情况 | +| --- | --- | --- | +| Django | Web、ORM、权限 | 已使用 | +| python-docx | Word 模板读取、表格填充、字体和底色设置 | 已在项目依赖链中使用 | +| openpyxl | 字段来源追溯清单 Excel 导出 | 已使用 | +| PyYAML | YAML 模板配置读取 | 已用于法规规则 | +| pypdf / python-pptx | 文本抽取链路复用 | 已使用 | +| LibreOffice/soffice | `.doc` 转 `.docx`、PDF 转换 | 本期非强依赖,后续待办 | + +### 3.2 技术边界 + +| 能力 | 本期实现 | 后续增强 | +| --- | --- | --- | +| `.docx` 模板填充 | 必须支持 | 支持内容控件、复杂 OOXML patch | +| `.doc` 模板处理 | 可通过预转换模板或标记失败 | 自动 LibreOffice 转换 | +| PDF 转换 | 可跳过并提示待生成 | LibreOffice 转 PDF + 视觉 QA | +| 字段级入库 | 不做 | 新增字段明细表和在线编辑 | +| LLM 抽取 | 输出 JSON 并留底 | 增加置信度校准和人工确认 | + +--- + +## 四、数据模型详细设计 + +模型放在 `review_agent/models.py`。 + +### 4.1 ApplicationFormFillBatch + +```python +class ApplicationFormFillBatch(models.Model): + class Status(models.TextChoices): + PENDING = "pending", "待执行" + RUNNING = "running", "执行中" + WAITING_USER = "waiting_user", "等待用户" + SUCCESS = "success", "成功" + PARTIAL_SUCCESS = "partial_success", "部分成功" + FAILED = "failed", "失败" + CANCELLED = "cancelled", "已取消" +``` + +关键字段: + +| 字段 | 说明 | +| --- | --- | +| conversation | 绑定对话 | +| user | 发起用户 | +| trigger_message | 触发消息 | +| source_summary_batch | 文件来源批次 | +| source_regulatory_batch | 可选法规核查批次 | +| batch_no | `AFF-YYYYMMDDHHMMSS-abcdef` | +| requested_templates | 用户指定模板 | +| selected_templates | 实际生成模板 | +| output_types | 本次请求输出类型,Demo 默认 `["word", "excel", "json"]` | +| registration_type | 识别出的注册类型 | +| registration_type_source | 注册类型来源 | +| product_name | 产品名称 | +| conflict_summary | 冲突摘要 | +| risk_notes | 不适用模板、PDF 待生成等提示 | +| template_config_version | 模板配置版本 | +| template_config_hash | 模板配置 hash | +| work_dir | 批次工作目录 | + +### 4.2 ApplicationFormFillArtifact + +用于保存过程产物和模板副本元数据。 + +```python +class ApplicationFormFillArtifact(models.Model): + class ArtifactType(models.TextChoices): + TEMPLATE_COPY = "template_copy", "模板副本" + FIELD_EXTRACT_RESULT = "field_extract_result", "字段抽取结果" + MERGED_FIELDS = "merged_fields", "字段合并结果" + TRACEABILITY = "traceability", "追溯清单" + FILLED_TEMPLATE = "filled_template", "已填模板" + NOTIFICATION_RECORD = "notification_record", "通知记录" +``` + +### 4.3 ApplicationFormFillNotificationRecord + +通知记录字段与第二批法规通知风格一致,支持重试: + +| 字段 | 说明 | +| --- | --- | +| batch | 自动填表批次 | +| recipient | 通知对象 | +| channel | feishu_cli、feishu_api、mock | +| template_codes | 涉及模板 | +| export_ids | 关联下载文件 | +| message_summary | 通知摘要 | +| send_status | pending、success、failed | +| retry_count | 重试次数 | +| external_message_id | 飞书外部消息 ID | +| error_message | 失败原因 | +| sent_at | 发送成功时间 | + +### 4.4 ExportedSummaryFile 扩展 + +`ExportedSummaryFile.ExportType` 增加: + +```python +WORD = "word", "Word" +PDF = "pdf", "PDF" +``` + +填表导出记录使用: + +| 字段 | 值 | +| --- | --- | +| workflow_type | application_form_fill | +| workflow_batch_id | ApplicationFormFillBatch.id | +| export_category | filled_template、traceability、extract_result | +| export_type | word、excel、json、pdf | + +--- + +## 五、常量设计 + +### 5.1 工作流节点 + +```python +FORM_FILL_NODE_DEFINITIONS = [ + ("prepare", "准备资料", "form_fill"), + ("template_select", "选择模板", "form_fill"), + ("template_copy", "复制模板", "form_fill"), + ("field_extract", "抽取字段", "form_fill"), + ("conflict_merge", "冲突归并", "form_fill"), + ("word_fill", "填写 Word", "form_fill"), + ("pdf_convert", "转换 PDF", "form_fill"), + ("trace_export", "追溯清单", "form_fill"), + ("output_export", "输出下载", "form_fill"), + ("notify", "飞书通知", "form_fill"), + ("completed", "完成", "completed"), +] +``` + +### 5.2 模板编码 + +```python +TEMPLATE_REGISTRATION_CERTIFICATE = "registration_certificate" +TEMPLATE_CHANGE_REGISTRATION = "change_registration" +TEMPLATE_ESSENTIAL_PRINCIPLES = "essential_principles" +``` + +### 5.3 触发关键词 + +```python +FORM_FILL_TRIGGER_KEYWORDS = [ + "填注册证", + "对应的表格", + "生成申报模板", + "安全和性能基本原则清单", + "填到申报模板", + "自动填表", + "生成表格", +] +``` + +--- + +## 六、核心数据结构 + +### 6.1 FormFillContext + +```python +@dataclass +class FormFillContext: + batch: ApplicationFormFillBatch + source_summary_batch: FileSummaryBatch + source_regulatory_batch: RegulatoryReviewBatch | None + template_config: dict[str, Any] + selected_templates: list["TemplateSpec"] + document_texts: dict[str, str] + regex_results: dict[str, Any] + llm_results: dict[str, Any] + merged_fields: dict[str, "MergedField"] + checklist_items: dict[str, Any] + conflicts: list[dict[str, Any]] + exports: list[ExportedSummaryFile] +``` + +### 6.2 TemplateSpec + +```python +@dataclass(frozen=True) +class TemplateSpec: + code: str + name: str + source_file: str + output_label: str + applies_when: dict[str, Any] + file_format: str + fields: list[dict[str, Any]] + checklist_items: list[dict[str, Any]] +``` + +### 6.3 ExtractedField + +```python +@dataclass(frozen=True) +class ExtractedField: + key: str + label: str + value: str + source_file: str + source_role: str + evidence: str + extractor: str + confidence: float +``` + +### 6.4 MergedField + +```python +@dataclass(frozen=True) +class MergedField: + key: str + label: str + value: str + source_file: str + evidence: str + confidence: float + has_conflict: bool = False + conflict_values: list[dict[str, Any]] = field(default_factory=list) +``` + +--- + +## 七、模板配置详细设计 + +### 7.1 配置路径 + +```text +review_agent/application_form_fill/templates/application_form_templates_v1.yaml +``` + +### 7.2 初始配置示例 + +```yaml +version: application_form_templates_v1 +source_dir: docs/0.原始材料/关于公布体外诊断试剂注册申报资料要求和批准证明文件格式的公告 +templates: + - code: registration_certificate + name: 中华人民共和国医疗器械注册证(体外诊断试剂)(格式) + source_file: 中华人民共和国医疗器械注册证(体外诊断试剂)(格式).docx + output_label: 注册证格式 + applies_when: + registration_type: ["首次注册"] + file_format: docx + fields: + - key: applicant_name + label: 注册人名称 + target: + type: table_row + row_label: 注册人名称 + source_roles: ["申请表", "说明书", "企业信息"] + - key: product_name + label: 产品名称 + target: + type: table_row + row_label: 产品名称 + source_roles: ["说明书", "产品技术要求", "注册检验报告"] + - key: intended_use + label: 预期用途 + target: + type: table_row + row_label: 预期用途 + source_roles: ["说明书", "临床评价资料", "产品技术要求"] +``` + +### 7.3 配置校验 + +`TemplateConfigService` 启动时校验: + +| 校验项 | 失败处理 | +| --- | --- | +| version 存在 | 批次 failed | +| source_dir 存在 | 批次 failed | +| templates 非空 | 批次 failed | +| code 唯一 | 批次 failed | +| source_file 存在 | 对应模板不可用 | +| target.type 支持 | 对应字段跳过并记录 | + +--- + +## 八、服务详细设计 + +### 8.1 TemplateConfigService + +```python +def load_template_config() -> dict: + """读取 YAML 模板配置。""" + +def validate_template_config(config: dict) -> list[str]: + """返回配置错误列表。""" + +def compute_config_hash(path: Path) -> str: + """计算模板配置 SHA-256。""" +``` + +### 8.2 TemplateSelectionService + +```python +def parse_requested_templates(message: str) -> list[str]: + """从用户话语中识别指定模板。""" + +def detect_registration_type(batch: ApplicationFormFillBatch, message: str) -> tuple[str, str]: + """按用户话语、法规核查批次、文件抽取结果识别注册类型及来源。""" + +def select_templates( + config: dict, + requested_templates: list[str], + registration_type: str, +) -> tuple[list[TemplateSpec], list[dict]]: + """输出模板列表和风险提示。""" +``` + +注册类型优先级: + +```text +用户话语明确指定 +-> source_regulatory_batch.condition_json / confirmed_conditions +-> source_summary_batch 文件内容抽取候选 +-> unknown +``` + +### 8.3 TemplateRepository + +```python +def resolve_source_template(spec: TemplateSpec) -> Path: + """返回原始模板路径或预转换工作模板路径。""" + +def copy_template_to_batch(spec: TemplateSpec, batch: ApplicationFormFillBatch) -> Path: + """复制模板到批次 work_dir/templates。""" + +def convert_doc_to_docx(source: Path, target_dir: Path) -> Path: + """P1 能力:使用 soffice 转 docx。""" +``` + +`.doc` 模板本期处理: + +| 场景 | 处理 | +| --- | --- | +| 存在 working_template docx | 使用工作模板 | +| 仅有 `.doc` 且无 soffice | 对应模板失败,其他模板继续 | +| 具备 soffice | 转换为 `.docx` 后继续 | + +### 8.4 FieldExtractionService + +```python +def collect_document_texts(summary_batch: FileSummaryBatch) -> dict[str, str]: + """复用 text_extract 读取文件文本。""" + +def extract_by_rules(texts: dict[str, str], specs: list[TemplateSpec]) -> dict: + """规则/正则抽取字段。""" + +def extract_by_llm(texts: dict[str, str], specs: list[TemplateSpec]) -> dict: + """LLM 结构化抽取字段。""" + +def run_parallel_extract(texts: dict[str, str], specs: list[TemplateSpec]) -> tuple[dict, dict]: + """并行执行规则/正则与 LLM 抽取。""" +``` + +并行实现可使用 `ThreadPoolExecutor(max_workers=2)`。LLM 超时或失败时,保留规则/正则结果继续。 + +### 8.5 FieldMergeService + +```python +def normalize_field_value(value: str) -> str: + """字段值归一化。""" + +def rank_source(source_role: str, source_file: str) -> int: + """说明书优先,其次产品技术要求、检测报告、性能研究等。""" + +def merge_fields(regex_results: dict, llm_results: dict) -> tuple[dict[str, MergedField], list[dict]]: + """合并字段并输出冲突。""" +``` + +来源优先级: + +| 排名 | 来源 | +| --- | --- | +| 1 | 说明书 | +| 2 | 产品技术要求 | +| 3 | 注册检验报告/检测报告 | +| 4 | 性能研究资料 | +| 5 | 其他注册资料 | + +### 8.6 WordTemplateFillService + +```python +def fill_template( + template_path: Path, + output_path: Path, + spec: TemplateSpec, + fields: dict[str, MergedField], + checklist_items: dict[str, Any], +) -> Path: + """填充 Word 模板并保存。""" + +def fill_table_row(document: Document, row_label: str, value: str, conflict: bool) -> bool: + """根据表格行首字段名定位并填入第二列。""" + +def replace_placeholders(document: Document, fields: dict[str, MergedField]) -> None: + """替换段落中的 {{field_key}}。""" + +def apply_conflict_style(cell_or_run) -> None: + """应用黄色底色和红色字体。""" +``` + +冲突样式: + +| 样式 | 说明 | +| --- | --- | +| 字体颜色 | 红色 `FF0000` | +| 底色 | 黄色 `FFFF00` | +| 适用范围 | 单元格或字段值 run | + +### 8.7 TraceabilityExportService + +```python +def build_traceability_workbook(batch, merged_fields, conflicts, specs) -> Workbook: + """生成追溯清单 Excel。""" + +def save_traceability_excel(batch, workbook) -> ExportedSummaryFile: + """保存 Excel 并写导出记录。""" + +def save_extract_json(batch, payload: dict) -> ApplicationFormFillArtifact: + """保存字段抽取 JSON 过程产物。""" +``` + +Excel Sheet: + +| Sheet | 内容 | +| --- | --- | +| 字段追溯 | 模板、字段、填入值、来源文件、证据、冲突状态 | +| 冲突字段 | 字段、采用值、冲突值、处理方式 | +| 低置信度条目 | 安全和性能基本原则清单候选判断 | +| 生成结果 | 模板文件、Word 状态、PDF 状态、错误说明 | + +### 8.8 FormFillNotifier + +```python +def notify_completion(batch: ApplicationFormFillBatch, exports: list[ExportedSummaryFile]) -> ApplicationFormFillNotificationRecord: + """发送填表完成通知。""" +``` + +通知摘要包含: + +| 内容 | 说明 | +| --- | --- | +| 批次号 | 填表批次 | +| 产品名称 | 如已识别 | +| 生成模板 | 模板名称列表 | +| 冲突数量 | 提示需下载核对 | +| 下载提示 | 提示回到系统对话下载,不直接暴露敏感全文 | + +--- + +## 九、工作流执行器详细设计 + +### 9.1 启动入口 + +```python +def start_application_form_fill_workflow(batch: ApplicationFormFillBatch, *, async_run: bool = True) -> None: + executor = FormFillWorkflowExecutor(batch) + if async_run: + Thread(target=executor.run, daemon=True).start() + else: + executor.run() +``` + +### 9.2 执行伪代码 + +```python +class FormFillWorkflowExecutor: + def run(self) -> None: + self.mark_batch_running() + try: + for node in self.nodes(): + if node.status == "success": + continue + self.run_node(node) + self.complete_or_partial() + except WorkflowPausedForUser: + self.mark_waiting_user() + except Exception as exc: + self.mark_failed(exc) +``` + +### 9.3 节点处理要点 + +| 节点 | 处理 | +| --- | --- | +| prepare | 校验 `source_summary_batch` 成功且属于当前对话 | +| template_select | 读取 YAML、识别注册类型、选择模板 | +| template_copy | 复制模板到 `work_dir/templates` | +| field_extract | 抽取文本,规则/正则与 LLM 并行,保存 JSON | +| conflict_merge | 合并字段,写 `conflict_summary` | +| word_fill | 逐模板生成 Word,写 `ExportedSummaryFile(word)` | +| pdf_convert | 本期 skipped,写 `risk_notes` | +| trace_export | 生成追溯 Excel 和 JSON | +| output_export | 生成 AI 对话 Markdown 摘要 | +| notify | 写飞书通知记录,失败不阻断 | +| completed | 标记 success 或 partial_success | + +### 9.4 批次状态决策 + +| 条件 | 状态 | +| --- | --- | +| 所有目标 Word 均成功,追溯清单成功,通知成功或跳过 | success | +| 至少一个 Word 成功,但部分模板、追溯清单、PDF 或通知失败 | partial_success | +| 所有目标 Word 均失败 | failed | +| 无来源文件汇总批次 | waiting_user | + +--- + +## 十、接口详细设计 + +### 10.1 发起自动填表 + +```text +POST /api/review-agent/application-form-fill/start/ +``` + +请求: + +| 参数 | 类型 | 必填 | 说明 | +| --- | --- | --- | --- | +| conversation_id | integer | 是 | 当前对话 | +| message_id | integer | 否 | 触发消息 | +| file_summary_batch_id | integer | 否 | 指定文件来源批次 | +| template_codes | array | 否 | 指定模板 | +| output_types | array | 否 | 输出类型,默认 word、excel、json | + +响应: + +```json +{ + "batch_id": 3001, + "workflow_type": "application_form_fill", + "status": "pending", + "selected_templates": ["registration_certificate", "essential_principles"] +} +``` + +### 10.2 查询状态 + +```text +GET /api/review-agent/application-form-fill/{batch_id}/ +``` + +响应: + +```json +{ + "batch": { + "id": 3001, + "batch_no": "AFF-20260607153000-a1b2c3", + "status": "success", + "product_name": "甲胎蛋白检测试剂盒", + "selected_templates": ["registration_certificate"] + }, + "nodes": [], + "conflicts": [], + "exports": [] +} +``` + +### 10.3 下载文件 + +继续复用既有导出下载接口: + +```text +GET /api/review-agent/file-summary/exports/{export_id}/download/ +``` + +下载权限通过 `workflow_type=application_form_fill` 和 `workflow_batch_id` 反查填表批次。 + +--- + +## 十一、前端详细设计 + +### 11.1 工作流卡片 + +新增卡片类型 `application_form_fill`。 + +| 节点 | 展示 | +| --- | --- | +| prepare | 准备资料 | +| template_select | 选择模板 | +| template_copy | 复制模板 | +| field_extract | 抽取字段 | +| conflict_merge | 冲突归并 | +| word_fill | 填写 Word | +| pdf_convert | 转换 PDF | +| trace_export | 追溯清单 | +| output_export | 输出下载 | +| notify | 飞书通知 | +| completed | 已完成 | + +PDF 本期显示为“已跳过/待增强”,不显示为失败。 + +### 11.2 AI 回复摘要 + +```markdown +已生成申报模板自动填表文件。 + +| 文件 | Word | PDF | +| --- | --- | --- | +| 注册证格式 | 下载 | 待增强 | +| 安全和性能基本原则清单 | 下载 | 待增强 | + +| 冲突字段 | 采用值 | 冲突来源 | 处理 | +| --- | --- | --- | --- | +| 储存条件 | 2-8℃保存 | 产品技术要求:-20℃保存 | 已按说明书填入,并在模板中高亮 | + +[下载字段来源追溯清单](download-url) +``` + +--- + +## 十二、异常与降级 + +| 场景 | 处理 | +| --- | --- | +| 无成功汇总批次 | 批次 waiting_user,对话提示上传资料 | +| 模板配置不存在 | 批次 failed | +| 指定模板不存在 | 忽略无效模板并提示;若无有效模板则 failed | +| `.doc` 模板无可用工作模板 | 该模板失败,其他模板继续 | +| 文本抽取失败 | 对应文件跳过,记录在追溯清单 | +| LLM 抽取失败 | 使用规则/正则结果继续 | +| 字段缺失 | Word 留空 | +| 字段冲突 | 说明书优先并高亮 | +| 追溯清单失败 | Word 成功时批次 partial_success | +| 飞书通知失败 | 批次 partial_success 或 success,取决于核心产物是否成功 | +| PDF 未实现 | 节点 skipped,写入待增强提示 | + +--- + +## 十三、测试设计 + +### 13.1 单元测试 + +| 用例 | 目标 | +| --- | --- | +| test_form_fill_trigger_keywords | 触发语句识别为自动填表 | +| test_template_config_loads | YAML 配置可加载并校验 | +| test_select_default_templates_initial_registration | 首次注册默认选择注册证和基本原则清单 | +| test_select_user_requested_mismatch | 用户指定不适用模板仍允许生成并提示 | +| test_field_merge_prefers_instructions | 说明书字段优先 | +| test_field_merge_marks_conflict | 冲突字段进入 conflict_summary | +| test_word_fill_table_row | 能按表格行名写入 Word | +| test_word_fill_conflict_highlight | 冲突字段黄底红字 | +| test_traceability_excel | 追溯清单包含字段、来源和冲突 | +| test_notify_records_failure | 飞书失败写通知记录但不阻断 | + +### 13.2 集成测试 + +| 场景 | 验证 | +| --- | --- | +| 最近汇总批次触发填表 | 无附件时复用最近 success `FileSummaryBatch` | +| 新附件触发填表 | 先自动汇总再启动填表 | +| 注册证模板填充 | 生成 Word 导出文件 | +| LLM 失败降级 | LLM 超时后规则抽取仍可生成 Word | +| 部分模板失败 | 至少一个 Word 成功时批次 partial_success | +| 权限隔离 | 不能查询或下载他人填表批次产物 | + +### 13.3 前端验证 + +| 场景 | 验证 | +| --- | --- | +| 自动填表卡片 | 节点状态随 SSE 更新 | +| 指定模板展示 | 卡片展示本次选择模板 | +| PDF 跳过显示 | PDF 节点显示待增强而非失败 | +| 下载链接 | Word 和追溯清单链接可点击下载 | +| 冲突摘要 | 冲突字段表格正常渲染 | + +--- + +## 十四、实施顺序建议 + +1. 修改功能设计中的模板配置路径为 `review_agent/application_form_fill/templates/application_form_templates_v1.yaml`。 +2. 新增数据库模型和 `ExportedSummaryFile.ExportType` 扩展。 +3. 新增 `application_form_fill` 模块目录和常量、schemas、storage。 +4. 新增模板配置 YAML,先录入注册证 `.docx` 的已识别字段。 +5. 实现模板选择、模板复制和 Word 表格行填充。 +6. 实现规则/正则字段抽取和 LLM 抽取降级。 +7. 实现字段合并、冲突高亮和追溯清单。 +8. 实现工作流执行器、节点事件和状态接口。 +9. 改造路由和前端工作流卡片。 +10. 接入飞书通知记录。 +11. 将字段级数据库表和 PDF 转换写入待办计划。 diff --git a/docs/4.数据库设计/3.产品关键信息提取与申报文件自动填表.md b/docs/4.数据库设计/3.产品关键信息提取与申报文件自动填表.md new file mode 100644 index 0000000..f13e417 --- /dev/null +++ b/docs/4.数据库设计/3.产品关键信息提取与申报文件自动填表.md @@ -0,0 +1,433 @@ +# 产品关键信息提取与申报文件自动填表数据库设计 + +## 文档信息 + +| 项目 | 内容 | +| --- | --- | +| 需求分析文档 | docs/1.需求分析/3.产品关键信息提取与申报文件自动填表.md | +| 功能设计文档 | docs/2.功能设计/3.产品关键信息提取与申报文件自动填表.md | +| 数据库类型 | SQLite / Django ORM | +| 表名前缀 | ra_ | +| 设计日期 | 2026-06-07 | +| 设计版本 | V1.0 | + +--- + +## 一、设计原则 + +| 原则 | 说明 | +| --- | --- | +| 独立填表批次 | 自动填表作为独立工作流,使用独立批次表,不强绑法规核查批次 | +| 复用文件来源 | 填表批次必须关联一个成功的 `FileSummaryBatch`,不重复保存文件清单 | +| 可选复用法规条件 | 如当前对话已有已确认法规核查批次,可通过可空外键复用注册类型等条件 | +| 导出记录复用 | Word、Excel、JSON、PDF 等下载文件继续进入 `ExportedSummaryFile` | +| 过程产物独立 | 自动填表过程产物单独建表,避免和法规核查 `RegulatoryArtifact` 混用 | +| 通知记录独立 | 自动填表飞书通知单独建表,字段风格与法规通知记录保持一致 | +| 大文本不入库 | 字段抽取 JSON、追溯清单和模板副本保存为文件,数据库仅保存路径、hash 和摘要 | +| 字段明细暂不入库 | 本期不新增字段级明细表;字段结果保存在 JSON/Excel 产物与批次摘要中 | +| SQLite 兼容 | 字段类型、索引和约束优先保证当前 SQLite + Django ORM 可运行 | + +--- + +## 二、ER 图 + +```mermaid +erDiagram + AUTH_USER ||--o{ CONVERSATION : owns + CONVERSATION ||--o{ RA_FILE_SUMMARY_BATCH : has + RA_FILE_SUMMARY_BATCH ||--o{ RA_FILE_SUMMARY_ITEM : produces + RA_FILE_SUMMARY_BATCH ||--o{ RA_APPLICATION_FORM_FILL_BATCH : feeds + RA_REGULATORY_REVIEW_BATCH ||--o{ RA_APPLICATION_FORM_FILL_BATCH : optionally_confirms + AUTH_USER ||--o{ RA_APPLICATION_FORM_FILL_BATCH : runs + CONVERSATION ||--o{ RA_APPLICATION_FORM_FILL_BATCH : has + MESSAGE ||--o{ RA_APPLICATION_FORM_FILL_BATCH : triggers + RA_APPLICATION_FORM_FILL_BATCH ||--o{ RA_APPLICATION_FORM_FILL_ARTIFACT : keeps + RA_APPLICATION_FORM_FILL_BATCH ||--o{ RA_APPLICATION_FORM_FILL_NOTIFICATION_RECORD : sends + RA_APPLICATION_FORM_FILL_BATCH ||--o{ RA_EXPORTED_SUMMARY_FILE : exports + RA_APPLICATION_FORM_FILL_BATCH ||--o{ RA_WORKFLOW_NODE_RUN : tracks + RA_APPLICATION_FORM_FILL_BATCH ||--o{ RA_WORKFLOW_EVENT : emits +``` + +说明:`ra_workflow_node_run`、`ra_workflow_event`、`ra_exported_summary_file` 已在第二批中被通用化,通过 `workflow_type` 与 `workflow_batch_id` 支持多工作流。本功能使用 `workflow_type=application_form_fill`。 + +--- + +## 三、表结构设计 + +### 3.1 ra_application_form_fill_batch + +一次自动填表工作流批次。该表记录本次触发来源、选择模板、输出类型、注册类型、产品名称、冲突摘要、工作目录和状态。 + +| 字段名 | Django 类型 | SQLite 类型 | 必填 | 说明 | +| --- | --- | --- | --- | --- | +| id | BigAutoField | integer | 是 | 主键 | +| conversation_id | ForeignKey | bigint | 是 | 绑定对话 | +| user_id | ForeignKey | bigint | 是 | 发起用户 | +| trigger_message_id | ForeignKey | bigint | 否 | 触发填表工作流的用户消息 | +| source_summary_batch_id | ForeignKey | bigint | 是 | 文件来源汇总批次 | +| source_regulatory_batch_id | ForeignKey | bigint | 否 | 可选,复用已确认法规核查批次条件 | +| batch_no | CharField(64) | varchar(64) | 是 | 填表批次编号,唯一 | +| status | CharField(30) | varchar(30) | 是 | pending、running、waiting_user、success、partial_success、failed、cancelled | +| requested_templates | JSONField | text/json | 是 | 用户指定模板编码列表;未指定为空数组 | +| selected_templates | JSONField | text/json | 是 | 系统实际选择模板编码列表 | +| output_types | JSONField | text/json | 是 | 请求输出类型,如 word、excel、json、pdf | +| registration_type | CharField(80) | varchar(80) | 否 | 识别出的注册类型 | +| registration_type_source | CharField(40) | varchar(40) | 否 | user_message、regulatory_batch、file_extract、unknown | +| product_name | CharField(200) | varchar(200) | 否 | 产品名称 | +| conflict_summary | JSONField | text/json | 是 | 冲突字段摘要 | +| risk_notes | JSONField | text/json | 是 | 不适用模板、低置信度、PDF 待生成等提示 | +| template_config_version | CharField(80) | varchar(80) | 否 | 模板配置版本 | +| template_config_hash | CharField(128) | varchar(128) | 否 | 模板配置文件 hash | +| work_dir | CharField(500) | varchar(500) | 否 | 批次工作目录 | +| error_message | TextField | text | 否 | 批次异常说明 | +| created_at | DateTimeField | datetime | 是 | 创建时间 | +| started_at | DateTimeField | datetime | 否 | 开始时间 | +| finished_at | DateTimeField | datetime | 否 | 完成时间 | +| archived_at | DateTimeField | datetime | 否 | 归档时间 | +| is_deleted | BooleanField | bool | 是 | 软删除标记 | + +唯一约束: + +| 约束名 | 字段 | +| --- | --- | +| uq_ra_aff_batch_no | batch_no | + +索引: + +| 索引名 | 字段 | 说明 | +| --- | --- | --- | +| idx_ra_aff_batch_conv_status | conversation_id, status | 查询对话下填表批次状态 | +| idx_ra_aff_batch_summary | source_summary_batch_id | 根据文件汇总批次查询填表历史 | +| idx_ra_aff_batch_regulatory | source_regulatory_batch_id | 根据法规核查批次查询关联填表历史 | +| idx_ra_aff_batch_user_created | user_id, created_at | 查询用户发起记录 | +| idx_ra_aff_batch_created | created_at | 按创建时间查询 | + +--- + +### 3.2 ra_application_form_fill_artifact + +自动填表过程产物表。仅保存文件元数据,不保存字段抽取大 JSON 的全文。 + +| 字段名 | Django 类型 | SQLite 类型 | 必填 | 说明 | +| --- | --- | --- | --- | --- | +| id | BigAutoField | integer | 是 | 主键 | +| batch_id | ForeignKey | bigint | 是 | 所属自动填表批次 | +| artifact_type | CharField(60) | varchar(60) | 是 | template_copy、field_extract_result、merged_fields、traceability、filled_template、notification_record | +| file_format | CharField(20) | varchar(20) | 是 | json、excel、docx、pdf、markdown | +| name | CharField(160) | varchar(160) | 是 | 产物名称 | +| file_name | CharField(255) | varchar(255) | 是 | 文件名 | +| storage_path | CharField(500) | varchar(500) | 是 | 存储路径 | +| file_size | BigIntegerField | bigint | 是 | 文件大小 | +| content_hash | CharField(128) | varchar(128) | 是 | 文件 SHA-256 hash | +| metadata | JSONField | text/json | 是 | 模板编码、输出类型、生成状态、错误摘要等 | +| created_by_node | CharField(60) | varchar(60) | 否 | 产生该产物的节点 | +| created_at | DateTimeField | datetime | 是 | 创建时间 | +| is_deleted | BooleanField | bool | 是 | 软删除标记 | + +索引: + +| 索引名 | 字段 | 说明 | +| --- | --- | --- | +| idx_ra_aff_artifact_batch_type | batch_id, artifact_type | 查询批次过程产物 | +| idx_ra_aff_artifact_format | file_format | 按文件格式查询 | +| idx_ra_aff_artifact_created | created_at | 按时间追溯 | + +--- + +### 3.3 ra_application_form_fill_notification_record + +自动填表飞书通知记录表。通知失败不阻断文件下载,但需要留痕和支持后续重试。 + +| 字段名 | Django 类型 | SQLite 类型 | 必填 | 说明 | +| --- | --- | --- | --- | --- | +| id | BigAutoField | integer | 是 | 主键 | +| batch_id | ForeignKey | bigint | 是 | 所属自动填表批次 | +| recipient_id | ForeignKey(User) | bigint | 是 | 通知对象,默认上传人/发起人 | +| channel | CharField(30) | varchar(30) | 是 | feishu_cli、feishu_api、mock | +| template_codes | JSONField | text/json | 是 | 本次通知涉及模板 | +| export_ids | JSONField | text/json | 是 | 本次通知关联导出文件 ID | +| message_summary | TextField | text | 是 | 通知摘要 | +| send_status | CharField(20) | varchar(20) | 是 | pending、success、failed | +| retry_count | PositiveIntegerField | integer | 是 | 已重试次数 | +| external_message_id | CharField(120) | varchar(120) | 否 | 飞书外部消息 ID | +| error_message | TextField | text | 否 | 失败原因 | +| sent_at | DateTimeField | datetime | 否 | 发送成功时间 | +| created_at | DateTimeField | datetime | 是 | 创建时间 | +| updated_at | DateTimeField | datetime | 是 | 更新时间 | +| is_deleted | BooleanField | bool | 是 | 软删除标记 | + +索引: + +| 索引名 | 字段 | 说明 | +| --- | --- | --- | +| idx_ra_aff_notify_batch | batch_id, created_at | 查询批次通知记录 | +| idx_ra_aff_notify_recipient | recipient_id, send_status | 查询用户通知状态 | +| idx_ra_aff_notify_status | send_status, retry_count | 查询待重试通知 | + +--- + +## 四、既有表扩展 + +### 4.1 ra_exported_summary_file + +继续复用导出文件表,需扩展导出类型。 + +| 字段/枚举 | 处理 | +| --- | --- | +| export_type | 增加 `word`、`pdf` | +| workflow_type | 使用 `application_form_fill` | +| workflow_batch_id | 记录 `ApplicationFormFillBatch.id` | +| export_category | 使用 `filled_template`、`traceability`、`extract_result` | + +导出类型枚举: + +| value | 中文展示 | 说明 | +| --- | --- | --- | +| markdown | Markdown | 既有报告 | +| excel | Excel | 追溯清单 | +| json | JSON | 字段抽取结果包 | +| word | Word | 填好的 Word 模板 | +| pdf | PDF | Word 转换后的 PDF,P1 预留 | + +### 4.2 ra_workflow_node_run + +本功能使用通用工作流字段: + +| 字段 | 值 | +| --- | --- | +| workflow_type | application_form_fill | +| workflow_batch_id | ApplicationFormFillBatch.id | +| node_group | form_fill | +| batch_id | 可为空或兼容性填充 source_summary_batch_id | + +### 4.3 ra_workflow_event + +本功能事件写入: + +| 字段 | 值 | +| --- | --- | +| workflow_type | application_form_fill | +| workflow_batch_id | ApplicationFormFillBatch.id | +| conversation_id | 当前对话 ID | +| payload | 节点状态、模板列表、冲突数量、导出文件等 | + +--- + +## 五、枚举设计 + +### 5.1 ApplicationFormFillBatch.status + +| value | 中文展示 | 说明 | +| --- | --- | --- | +| pending | 待执行 | 批次已创建,等待执行 | +| running | 执行中 | 工作流正在执行 | +| waiting_user | 等待用户 | 缺少文件汇总批次或关键条件 | +| success | 成功 | Word 和必要追溯产物生成成功 | +| partial_success | 部分成功 | 部分模板、PDF、追溯清单或通知失败 | +| failed | 失败 | 所有目标 Word 模板均生成失败 | +| cancelled | 已取消 | 用户或系统取消执行 | + +### 5.2 artifact_type + +| value | 说明 | +| --- | --- | +| template_copy | 模板副本 | +| field_extract_result | 规则/正则与 LLM 抽取原始结果 | +| merged_fields | 合并后的最终字段和冲突 | +| traceability | 字段来源追溯清单 | +| filled_template | 已填写模板 | +| notification_record | 通知记录产物 | + +### 5.3 registration_type_source + +| value | 说明 | +| --- | --- | +| user_message | 用户话语明确指定 | +| regulatory_batch | 复用已确认法规核查条件 | +| file_extract | 从文件内容抽取 | +| unknown | 未识别 | + +### 5.4 通知枚举 + +| 字段 | value | +| --- | --- | +| channel | feishu_cli、feishu_api、mock | +| send_status | pending、success、failed | + +--- + +## 六、JSON 字段结构建议 + +### 6.1 requested_templates / selected_templates + +```json +["registration_certificate", "essential_principles"] +``` + +### 6.2 output_types + +```json +["word", "excel", "json"] +``` + +PDF 作为 P1 预留,可在后续加入: + +```json +["word", "pdf", "excel", "json"] +``` + +### 6.3 conflict_summary + +```json +[ + { + "field_key": "storage_condition", + "field_label": "产品储存条件及有效期", + "selected_value": "2-8℃保存,有效期12个月", + "selected_source": "说明书.docx", + "conflict_values": [ + { + "value": "-20℃保存", + "source_file": "产品技术要求.docx", + "evidence": "储存条件:-20℃保存" + } + ], + "handling": "说明书优先,模板内黄底红字高亮" + } +] +``` + +### 6.4 risk_notes + +```json +[ + { + "type": "template_registration_mismatch", + "message": "用户指定变更注册(备案)文件,但系统识别注册类型为首次注册,需人工确认。" + }, + { + "type": "pdf_pending", + "message": "PDF 转换为后续增强项,本次优先生成 Word。" + } +] +``` + +### 6.5 artifact.metadata + +```json +{ + "template_code": "registration_certificate", + "output_type": "word", + "node_code": "word_fill", + "status": "success", + "conflict_count": 2 +} +``` + +--- + +## 七、存储路径设计 + +自动填表工作目录按用户、对话和批次隔离: + +```text +media/application_form_fill/{user_id}/{conversation_id}/{batch_no}/ +``` + +目录结构: + +```text +media/application_form_fill/12/1001/AFF-20260607153000-a1b2c3/ + templates/ + registration_certificate.source.docx + essential_principles.source.docx + filled/ + AFF-20260607153000-a1b2c3-甲胎蛋白检测试剂盒-注册证格式.docx + exports/ + AFF-20260607153000-a1b2c3-甲胎蛋白检测试剂盒-字段来源追溯清单.xlsx + field_extract_result.json + merged_fields.json + notifications/ + notification_record.json +``` + +所有产物写入 `ApplicationFormFillArtifact` 时必须记录 SHA-256 hash。 + +--- + +## 八、权限与查询规则 + +### 8.1 批次访问权限 + +```text +ApplicationFormFillBatch -> conversation -> user +必须等于当前 request.user +``` + +### 8.2 导出下载权限 + +```text +ExportedSummaryFile.workflow_type == application_form_fill +-> workflow_batch_id +-> ApplicationFormFillBatch.conversation.user +``` + +若 `workflow_type=file_summary` 或 `regulatory_review`,仍按既有逻辑校验。 + +### 8.3 文件读取权限 + +自动填表只能读取 `source_summary_batch.items` 对应的文件,不允许从其他对话或其他批次随意读取文件。 + +--- + +## 九、字段级数据库表暂缓说明 + +本期不新增 `ApplicationFormFillField` 字段级明细表。原因: + +| 原因 | 说明 | +| --- | --- | +| Demo 主链路更轻 | 字段结果以 JSON 和 Excel 追溯清单即可满足下载复核 | +| 避免过早建模 | 字段结构依赖模板配置和后续人工修改交互,暂不固化表结构 | +| 查询需求有限 | 本期主要按批次下载文件,不做字段级统计和在线编辑 | + +后续如需要在线确认、人工修改、字段级审计或批量统计,再新增字段级表。该事项写入 `docs/6.待办计划/第二阶段暂缓事项.md`。 + +--- + +## 十、Django Model 命名建议 + +| 表名 | Model 名称 | +| --- | --- | +| ra_application_form_fill_batch | ApplicationFormFillBatch | +| ra_application_form_fill_artifact | ApplicationFormFillArtifact | +| ra_application_form_fill_notification_record | ApplicationFormFillNotificationRecord | + +建议模型仍集中放在 `review_agent/models.py`,与前两批现有模型保持一致;业务逻辑放在 `review_agent/application_form_fill/`。 + +--- + +## 十一、验收检查点 + +| 序号 | 检查项 | 验收标准 | +| --- | --- | --- | +| 1 | 独立批次 | 触发填表后生成 `ApplicationFormFillBatch` | +| 2 | 文件来源 | 每个填表批次都关联一个成功的 `FileSummaryBatch` | +| 3 | 可选法规条件 | 如有关联法规核查批次,可记录 `source_regulatory_batch` | +| 4 | 过程产物 | 字段抽取 JSON、合并结果、追溯清单、模板副本均可留底 | +| 5 | 导出复用 | 填好的 Word 和追溯清单进入 `ExportedSummaryFile` | +| 6 | 导出类型 | `ExportedSummaryFile.ExportType` 支持 `word`、`pdf` | +| 7 | 通知记录 | 飞书通知记录能保存状态、重试次数、失败原因 | +| 8 | 权限隔离 | A 对话的填表批次和导出文件不能被 B 对话访问 | +| 9 | 字段表暂缓 | 字段级结果不入库,但能从 JSON/Excel 追溯产物复核 | + +--- + +## 十二、开发顺序建议 + +1. 扩展 `ExportedSummaryFile.ExportType`,增加 `word`、`pdf`。 +2. 新增 `ApplicationFormFillBatch`、`ApplicationFormFillArtifact`、`ApplicationFormFillNotificationRecord`。 +3. 为新增状态字段定义 Django `TextChoices`。 +4. 配置表名、索引和唯一约束。 +5. 执行 `python manage.py makemigrations review_agent` 和 `python manage.py migrate`。 +6. 编写模型测试,覆盖批次创建、产物 hash、通知重试字段、导出权限查询。 +7. 将字段级数据库表和 PDF 转换能力写入待办计划。 diff --git a/docs/5.开发计划/3.产品关键信息提取与申报文件自动填表.md b/docs/5.开发计划/3.产品关键信息提取与申报文件自动填表.md new file mode 100644 index 0000000..0dc6b5e --- /dev/null +++ b/docs/5.开发计划/3.产品关键信息提取与申报文件自动填表.md @@ -0,0 +1,632 @@ +# 产品关键信息提取与申报文件自动填表开发计划 + +## 文档信息 + +| 项目 | 内容 | +| --- | --- | +| 需求分析文档 | docs/1.需求分析/3.产品关键信息提取与申报文件自动填表.md | +| 功能设计文档 | docs/2.功能设计/3.产品关键信息提取与申报文件自动填表.md | +| 详细设计文档 | docs/3.详细设计/3.产品关键信息提取与申报文件自动填表.md | +| 数据库设计文档 | docs/4.数据库设计/3.产品关键信息提取与申报文件自动填表.md | +| 功能名称 | 产品关键信息提取与申报文件自动填表 | +| 所属模块 | 审核智能体 review_agent | +| 执行方式 | 单人开发 + Codex 目标模式自动化执行 | +| 计划日期 | 2026-06-07 | +| 计划版本 | V1.0 | + +--- + +## 一、开发计划目标 + +本开发计划用于指导 Codex 目标模式按阶段完成“产品关键信息提取与申报文件自动填表”功能开发。该功能作为独立工作流 `application_form_fill` 实现,由用户对话触发,默认复用当前对话最近成功的文件汇总批次;如本次消息带新附件,则先串联文件汇总,再执行自动填表。 + +本期必须完成:独立填表批次、过程产物、飞书通知记录、模板配置、注册证 `.docx` 模板填充、字段抽取与合并、冲突高亮、追溯清单、Word 下载、自动填表工作流卡片和权限校验。 + +本期明确不强制完成:PDF 转换、字段级数据库表、`.doc` 模板自动转换、完整安全和性能基本原则清单条目拆解。这些事项已进入 `docs/6.待办计划/第二阶段暂缓事项.md`。 + +--- + +## 二、已确认开发规则 + +| 规则项 | 内容 | +| --- | --- | +| 工作流类型 | 新增独立 `application_form_fill`,不塞入 `regulatory_review` 工作流 | +| 触发方式 | 用户对话触发,如“帮我填注册证”“给我这个内容对应的表格”“为我该方案生成申报模板” | +| 模板指定 | 用户可指定模板;未指定时按注册类型生成适用模板 | +| 文件来源 | 无新附件时复用当前对话最近成功 `FileSummaryBatch`;有新附件时先自动汇总 | +| 模板配置 | 放在 `review_agent/application_form_fill/templates/application_form_templates_v1.yaml` | +| 字段抽取 | 规则/正则与 LLM 结构化抽取并行,合并处理 | +| 冲突处理 | 说明书优先;冲突字段在 Word 中黄色底色、红色字体 | +| 输出范围 | Demo 主链路优先 Word + Excel/JSON 追溯清单 | +| PDF | 数据结构预留,工作流节点可 skipped,不作为本期强验收 | +| 飞书 | 新增自动填表通知记录表,通知失败不阻断下载 | +| 数据库 | 新增三张表;字段级明细表暂缓 | +| Git 提交 | 每个阶段完成并验证通过后提交一次 | +| 测试要求 | 每阶段至少运行对应 pytest;前端阶段补卡片和渲染测试 | + +--- + +## 三、总体验收标准 + +| 类别 | 完成标准 | +| --- | --- | +| 数据库 | `ApplicationFormFillBatch`、`ApplicationFormFillArtifact`、`ApplicationFormFillNotificationRecord` 可通过 migration 落库 | +| 导出类型 | `ExportedSummaryFile.ExportType` 支持 `word`、`pdf`,并兼容既有 markdown/excel/json | +| 模块结构 | 新增 `review_agent/application_form_fill/` 独立模块 | +| 触发 | 用户说“帮我填注册证”等语句可触发 `application_form_fill` | +| 文件来源 | 无新附件时复用最近成功汇总批次;无汇总批次时提示上传资料 | +| 模板配置 | YAML 可加载、校验,并至少配置注册证格式 `.docx` 已识别字段 | +| 字段抽取 | 规则/正则与 LLM 抽取结果均可留底;LLM 失败时规则结果可继续 | +| 字段合并 | 说明书优先,冲突字段进入 `conflict_summary` 和追溯清单 | +| Word 填充 | 能按表格行名填入注册证模板字段,缺失字段留空 | +| 冲突高亮 | 冲突字段在 Word 内黄底红字 | +| 追溯清单 | 生成 Excel/JSON,记录规则结果、LLM 结果、合并字段、冲突和来源证据 | +| 下载 | 对话框提供填好 Word 和追溯清单下载链接 | +| 工作流卡片 | 前端支持 `application_form_fill` 卡片,展示准备资料、选择模板、复制模板、抽取字段、填写 Word 等节点 | +| 飞书通知 | 填表完成后写通知记录,可 mock;失败不阻断文件下载 | +| 权限 | A 对话不能查询或下载 B 对话的填表批次和导出文件 | +| 回归 | 第一批文件汇总、第二批法规核查既有测试不回归 | + +--- + +## 四、阶段总览 + +| 阶段 | 名称 | 目标 | 阶段验收 | +| --- | --- | --- | --- | +| AFF-0 | 准备与回归 | 创建开发分支,确认现有测试基线 | `python manage.py check` 和关键回归测试通过 | +| AFF-1 | 数据模型与通用导出扩展 | 新增三张表,扩展 word/pdf 导出类型 | migration、模型测试通过 | +| AFF-2 | 模块骨架与模板配置 | 新建独立模块、YAML 配置和配置校验 | 模板配置测试通过 | +| AFF-3 | 触发与工作流骨架 | 对话触发、批次创建、节点事件和状态查询 | 可创建并运行空工作流 | +| AFF-4 | 模板选择与文件来源 | 复用最近汇总批次,支持指定/默认模板选择 | 模板选择和来源批次测试通过 | +| AFF-5 | 字段抽取与合并 | 规则/正则 + LLM 并行抽取、冲突归并和产物留底 | 字段抽取、冲突测试通过 | +| AFF-6 | Word 填充与追溯导出 | 注册证 Word 填充、冲突高亮、Excel/JSON 追溯 | 可下载 Word 和追溯清单 | +| AFF-7 | 飞书通知与对话摘要 | 生成助手摘要、下载链接和通知记录 | 通知、摘要、下载权限测试通过 | +| AFF-8 | 前端卡片与总体验收 | 自动填表工作流卡片、状态恢复、全量回归 | 全量测试通过 | + +--- + +## 五、AFF-0 准备与回归 + +### AFF-0-001 创建开发分支并确认现状 + +| 项目 | 内容 | +| --- | --- | +| 任务类型 | Git / 准备 | +| 前置任务 | 无 | +| 涉及文件 | 无固定文件 | +| 目标 | 从当前稳定分支创建 `codex/YYYYMMDD-申报文件自动填表` 开发分支,并确认工作区状态 | +| 开发步骤 | 1. 检查当前分支和 `git status`;2. 确认第三批设计文档存在;3. 创建开发分支;4. 记录已有未提交变更,不得回滚用户变更 | +| 验收标准 | 分支创建成功,工作区变更来源清楚 | +| 验证命令 | `git branch --show-current`; `git status --short` | +| Codex 执行提示 | 请创建第三批自动填表开发分支,检查当前工作区状态和设计文档,不要回滚用户已有变更。 | + +### AFF-0-002 运行基线回归 + +| 项目 | 内容 | +| --- | --- | +| 任务类型 | 测试 / 回归 | +| 前置任务 | AFF-0-001 | +| 涉及文件 | 无固定文件 | +| 目标 | 确认现有文件汇总和法规核查主流程在开发前可用 | +| 开发步骤 | 1. 运行 Django check;2. 运行文件汇总测试;3. 运行法规核查测试;4. 记录失败项并先判断是否为既有问题 | +| 验收标准 | 关键回归测试通过,或记录清楚既有失败和本阶段处理策略 | +| 验证命令 | `python manage.py check`; `pytest tests/test_file_summary_*.py tests/test_regulatory_*.py` | +| Codex 执行提示 | 请在开发前运行 Django check 和文件汇总/法规核查关键测试,确认基线稳定。若存在既有失败,请记录,不要直接改无关代码。 | + +--- + +## 六、AFF-1 数据模型与通用导出扩展 + +### AFF-1-001 新增自动填表 ORM 模型 + +| 项目 | 内容 | +| --- | --- | +| 任务类型 | 数据库 / 后端 | +| 前置任务 | AFF-0 | +| 涉及文件 | `review_agent/models.py` | +| 目标 | 新增 `ApplicationFormFillBatch`、`ApplicationFormFillArtifact`、`ApplicationFormFillNotificationRecord` | +| 开发步骤 | 1. 定义批次状态枚举;2. 定义产物类型枚举;3. 定义通知状态和渠道枚举;4. 添加外键到 Conversation、User、Message、FileSummaryBatch、RegulatoryReviewBatch;5. 添加 JSONField、hash、路径、时间字段;6. 添加 `db_table`、索引和唯一约束 | +| 验收标准 | 模型字段、表名、索引与数据库设计一致 | +| 验证命令 | `python manage.py check` | +| Codex 执行提示 | 请按 `docs/4.数据库设计/3.产品关键信息提取与申报文件自动填表.md` 新增自动填表三张表模型,模型集中放在 `review_agent/models.py`。 | + +### AFF-1-002 扩展导出类型和权限查询能力 + +| 项目 | 内容 | +| --- | --- | +| 任务类型 | 数据库 / 下载 | +| 前置任务 | AFF-1-001 | +| 涉及文件 | `review_agent/models.py`、导出下载权限相关视图 | +| 目标 | 为 `ExportedSummaryFile.ExportType` 增加 `word`、`pdf`,并确保下载权限支持 `application_form_fill` | +| 开发步骤 | 1. 扩展 `ExportType.WORD`;2. 扩展 `ExportType.PDF`;3. 检查下载接口按 workflow_type 分派权限;4. 增加 application_form_fill 反查批次的权限路径 | +| 验收标准 | Word/ PDF 导出记录可创建;填表导出下载权限可追溯到当前用户 | +| 验证命令 | `python manage.py check`; `pytest tests/test_file_summary_views.py -k download` | +| Codex 执行提示 | 请扩展 ExportedSummaryFile 支持 word/pdf,并让现有下载接口能通过 workflow_type=application_form_fill 校验填表批次权限。 | + +### AFF-1-003 生成迁移并补模型测试 + +| 项目 | 内容 | +| --- | --- | +| 任务类型 | 数据库 / 测试 | +| 前置任务 | AFF-1-002 | +| 涉及文件 | `review_agent/migrations/`、`tests/test_application_form_fill_models.py` | +| 目标 | 生成迁移并覆盖新增表的基础约束和权限关系 | +| 开发步骤 | 1. 运行 makemigrations;2. 检查 migration 只包含第三批相关变更;3. 运行 migrate;4. 测试批次创建;5. 测试产物 hash 字段;6. 测试通知重试字段;7. 测试 ExportedSummaryFile word 类型 | +| 验收标准 | migration 可执行,模型测试通过 | +| 验证命令 | `python manage.py makemigrations review_agent`; `python manage.py migrate`; `pytest tests/test_application_form_fill_models.py` | +| Codex 执行提示 | 请为第三批模型生成迁移并新增模型测试,覆盖批次、产物、通知记录和 word/pdf 导出类型。 | + +### AFF-1 阶段验证 + +```bash +python manage.py check +pytest tests/test_application_form_fill_models.py tests/test_file_summary_views.py -k download +``` + +--- + +## 七、AFF-2 模块骨架与模板配置 + +### AFF-2-001 创建 application_form_fill 模块骨架 + +| 项目 | 内容 | +| --- | --- | +| 任务类型 | 后端 / 模块 | +| 前置任务 | AFF-1 | +| 涉及文件 | `review_agent/application_form_fill/` | +| 目标 | 建立独立模块目录、常量、schemas、storage、workflow、views 和 services 包 | +| 开发步骤 | 1. 创建模块目录;2. 创建 `constants.py`;3. 创建 `schemas.py`;4. 创建 `storage.py`;5. 创建 `workflow.py`;6. 创建 `views.py`;7. 创建 services 子模块;8. 创建 templates 和 prompts 目录 | +| 验收标准 | 模块可 import,不影响既有应用启动 | +| 验证命令 | `python manage.py check` | +| Codex 执行提示 | 请新增 `review_agent/application_form_fill/` 独立模块骨架,先只放常量、schema、空服务和基础 import,不要改动法规核查模块。 | + +### AFF-2-002 编写模板配置 YAML + +| 项目 | 内容 | +| --- | --- | +| 任务类型 | 配置 / 模板 | +| 前置任务 | AFF-2-001 | +| 涉及文件 | `review_agent/application_form_fill/templates/application_form_templates_v1.yaml` | +| 目标 | 建立模板配置,至少覆盖注册证 `.docx` 已识别字段 | +| 开发步骤 | 1. 定义 version;2. 定义 source_dir;3. 配置 `registration_certificate`;4. 配置 `change_registration` 为 `.doc` 待转换模板;5. 配置 `essential_principles` 为 `.doc` 待转换模板;6. 为注册证配置注册人名称、注册人住所、生产地址、产品名称、包装规格、主要组成成分、预期用途、储存条件及有效期、附件等字段 | +| 验收标准 | YAML 可解析,注册证字段映射到 table_row | +| 验证命令 | `pytest tests/test_application_form_fill_template_config.py` | +| Codex 执行提示 | 请新增自动填表模板配置 YAML,配置路径必须是 `review_agent/application_form_fill/templates/application_form_templates_v1.yaml`,先完整录入注册证表格字段。 | + +### AFF-2-003 实现模板配置加载与校验 + +| 项目 | 内容 | +| --- | --- | +| 任务类型 | 后端 / 配置 | +| 前置任务 | AFF-2-002 | +| 涉及文件 | `review_agent/application_form_fill/services/template_config.py`、`tests/test_application_form_fill_template_config.py` | +| 目标 | 读取、校验模板配置并计算 hash | +| 开发步骤 | 1. 实现 `load_template_config()`;2. 实现 `validate_template_config()`;3. 实现 `compute_config_hash()`;4. 校验 version、source_dir、templates、code 唯一、source_file 存在、target.type 支持;5. 对 `.doc` 待转换模板允许配置存在但标记运行时处理 | +| 验收标准 | 有效配置通过,缺失 source_dir 或重复 code 能被测试捕获 | +| 验证命令 | `pytest tests/test_application_form_fill_template_config.py` | +| Codex 执行提示 | 请实现模板配置加载和校验服务,配置错误必须返回清晰错误列表,不要在 import 时直接崩溃。 | + +### AFF-2 阶段验证 + +```bash +python manage.py check +pytest tests/test_application_form_fill_template_config.py +``` + +--- + +## 八、AFF-3 触发与工作流骨架 + +### AFF-3-001 扩展意图路由 + +| 项目 | 内容 | +| --- | --- | +| 任务类型 | 后端 / 意图识别 | +| 前置任务 | AFF-2 | +| 涉及文件 | `review_agent/skill_router.py`、`review_agent/application_form_fill/constants.py`、`tests/test_application_form_fill_trigger.py` | +| 目标 | 用户话语命中自动填表意图时返回 `application_form_fill` | +| 开发步骤 | 1. 增加触发关键词;2. 支持“帮我填注册证”“对应的表格”“生成申报模板”等;3. 支持指定模板识别入口;4. 保持文件汇总和法规核查路由不回归 | +| 验收标准 | 自动填表语句触发正确,普通对话不误触发 | +| 验证命令 | `pytest tests/test_application_form_fill_trigger.py tests/test_regulatory_workflow.py -k router` | +| Codex 执行提示 | 请扩展现有意图路由,新增 application_form_fill 动作。不要破坏 file_summary 和 regulatory_review 的现有触发。 | + +### AFF-3-002 实现批次创建和节点初始化 + +| 项目 | 内容 | +| --- | --- | +| 任务类型 | 后端 / 工作流 | +| 前置任务 | AFF-3-001 | +| 涉及文件 | `review_agent/application_form_fill/workflow.py`、`review_agent/application_form_fill/storage.py`、`tests/test_application_form_fill_workflow.py` | +| 目标 | 创建填表批次、生成工作目录、初始化节点 | +| 开发步骤 | 1. 实现 `build_batch_no()`;2. 实现 `build_batch_work_dir()`;3. 实现 `create_application_form_fill_batch()`;4. 绑定 conversation、user、trigger_message、source_summary_batch;5. 初始化 `FORM_FILL_NODE_DEFINITIONS` 节点;6. 写 workflow_created 事件 | +| 验收标准 | 批次编号唯一,节点数量正确,工作目录在受控路径 | +| 验证命令 | `pytest tests/test_application_form_fill_workflow.py -k create` | +| Codex 执行提示 | 请实现自动填表批次创建和节点初始化,workflow_type 必须写 application_form_fill。 | + +### AFF-3-003 实现工作流执行器骨架 + +| 项目 | 内容 | +| --- | --- | +| 任务类型 | 后端 / 工作流 | +| 前置任务 | AFF-3-002 | +| 涉及文件 | `review_agent/application_form_fill/workflow.py`、`tests/test_application_form_fill_workflow.py` | +| 目标 | 实现节点串行执行、状态更新、事件推送和 skipped PDF 节点 | +| 开发步骤 | 1. 实现 `FormFillWorkflowExecutor.run()`;2. 实现 `_nodes()`;3. 实现 `_run_node()`;4. 每个节点写 running/success/skipped;5. `pdf_convert` 本期标记 skipped;6. 失败时写 batch.failed | +| 验收标准 | 空实现节点可完整跑到 success;PDF 节点 skipped | +| 验证命令 | `pytest tests/test_application_form_fill_workflow.py -k executor` | +| Codex 执行提示 | 请实现自动填表工作流执行器骨架,先让节点状态可完整流转,PDF 转换节点本期标记 skipped。 | + +### AFF-3-004 接入流式对话启动逻辑 + +| 项目 | 内容 | +| --- | --- | +| 任务类型 | 后端 / 对话 | +| 前置任务 | AFF-3-003 | +| 涉及文件 | `review_agent/services.py`、`review_agent/application_form_fill/views.py` | +| 目标 | 用户触发自动填表时启动工作流;有附件时先自动汇总,无附件时使用最近成功汇总批次 | +| 开发步骤 | 1. 在 stream_message 中处理 application_form_fill 路由;2. 如本次存在新附件,复用文件汇总启动逻辑;3. 无新附件时查找最近成功 `FileSummaryBatch`;4. 无来源批次时回复请上传资料;5. 返回 workflow meta | +| 验收标准 | 对话触发能创建填表批次;无汇总批次时不崩溃 | +| 验证命令 | `pytest tests/test_application_form_fill_workflow.py -k stream` | +| Codex 执行提示 | 请把 application_form_fill 接入现有 stream_message。无附件时复用最近成功汇总批次;有新附件时先自动汇总。 | + +### AFF-3 阶段验证 + +```bash +python manage.py check +pytest tests/test_application_form_fill_trigger.py tests/test_application_form_fill_workflow.py +``` + +--- + +## 九、AFF-4 模板选择与文件来源 + +### AFF-4-001 实现模板指定解析 + +| 项目 | 内容 | +| --- | --- | +| 任务类型 | 后端 / 模板选择 | +| 前置任务 | AFF-3 | +| 涉及文件 | `review_agent/application_form_fill/services/template_select.py`、`tests/test_application_form_fill_template_select.py` | +| 目标 | 从用户话语中识别指定模板 | +| 开发步骤 | 1. 识别注册证;2. 识别变更注册备案文件;3. 识别安全和性能基本原则清单;4. 识别全部模板;5. 未指定返回空数组 | +| 验收标准 | 指定模板语句可返回正确 template_codes | +| 验证命令 | `pytest tests/test_application_form_fill_template_select.py -k requested` | +| Codex 执行提示 | 请实现用户指定模板解析,支持注册证、变更注册备案文件、安全和性能基本原则清单、全部模板。 | + +### AFF-4-002 实现注册类型识别和模板选择 + +| 项目 | 内容 | +| --- | --- | +| 任务类型 | 后端 / 模板选择 | +| 前置任务 | AFF-4-001 | +| 涉及文件 | `review_agent/application_form_fill/services/template_select.py`、`tests/test_application_form_fill_template_select.py` | +| 目标 | 按用户话语、法规确认条件、文件抽取识别注册类型,并选择模板 | +| 开发步骤 | 1. 用户话语识别首次注册、变更注册、备案;2. 从 `source_regulatory_batch.condition_json` 读取 confirmed_conditions;3. 从文件抽取候选读取 registration_type;4. 未指定模板时首次注册生成注册证 + 基本原则清单;5. 变更/备案生成变更文件 + 基本原则清单;6. 指定不适用模板允许生成但写 risk_notes | +| 验收标准 | 模板选择规则与功能设计一致 | +| 验证命令 | `pytest tests/test_application_form_fill_template_select.py` | +| Codex 执行提示 | 请实现注册类型识别和默认模板选择,优先级是用户话语、已确认法规核查条件、文件抽取、unknown。 | + +### AFF-4-003 实现模板复制服务 + +| 项目 | 内容 | +| --- | --- | +| 任务类型 | 后端 / 模板 | +| 前置任务 | AFF-4-002 | +| 涉及文件 | `review_agent/application_form_fill/services/template_repository.py`、`review_agent/application_form_fill/storage.py`、`tests/test_application_form_fill_template_repository.py` | +| 目标 | 将原始模板复制到批次目录,原始模板只读 | +| 开发步骤 | 1. 根据 TemplateSpec 定位 source_file;2. 复制到 `work_dir/templates`;3. 记录 ApplicationFormFillArtifact(template_copy);4. `.doc` 且无工作模板时返回模板失败,不影响其他模板;5. 路径必须在受控工作目录内 | +| 验收标准 | 注册证 `.docx` 可复制;原始文件不被修改;产物 hash 写入 | +| 验证命令 | `pytest tests/test_application_form_fill_template_repository.py` | +| Codex 执行提示 | 请实现模板复制服务,只允许复制到批次工作目录,不能直接写原始法规材料目录。 | + +### AFF-4 阶段验证 + +```bash +pytest tests/test_application_form_fill_template_select.py tests/test_application_form_fill_template_repository.py +``` + +--- + +## 十、AFF-5 字段抽取与合并 + +### AFF-5-001 实现规则/正则字段抽取 + +| 项目 | 内容 | +| --- | --- | +| 任务类型 | 后端 / 字段抽取 | +| 前置任务 | AFF-4 | +| 涉及文件 | `review_agent/application_form_fill/services/field_extract.py`、`tests/test_application_form_fill_field_extract.py` | +| 目标 | 从说明书、产品技术要求等文本中按标签和章节抽取字段 | +| 开发步骤 | 1. 复用 `regulatory_review.services.text_extract.extract_text`;2. 识别文件角色;3. 匹配 `字段名:值` 标签行;4. 支持多行值拼接;5. 保存 source_file、source_role、evidence、confidence、extractor=rule | +| 验收标准 | 能从测试说明书文本抽取产品名称、预期用途、储存条件、有效期、包装规格 | +| 验证命令 | `pytest tests/test_application_form_fill_field_extract.py -k rules` | +| Codex 执行提示 | 请实现自动填表规则/正则字段抽取,优先覆盖注册证模板字段,抽取结果必须包含来源文件、来源角色和证据片段。 | + +### AFF-5-002 实现 LLM 结构化抽取封装 + +| 项目 | 内容 | +| --- | --- | +| 任务类型 | 后端 / LLM | +| 前置任务 | AFF-5-001 | +| 涉及文件 | `review_agent/application_form_fill/services/field_extract.py`、`review_agent/application_form_fill/prompts/field_extract.md`、`tests/test_application_form_fill_field_extract.py` | +| 目标 | 调用现有 LLM 能力输出字段 JSON,失败时降级 | +| 开发步骤 | 1. 编写字段抽取 prompt;2. 输入模板字段、文件上下文和候选文本;3. 要求输出 JSON fields/checklist_items;4. 解析 JSON;5. 捕获超时和解析失败;6. 失败返回空 LLM 结果,不阻断规则抽取 | +| 验收标准 | monkeypatch LLM 后可解析结构化字段;LLM 异常时工作流继续 | +| 验证命令 | `pytest tests/test_application_form_fill_field_extract.py -k llm` | +| Codex 执行提示 | 请实现 LLM 结构化抽取封装,必须可测试、可降级。LLM 输出解析失败不能导致整个填表批次失败。 | + +### AFF-5-003 实现并行抽取和产物留底 + +| 项目 | 内容 | +| --- | --- | +| 任务类型 | 后端 / 字段抽取 | +| 前置任务 | AFF-5-002 | +| 涉及文件 | `review_agent/application_form_fill/services/field_extract.py`、`review_agent/application_form_fill/storage.py` | +| 目标 | 并行执行规则/正则和 LLM 抽取,并保存 `field_extract_result.json` | +| 开发步骤 | 1. 使用 ThreadPoolExecutor;2. 规则和 LLM 两路并行;3. 组装 regex_results、llm_results、selected_templates、source_evidence;4. 保存 JSON;5. 写 ApplicationFormFillArtifact(field_extract_result) | +| 验收标准 | JSON 产物包含两路结果和模板列表 | +| 验证命令 | `pytest tests/test_application_form_fill_field_extract.py -k parallel` | +| Codex 执行提示 | 请实现字段并行抽取和 field_extract_result.json 产物留底,LLM 失败时也必须保存规则结果。 | + +### AFF-5-004 实现字段合并与冲突检测 + +| 项目 | 内容 | +| --- | --- | +| 任务类型 | 后端 / 字段合并 | +| 前置任务 | AFF-5-003 | +| 涉及文件 | `review_agent/application_form_fill/services/field_merge.py`、`tests/test_application_form_fill_field_merge.py` | +| 目标 | 合并规则和 LLM 字段,说明书优先,并生成冲突摘要 | +| 开发步骤 | 1. 实现字段值归一化;2. 实现来源优先级排序;3. 同字段多值一致时合并;4. 不一致时选择最高优先级来源;5. 说明书与其他文件冲突时标记 conflict;6. 输出 merged_fields 和 conflicts | +| 验收标准 | 说明书优先;冲突字段包含 selected_value、selected_source、conflict_values、handling | +| 验证命令 | `pytest tests/test_application_form_fill_field_merge.py` | +| Codex 执行提示 | 请实现字段合并服务,严格按说明书优先处理冲突,并把冲突列表写成可用于对话摘要和追溯清单的结构。 | + +### AFF-5 阶段验证 + +```bash +pytest tests/test_application_form_fill_field_extract.py tests/test_application_form_fill_field_merge.py +``` + +--- + +## 十一、AFF-6 Word 填充与追溯导出 + +### AFF-6-001 实现 Word 表格行填充 + +| 项目 | 内容 | +| --- | --- | +| 任务类型 | 后端 / Word | +| 前置任务 | AFF-5 | +| 涉及文件 | `review_agent/application_form_fill/services/word_fill.py`、`tests/test_application_form_fill_word_fill.py` | +| 目标 | 使用 `python-docx` 按表格行名写入注册证模板 | +| 开发步骤 | 1. 打开 docx 模板副本;2. 遍历 tables/rows/cells;3. 匹配第一列 row_label;4. 写入第二列;5. 缺失字段保持空白;6. 保存 output_path | +| 验收标准 | 产品名称、包装规格、预期用途等能写入注册证模板对应行 | +| 验证命令 | `pytest tests/test_application_form_fill_word_fill.py -k table` | +| Codex 执行提示 | 请实现 Word 表格行填充服务,先支持注册证模板的两列表格行名匹配。 | + +### AFF-6-002 实现冲突高亮 + +| 项目 | 内容 | +| --- | --- | +| 任务类型 | 后端 / Word | +| 前置任务 | AFF-6-001 | +| 涉及文件 | `review_agent/application_form_fill/services/word_fill.py`、`tests/test_application_form_fill_word_fill.py` | +| 目标 | 冲突字段在 Word 中黄底红字 | +| 开发步骤 | 1. 对冲突字段写入 run;2. 设置字体颜色 `FF0000`;3. 设置单元格 shading `FFFF00`;4. 非冲突字段保持原样式;5. 测试读取 docx XML 验证颜色和底色 | +| 验收标准 | 冲突字段样式可在 docx XML 中验证 | +| 验证命令 | `pytest tests/test_application_form_fill_word_fill.py -k highlight` | +| Codex 执行提示 | 请实现 Word 冲突高亮,冲突字段必须红色字体和黄色底色,测试需检查 docx XML。 | + +### AFF-6-003 创建 Word 导出记录 + +| 项目 | 内容 | +| --- | --- | +| 任务类型 | 后端 / 导出 | +| 前置任务 | AFF-6-002 | +| 涉及文件 | `review_agent/application_form_fill/services/word_fill.py`、`review_agent/application_form_fill/workflow.py` | +| 目标 | Word 生成后写入 `ExportedSummaryFile(export_type=word)` 和产物记录 | +| 开发步骤 | 1. 按批次号、产品名、模板标签生成文件名;2. 保存到 `work_dir/filled`;3. 创建 `ApplicationFormFillArtifact(filled_template)`;4. 创建 `ExportedSummaryFile`;5. 记录模板失败时错误 | +| 验收标准 | 可查询到 word 导出记录和 filled_template 产物 | +| 验证命令 | `pytest tests/test_application_form_fill_word_fill.py -k export` | +| Codex 执行提示 | 请把 Word 填充结果保存为导出文件,export_type 使用 word,workflow_type 使用 application_form_fill。 | + +### AFF-6-004 实现追溯清单 Excel/JSON + +| 项目 | 内容 | +| --- | --- | +| 任务类型 | 后端 / 导出 | +| 前置任务 | AFF-6-003 | +| 涉及文件 | `review_agent/application_form_fill/services/traceability_export.py`、`tests/test_application_form_fill_traceability.py` | +| 目标 | 输出字段来源追溯清单和合并结果 JSON | +| 开发步骤 | 1. 生成“字段追溯”Sheet;2. 生成“冲突字段”Sheet;3. 生成“低置信度条目”Sheet;4. 生成“生成结果”Sheet;5. 保存 Excel;6. 保存 merged_fields.json;7. 创建导出和产物记录 | +| 验收标准 | Excel 可打开,包含字段、来源、证据、冲突、处理方式 | +| 验证命令 | `pytest tests/test_application_form_fill_traceability.py` | +| Codex 执行提示 | 请实现字段来源追溯清单导出,必须包含规则/LLM 合并结果、冲突字段和生成结果。 | + +### AFF-6 阶段验证 + +```bash +pytest tests/test_application_form_fill_word_fill.py tests/test_application_form_fill_traceability.py +``` + +--- + +## 十二、AFF-7 飞书通知与对话摘要 + +### AFF-7-001 生成助手 Markdown 摘要 + +| 项目 | 内容 | +| --- | --- | +| 任务类型 | 后端 / 对话 | +| 前置任务 | AFF-6 | +| 涉及文件 | `review_agent/application_form_fill/services/traceability_export.py`、`review_agent/application_form_fill/workflow.py` | +| 目标 | 工作流完成后向当前对话写入下载链接和冲突摘要 | +| 开发步骤 | 1. 汇总 Word 导出;2. 汇总 PDF 状态为待增强;3. 汇总冲突字段;4. 添加追溯清单下载链接;5. 创建 assistant Message | +| 验收标准 | 对话中出现 Markdown 表格、Word 下载、追溯清单下载和冲突摘要 | +| 验证命令 | `pytest tests/test_application_form_fill_workflow.py -k summary` | +| Codex 执行提示 | 请实现自动填表完成后的助手 Markdown 摘要,PDF 本期显示为待增强,不作为失败。 | + +### AFF-7-002 实现飞书通知记录和 mock 通知 + +| 项目 | 内容 | +| --- | --- | +| 任务类型 | 后端 / 通知 | +| 前置任务 | AFF-7-001 | +| 涉及文件 | `review_agent/application_form_fill/services/notifier.py`、`tests/test_application_form_fill_notification.py` | +| 目标 | 填表完成后记录通知,可 mock 发送,失败不阻断下载 | +| 开发步骤 | 1. 实现 `notify_completion()`;2. 默认 channel=mock;3. 写 template_codes、export_ids、message_summary;4. 支持 send_status success/failed;5. 失败时记录 error_message 和 retry_count | +| 验收标准 | 通知记录可查;通知失败不影响批次核心产物 | +| 验证命令 | `pytest tests/test_application_form_fill_notification.py` | +| Codex 执行提示 | 请实现自动填表通知服务,先用 mock 通知记录即可。通知失败不得阻断 Word 下载。 | + +### AFF-7-003 完成工作流状态归并 + +| 项目 | 内容 | +| --- | --- | +| 任务类型 | 后端 / 工作流 | +| 前置任务 | AFF-7-002 | +| 涉及文件 | `review_agent/application_form_fill/workflow.py`、`tests/test_application_form_fill_workflow.py` | +| 目标 | 根据 Word、追溯清单、通知结果标记 success/partial_success/failed | +| 开发步骤 | 1. 所有目标 Word 成功时 success;2. 至少一个 Word 成功但非关键产物失败时 partial_success;3. 所有 Word 失败时 failed;4. PDF skipped 不导致失败;5. 发送 workflow_completed 事件 | +| 验收标准 | 批次状态符合详细设计 | +| 验证命令 | `pytest tests/test_application_form_fill_workflow.py -k status` | +| Codex 执行提示 | 请完成自动填表工作流状态归并,PDF skipped 不影响 success,通知失败最多导致 partial_success。 | + +### AFF-7 阶段验证 + +```bash +pytest tests/test_application_form_fill_workflow.py tests/test_application_form_fill_notification.py +``` + +--- + +## 十三、AFF-8 前端卡片与总体验收 + +### AFF-8-001 后端状态接口 + +| 项目 | 内容 | +| --- | --- | +| 任务类型 | 后端 / 接口 | +| 前置任务 | AFF-7 | +| 涉及文件 | `review_agent/application_form_fill/views.py`、`review_agent/urls.py` 或相关 URL 文件 | +| 目标 | 提供自动填表启动和状态查询接口 | +| 开发步骤 | 1. 新增 start 接口;2. 新增 detail/status 接口;3. 返回 batch、nodes、conflicts、exports;4. 校验 conversation/user 权限;5. 接入 URL | +| 验收标准 | 当前用户可查自己的填表批次,不能查他人批次 | +| 验证命令 | `pytest tests/test_application_form_fill_views.py` | +| Codex 执行提示 | 请实现自动填表启动和状态查询接口,所有查询必须校验当前用户权限。 | + +### AFF-8-002 前端支持 application_form_fill 卡片 + +| 项目 | 内容 | +| --- | --- | +| 任务类型 | 前端 / 工作流卡片 | +| 前置任务 | AFF-8-001 | +| 涉及文件 | `static/js/app.js`、`templates/home.html`、静态 CSS 文件 | +| 目标 | 前端展示自动填表工作流卡片,并根据 SSE 更新节点 | +| 开发步骤 | 1. 解析 workflow_type=application_form_fill;2. 定义节点文案;3. 创建卡片;4. 更新节点状态;5. PDF 节点显示待增强/跳过;6. 页面刷新后恢复 | +| 验收标准 | 自动填表卡片可显示准备资料、选择模板、复制模板、抽取字段、填写 Word、追溯清单、飞书通知 | +| 验证命令 | `pytest tests/test_application_form_fill_frontend.py` 或现有前端测试命令 | +| Codex 执行提示 | 请在现有工作流卡片逻辑中新增 application_form_fill 类型,展示自动填表节点并支持状态恢复。 | + +### AFF-8-003 前端展示结果和下载链接 + +| 项目 | 内容 | +| --- | --- | +| 任务类型 | 前端 / Markdown | +| 前置任务 | AFF-8-002 | +| 涉及文件 | `static/js/app.js`、模板和 CSS | +| 目标 | 对话框正常展示 Word 下载、追溯清单、冲突摘要 | +| 开发步骤 | 1. 确认助手 Markdown 渲染支持表格;2. 验证 Word 下载链接点击;3. 验证冲突摘要表格;4. PDF 列显示待增强 | +| 验收标准 | 对话结果可读、链接可用、PDF 待增强不被误判为失败 | +| 验证命令 | 前端/Playwright 对应测试 | +| Codex 执行提示 | 请验证并完善自动填表结果展示,确保 Markdown 表格、Word 下载链接、追溯清单链接和冲突摘要正常显示。 | + +### AFF-8-004 总体验收与回归 + +| 项目 | 内容 | +| --- | --- | +| 任务类型 | 验收 / 回归 | +| 前置任务 | AFF-8-003 | +| 涉及文件 | 全项目 | +| 目标 | 运行全量测试,确认前三批能力均不回归 | +| 开发步骤 | 1. 运行 Django check;2. 运行自动填表测试;3. 运行文件汇总测试;4. 运行法规核查测试;5. 如可用,运行前端/Playwright 测试;6. 检查 git status | +| 验收标准 | 全量测试通过;失败项均有解释;无意外文件变更 | +| 验证命令 | `python manage.py check`; `pytest` | +| Codex 执行提示 | 请执行第三批自动填表总体验收,运行 Django check 和 pytest 全量回归,确认文件汇总与法规核查不回归。 | + +### AFF-8 阶段验证 + +```bash +python manage.py check +pytest +``` + +--- + +## 十四、测试分层要求 + +| 层级 | 验证内容 | 建议文件 | +| --- | --- | --- | +| 模型测试 | 三张新表、word/pdf 导出类型、权限关系 | `tests/test_application_form_fill_models.py` | +| 配置测试 | YAML 加载、模板配置校验、hash | `tests/test_application_form_fill_template_config.py` | +| 选择测试 | 触发语句、指定模板、注册类型优先级、默认模板 | `tests/test_application_form_fill_template_select.py` | +| 抽取测试 | 规则/正则、LLM 降级、并行抽取、字段合并 | `tests/test_application_form_fill_field_extract.py`、`tests/test_application_form_fill_field_merge.py` | +| Word 测试 | 表格行填充、冲突高亮、导出记录 | `tests/test_application_form_fill_word_fill.py` | +| 导出测试 | 追溯清单 Excel、JSON 产物、下载权限 | `tests/test_application_form_fill_traceability.py`、`tests/test_application_form_fill_views.py` | +| 工作流测试 | 批次创建、节点流转、状态归并、助手摘要 | `tests/test_application_form_fill_workflow.py` | +| 通知测试 | mock 通知、失败记录、重试字段 | `tests/test_application_form_fill_notification.py` | +| 前端测试 | 卡片节点、PDF 待增强、下载链接、冲突摘要 | `tests/test_application_form_fill_frontend.py` | + +--- + +## 十五、Codex 自动化执行规则 + +| 规则 | 内容 | +| --- | --- | +| 顺序执行 | 必须从 AFF-0 到 AFF-8 顺序执行,不得跳阶段 | +| TDD | 新行为先写失败测试,再实现 | +| 当前阶段优先 | 某阶段失败时先修复当前阶段,不继续后续阶段 | +| 回归保护 | 文件汇总和法规核查已有测试不得回归 | +| PDF 边界 | PDF 节点本期可 skipped,不为 PDF 引入强依赖 | +| 字段表边界 | 不新增字段级数据库表,后续增强已在待办计划 | +| 每阶段验证 | 每阶段完成后运行对应验证命令 | +| 每阶段提交 | 每阶段验证通过后生成提交摘要并本地提交 | +| 不覆盖变更 | 不得回滚或覆盖用户已有未提交变更 | + +--- + +## 十六、推荐目标模式提示词 + +后续可直接对 Codex 输入: + +```text +请按 docs/5.开发计划/3.产品关键信息提取与申报文件自动填表.md 执行第三批开发。 + +目标: +完成独立 application_form_fill 工作流,通过用户对话触发自动填表,复用当前对话最近成功 FileSummaryBatch,支持模板配置、注册证 Word 自动填写、规则/正则与 LLM 并行字段抽取、说明书优先冲突归并、冲突高亮、字段来源追溯清单、Word 下载、自动填表工作流卡片和飞书 mock 通知记录。 + +执行规则: +1. 创建 codex/YYYYMMDD-申报文件自动填表 分支。 +2. 按 AFF-0 到 AFF-8 顺序执行,不跳阶段。 +3. 每阶段先写测试,再实现,完成后运行对应验证命令。 +4. 不实现字段级数据库表。 +5. PDF 转换本期作为 skipped/待增强,不引入强制 LibreOffice 依赖。 +6. 模板配置路径必须为 review_agent/application_form_fill/templates/application_form_templates_v1.yaml。 +7. Word 模板优先支持注册证格式 docx,两个 doc 模板可标记待转换或部分成功。 +8. 每阶段验证通过后调用 git-commit-summary 生成提交摘要并本地提交。 +9. 最后运行 python manage.py check 和 pytest 全量验收。 +``` + +--- + +## 十七、待执行前检查清单 + +| 检查项 | 状态 | +| --- | --- | +| 第三批需求分析、功能设计、详细设计、数据库设计均已存在 | 待执行时确认 | +| 当前分支是否适合创建开发分支 | 待执行时确认 | +| 是否存在用户未提交变更 | 待执行时确认 | +| `python-docx`、`openpyxl`、`PyYAML` 是否可用 | 待执行时确认 | +| 现有文件汇总和法规核查测试是否通过 | 待执行时确认 | +| 执行机器是否提供 `git-commit-summary` skill | 待执行时确认 | +| `.doc` 模板和 PDF 转换是否保持在待办边界内 | 待执行时确认 | diff --git a/docs/6.待办计划/第二阶段暂缓事项.md b/docs/6.待办计划/第二阶段暂缓事项.md index c79c941..72d19d9 100644 --- a/docs/6.待办计划/第二阶段暂缓事项.md +++ b/docs/6.待办计划/第二阶段暂缓事项.md @@ -33,10 +33,12 @@ | 编号 | 待办项 | 来源 | 建议优先级 | 说明 | | --- | --- | --- | --- | --- | -| TODO-FILL-001 | 产品关键信息抽取结果确认 | 原始需求 3 | P1 | 将第二阶段抽取字段转成可人工确认的信息表 | -| TODO-FILL-002 | 自动填写目标文件 | 原始需求 3 | P1 | 将确认后的字段写入注册申报表格或对照清单 | -| TODO-FILL-003 | 填写前后差异报告 | 自动填写风控 | P1 | 输出写入前后 diff,供人工复核 | -| TODO-FILL-004 | 自动填写审批确认 | 自动填写风控 | P1 | 文件写操作前必须人工确认 | +| TODO-FILL-001 | 字段级数据库表 | 第三批自动填表数据库设计 | P1 | 后续新增 `ApplicationFormFillField`,支持字段级查询、人工修改、审计和统计 | +| TODO-FILL-002 | PDF 转换与版式 QA | 第三批自动填表详细设计 | P1 | 使用 LibreOffice/soffice 将填好的 Word 转 PDF,并增加页数非 0、逐页截图或版式差异检查 | +| TODO-FILL-003 | `.doc` 模板预转换管理 | 第三批自动填表模板处理 | P1 | 将变更注册(备案)文件和安全和性能基本原则清单预转换为 `.docx` 工作模板,并人工确认版式 | +| TODO-FILL-004 | 安全和性能基本原则清单完整条目拆解 | 第三批自动填表模板配置 | P1 | 拆解清单条目编号、原则内容、适用性栏、证据栏和证明文件位置栏,写入 YAML 配置 | +| TODO-FILL-005 | 填写前后差异报告 | 自动填写风控 | P1 | 输出写入前后 diff,供人工复核 | +| TODO-FILL-006 | 自动填写审批确认 | 自动填写风控 | P1 | 文件写操作前支持人工确认或二次审批 | ---