# 比赛备赛规划文档 ## 一、赛题核心理解 ### 1.1 赛题名称 **A23 - 基于大语言模型的文档理解与多源数据融合** 参赛院校:金陵科技学院 ### 1.2 核心任务 1. **文档解析**:解析 docx/md/xlsx/txt 四种格式的源数据文档 2. **模板填写**:根据模板表格要求,从源文档中提取数据填写到 Word/Excel 模板 3. **准确率与速度**:准确率优先,速度作为辅助评分因素 ### 1.3 评分规则 | 要素 | 说明 | |------|------| | 准确率 | 填写结果与样例表格对比的正确率 | | 响应时间 | 从导入文档到得到结果的时间 ≤ 90s × 文档数量 | | 评测方式 | 赛方提供空表格模板 + 样例表格(人工填写),系统自动填写后对比 | ### 1.4 关键Q&A摘录 | 问题 | 解答要点 | |------|----------| | Q2: 模板与文档的关系 | 前2个表格只涉及1份文档;第3-4个涉及多份文档;第5个涉及大部分文档(从易到难) | | Q5: 响应时间定义 | 从导入文档到最终得到结果的时间 ≤ 90s × 文档数量 | | Q7: 需要读取哪些文件 | 每个模板只读取指定的数据文件,不需要读取全部 | | Q10: 部署方式 | 不要求部署到服务器,本地部署即可 | | Q14: 模板匹配 | 模板已指定数据文件,不需要算法匹配 | | Q16: 数据库存储 | 可跳过,不强制要求 | | Q20: 创新点 | 不用管,随意发挥 | | Q21: 填写依据 | 按照测试表格模板给的提示词进行填写 | --- ## 二、已完成功能清单 ### 2.1 后端服务 (`backend/app/services/`) | 服务文件 | 功能状态 | 说明 | |----------|----------|------| | `file_service.py` | ✅ 已完成 | 文件上传、保存、类型识别 | | `excel_storage_service.py` | ✅ 已完成 | Excel 存储到 MySQL,支持 XML 回退解析 | | `table_rag_service.py` | ⚠️ 已禁用 | RAG 索引构建(当前禁用,仅记录日志) | | `llm_service.py` | ✅ 已完成 | LLM 调用、流式输出、多模型支持 | | `markdown_ai_service.py` | ✅ 已完成 | Markdown AI 分析、分章节提取、流式输出、图表生成 | | `excel_ai_service.py` | ✅ 已完成 | Excel AI 分析 | | `visualization_service.py` | ✅ 已完成 | 图表生成(matplotlib) | | `rag_service.py` | ⚠️ 已禁用 | FAISS 向量检索(当前禁用) | | `prompt_service.py` | ✅ 已完成 | Prompt 模板管理 | | `text_analysis_service.py` | ✅ 已完成 | 文本分析 | | `chart_generator_service.py` | ✅ 已完成 | 图表生成服务 | | `template_fill_service.py` | ✅ 已完成 | 模板填写服务,支持多行提取、直接从结构化数据提取、JSON容错、Word文档表格处理 | ### 2.2 API 接口 (`backend/app/api/endpoints/`) | 接口文件 | 路由 | 功能状态 | |----------|------|----------| | `upload.py` | `/api/v1/upload/document` | ✅ 文档上传与解析 | | `documents.py` | `/api/v1/documents/*` | ✅ 文档管理(列表、删除、搜索) | | `ai_analyze.py` | `/api/v1/analyze/*` | ✅ AI 分析(Excel、Markdown、流式) | | `rag.py` | `/api/v1/rag/*` | ⚠️ RAG 检索(当前返回空) | | `tasks.py` | `/api/v1/tasks/*` | ✅ 异步任务状态查询 | | `templates.py` | `/api/v1/templates/*` | ✅ 模板管理(含多行导出、Word导出、Word结构化字段解析) | | `visualization.py` | `/api/v1/visualization/*` | ✅ 可视化图表 | | `health.py` | `/api/v1/health` | ✅ 健康检查 | ### 2.3 前端页面 (`frontend/src/pages/`) | 页面文件 | 功能 | 状态 | |----------|------|------| | `Documents.tsx` | 主文档管理页面 | ✅ 已完成 | | `TemplateFill.tsx` | 智能填表页面 | ✅ 已完成 | | `ExcelParse.tsx` | Excel 解析页面 | ✅ 已完成 | ### 2.4 文档解析能力 | 格式 | 解析状态 | 说明 | |------|----------|------| | Excel (.xlsx/.xls) | ✅ 已完成 | pandas + XML 回退解析,支持多sheet | | Markdown (.md) | ✅ 已完成 | 正则 + AI 分章节 | | Word (.docx) | ✅ 已完成 | python-docx 解析,支持表格提取和字段识别 | | Text (.txt) | ✅ 已完成 | chardet 编码检测,支持文本清洗和结构化提取 | --- ## 三、核心功能实现详情 ### 3.1 模板填写模块(✅ 已完成) **核心流程**: ``` 上传模板表格(Word/Excel) ↓ 解析模板,提取需要填写的字段和提示词 ↓ 根据源文档ID列表读取源数据(MongoDB或文件) ↓ 优先从结构化数据直接提取(Excel rows) ↓ 无法直接提取时使用 LLM 从文本中提取 ↓ 将提取的数据填入原始模板对应位置(保持模板格式) ↓ 导出填写完成的表格(Excel/Word) ``` **关键特性**: - **原始模板填充**:直接打开原始模板文件,填充数据到原表格/单元格 - **多行数据支持**:每个字段可提取多个值,导出时自动扩展行数 - **结构化数据优先**:直接从 Excel rows 提取,无需 LLM - **JSON 容错**:支持 LLM 返回的损坏/截断 JSON - **Markdown 清理**:自动清理 LLM 返回的 markdown 格式 ### 3.2 Word 文档解析(✅ 已完成) **已实现功能**: - `docx_parser.py` - Word 文档解析器 - 提取段落文本 - 提取表格内容(支持比赛表格格式:字段名 | 提示词 | 填写值) - `parse_tables_for_template()` - 解析表格模板,提取字段 - `extract_template_fields_from_docx()` - 提取模板字段定义 - `_infer_field_type_from_hint()` - 从提示词推断字段类型 - **API 端点**:`/api/v1/templates/parse-word-structure` - 上传 Word 文档,提取结构化字段并存入 MongoDB - **API 端点**:`/api/v1/templates/word-fields/{doc_id}` - 获取已存文档的模板字段信息 ### 3.3 Text 文档解析(✅ 已完成) **已实现功能**: - `txt_parser.py` - 文本文件解析器 - 编码自动检测 (chardet) - 文本清洗(去除控制字符、规范化空白) - 结构化数据提取(邮箱、URL、电话、日期、金额) --- ## 四、参赛材料准备 ### 4.1 必交材料 | 材料 | 要求 | 当前状态 | 行动项 | |------|------|----------|--------| | 项目概要介绍 | PPT 格式 | ❌ 待制作 | 制作 PPT | | 项目简介 PPT | - | ❌ 待制作 | 制作 PPT | | 项目详细方案 | 文档 | ⚠️ 部分完成 | 完善文档 | | 项目演示视频 | - | ❌ 待制作 | 录制演示视频 | | 训练素材说明 | 来源说明 | ⚠️ 已有素材 | 整理素材文档 | | 关键模块设计文档 | 概要设计 | ⚠️ 已有部分 | 完善文档 | | 可运行 Demo | 核心代码 | ✅ 已完成 | 打包可运行版本 | ### 4.2 Demo 提交要求 根据 Q&A: - 可以只提交核心代码,不需要完整运行环境 - 现场答辩可使用自带笔记本电脑 - 需要提供部署和运行说明(README) --- ## 五、测试验证计划 ### 5.1 使用现有测试数据 ``` docs/test/ ├── 2023年文化和旅游发展统计公报.md ├── 2024年卫生健康事业发展统计公报.md ├── 第三次全国工业普查主要数据公报.md ``` ### 5.2 模板填写测试流程 1. 准备一个 Word/Excel 模板表格 2. 指定源数据文档 3. 上传模板和文档 4. 执行模板填写 5. 检查填写结果准确率 6. 记录响应时间 ### 5.3 性能目标 | 指标 | 目标 | 当前状态 | |------|------|----------| | 信息提取准确率 | ≥80% | 需测试验证 | | 单次响应时间 | ≤90s × 文档数 | 需测试验证 | --- ## 六、工作计划(建议) ### 第一优先级:端到端测试 - 使用真实测试数据进行准确率测试 - 验证多行数据导出是否正确 - 测试 Word 模板解析是否正常 ### 第二优先级:Demo 打包与文档 - 制作项目演示 PPT - 录制演示视频 - 完善 README 部署文档 ### 第三优先级:优化 - 优化响应时间 - 完善错误处理 - 增加更多测试用例 --- ## 七、注意事项 1. **创新点**:根据 Q&A,不必纠结创新点数量限制 2. **数据库**:不强制要求数据库存储,可跳过 3. **部署**:本地部署即可,不需要公网服务器 4. **评测数据**:初赛仅使用目前提供的数据 5. **RAG 功能**:当前已临时禁用,不影响核心评测功能(因为使用直接文件读取) --- *文档版本: v1.5* *最后更新: 2026-04-09* --- ## 八、技术实现细节 ### 8.1 模板填表流程 #### 流程图 ``` ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ 上传模板 │ ──► │ 选择数据源 │ ──► │ 智能填表 │ └─────────────┘ └─────────────┘ └─────────────┘ │ ┌─────────────────────────┼─────────────────────────┐ │ │ │ ▼ ▼ ▼ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │ 结构化数据提取 │ │ LLM 提取 │ │ 导出结果 │ │ (直接读rows) │ │ (文本理解) │ │ (Excel/Word) │ └───────────────┘ └───────────────┘ └───────────────┘ ``` #### 核心组件 | 组件 | 文件 | 说明 | |------|------|------| | 模板上传 | `templates.py` `/templates/upload` | 接收模板文件,提取字段 | | 字段提取 | `template_fill_service.py` | 从 Word/Excel 表格提取字段定义 | | 文档解析 | `docx_parser.py`, `xlsx_parser.py`, `txt_parser.py` | 解析源文档内容 | | 智能填表 | `template_fill_service.py` `fill_template()` | 结构化提取 + LLM 提取 | | 多行支持 | `template_fill_service.py` `FillResult` | values 数组支持 | | JSON 容错 | `template_fill_service.py` `_fix_json()` | 修复损坏的 JSON | | 结果导出 | `templates.py` `/templates/export` | 多行 Excel + Word 导出 | ### 8.2 源文档加载方式 模板填表服务支持两种方式加载源文档: 1. **通过 MongoDB 文档 ID**:`source_doc_ids` - 文档已上传并存入 MongoDB - 服务直接查询 MongoDB 获取文档内容 2. **通过文件路径**:`source_file_paths` - 直接读取本地文件 - 使用对应的解析器解析内容 ### 8.3 Word 表格模板解析 比赛评分表格通常是 Word 格式,`docx_parser.py` 提供了专门的解析方法: ```python # 提取表格模板字段 from docx_parser import DocxParser parser = DocxParser() fields = parser.extract_template_fields_from_docx(file_path) # 返回格式 # [ # { # "cell": "T0R1", # 表格0,行1 # "name": "字段名", # "hint": "提示词", # "field_type": "text/number/date", # "required": True # }, # ... # ] ``` ### 8.4 字段类型推断 系统支持从提示词自动推断字段类型: | 关键词 | 推断类型 | 示例 | |--------|----------|------| | 年、月、日、日期、时间、出生 | date | 出生日期 | | 数量、金额、比率、%、率、合计 | number | 增长比率 | | 其他 | text | 姓名、地址 | ### 8.5 API 接口 #### POST `/api/v1/templates/upload` 上传模板文件,提取字段定义。 **响应**: ```json { "success": true, "template_id": "/path/to/saved/template.docx", "filename": "模板.docx", "file_type": "docx", "fields": [ {"cell": "A1", "name": "姓名", "field_type": "text", "required": true, "hint": "提取人员姓名"} ], "field_count": 1 } ``` #### POST `/api/v1/templates/fill` 填写请求: ```json { "template_id": "模板ID", "template_fields": [ {"cell": "A1", "name": "姓名", "field_type": "text", "required": true, "hint": "提取人员姓名"} ], "source_doc_ids": ["mongodb_doc_id_1", "mongodb_doc_id_2"], "source_file_paths": [], "user_hint": "请从xxx文档中提取" } ``` **响应(含多行支持)**: ```json { "success": true, "filled_data": { "姓名": ["张三", "李四", "王五"], "年龄": ["25", "30", "28"] }, "fill_details": [ { "field": "姓名", "cell": "A1", "values": ["张三", "李四", "王五"], "value": "张三", "source": "结构化数据直接提取", "confidence": 1.0 } ], "source_doc_count": 2, "max_rows": 3 } ``` #### POST `/api/v1/templates/export` 导出请求(创建新文件): ```json { "template_id": "模板ID", "filled_data": {"姓名": ["张三", "李四"], "金额": ["10000", "20000"]}, "format": "xlsx" } ``` #### POST `/api/v1/templates/fill-and-export` **填充原始模板并导出**(推荐用于比赛) 直接打开原始模板文件,将数据填入模板的表格/单元格中,然后导出。**保持原始模板格式不变**。 **请求**: ```json { "template_path": "/path/to/original/template.docx", "filled_data": { "姓名": ["张三", "李四", "王五"], "年龄": ["25", "30", "28"] }, "format": "docx" } ``` **响应**:填充后的 Word/Excel 文件(文件流) **特点**: - 打开原始模板文件 - 根据表头行匹配字段名到列索引 - 将数据填入对应列的单元格 - 多行数据自动扩展表格行数 - 保持原始模板格式和样式 #### POST `/api/v1/templates/parse-word-structure` **上传 Word 文档并提取结构化字段**(比赛专用) 上传 Word 文档,从表格模板中提取字段定义(字段名、提示词、字段类型)并存入 MongoDB。 **请求**:multipart/form-data - file: Word 文件 **响应**: ```json { "success": true, "doc_id": "mongodb_doc_id", "filename": "模板.docx", "file_path": "/path/to/saved/template.docx", "field_count": 5, "fields": [ { "cell": "T0R1", "name": "字段名", "hint": "提示词", "field_type": "text", "required": true } ], "tables": [...], "metadata": { "paragraph_count": 10, "table_count": 1, "word_count": 500, "has_tables": true } } ``` #### GET `/api/v1/templates/word-fields/{doc_id}` **获取 Word 文档模板字段信息** 根据 doc_id 获取已上传的 Word 文档的模板字段信息。 **响应**: ```json { "success": true, "doc_id": "mongodb_doc_id", "filename": "模板.docx", "fields": [...], "tables": [...], "field_count": 5, "metadata": {...} } ``` ### 8.6 多行数据处理 **FillResult 数据结构**: ```python @dataclass class FillResult: field: str values: List[Any] = None # 支持多个值(数组) value: Any = "" # 保留兼容(第一个值) source: str = "" # 来源文档 confidence: float = 1.0 # 置信度 ``` **导出逻辑**: - 计算所有字段的最大行数 - 遍历每一行,取对应索引的值 - 不足的行填空字符串 ### 8.7 JSON 容错处理 当 LLM 返回的 JSON 损坏或被截断时,系统会: 1. 清理 markdown 代码块标记(```json, ```) 2. 尝试配对括号找到完整的 JSON 3. 移除末尾多余的逗号 4. 使用正则表达式提取 values 数组 5. 备选方案:直接提取所有引号内的字符串 ### 8.8 结构化数据优先提取 对于 Excel 等有 `rows` 结构的文档,系统会: 1. 直接从 `structured_data.rows` 中查找匹配列 2. 使用模糊匹配(字段名包含或被包含) 3. 提取该列的所有行值 4. 无需调用 LLM,速度更快,准确率更高 ```python # 内部逻辑 if structured.get("rows"): columns = structured.get("columns", []) values = _extract_column_values(rows, columns, field_name) ``` --- ## 九、依赖说明 ### Python 依赖 ``` # requirements.txt 中需要包含 fastapi>=0.104.0 uvicorn>=0.24.0 motor>=3.3.0 # MongoDB 异步驱动 sqlalchemy>=2.0.0 # MySQL ORM pandas>=2.0.0 # Excel 处理 openpyxl>=3.1.0 # Excel 写入 python-docx>=0.8.0 # Word 处理 chardet>=4.0.0 # 编码检测 httpx>=0.25.0 # HTTP 客户端 ``` ### 前端依赖 ``` # package.json 中需要包含 react>=18.0.0 react-dropzone>=14.0.0 lucide-react>=0.300.0 sonner>=1.0.0 # toast 通知 ``` --- ## 十、启动说明 ### 后端启动 ```bash cd backend .\venv\Scripts\Activate.ps1 # 或 Activate.bat pip install -r requirements.txt # 确保依赖完整 .\venv\Scripts\python.exe -m uvicorn app.main:app --host 127.0.0.1 --port 8000 --reload ``` ### 前端启动 ```bash cd frontend npm install npm run dev ``` ### 环境变量 在 `backend/.env` 中配置: ``` MONGODB_URL=mongodb://localhost:27017 MONGODB_DB_NAME=document_system MYSQL_HOST=localhost MYSQL_PORT=3306 MYSQL_USER=root MYSQL_PASSWORD=your_password MYSQL_DATABASE=document_system LLM_API_KEY=your_api_key LLM_BASE_URL=https://api.minimax.chat LLM_MODEL_NAME=MiniMax-Text-01 ```