3 Коміти ad61e0ace2 ... 1b1b1acb02

Автор SHA1 Опис Дата
  zhch158_admin 1b1b1acb02 fix: 修正差异数据框的样式应用方法 1 тиждень тому
  zhch158_admin 5a5e4015d6 Remove obsolete configuration file for OCR validation tool, including styles, UI settings, OCR data configurations, data sources, and pre-validation paths. 1 тиждень тому
  zhch158_admin d1b21341f2 feat: 添加OCR验证系统配置文件说明文档 1 тиждень тому
4 змінених файлів з 1031 додано та 433 видалено
  1. 551 99
      README.md
  2. 0 333
      config.yaml
  3. 479 0
      config/README.md
  4. 1 1
      streamlit_validator_result.py

+ 551 - 99
README.md

@@ -8,22 +8,26 @@
 
 - **Dots OCR**:专业 VLM OCR 引擎
 - **PaddleOCR PPStructV3**:结构化文档识别
+- **PaddleOCR-VL**:视觉语言模型增强版
 - **Table Recognition V2**:专业表格识别
-- **MinerU VLM-2.5.3**:多模态文档理解
+- **MinerU VLM**:多模态文档理解
 
 ### 🔄 智能交叉验证
 
 - **多数据源对比**:支持不同 OCR 工具结果的交叉验证
 - **细粒度差异检测**:精确到单元格级别的差异分析
 - **智能表格对比**:
-  - 标准表格模式
-  - 流水表格模式(支持表头位置检测)
+  - 标准表格模式(`standard`)
+  - 流水表格模式(`flow_list`)- 支持表头位置智能检测
+  - **资产负债表等多层表头识别**:自动识别总表头和分类标题
+  - 自动列类型检测(数字、日期、文本、文本型数字)
 - **差异分类统计**:
-  - 金额差异(`table_amount`)
-  - 日期时间差异(`table_datetime`)
-  - 文本差异(`table_text`)
+  - 金额差异(`table_amount`)- 严重度:**high**
+  - 日期时间差异(`table_datetime`)- 严重度:**medium**
+  - 文本差异(`table_text`)- 严重度:**low/medium**(根据相似度)
   - 表头差异(位置、内容、结构)
   - 段落差异
+  - **列类型冲突**(自动提升严重度到 **high**)
 
 ### 📊 可视化校验工具
 
@@ -72,30 +76,75 @@ cd ocr_verify
 
 # 安装依赖
 pip install -r requirements.txt
-# 或手动安装
+# 或手动安装核心依赖
 pip install streamlit plotly pandas pillow numpy opencv-python openpyxl \
     beautifulsoup4 pyyaml fuzzywuzzy python-Levenshtein
 ```
 
 ### 配置文件
 
-编辑 [`config.yaml`](config.yaml) 配置数据源:
+编辑配置文件(详见 [`config/README.md`](config/README.md)):
+
+#### 1. 全局配置 (`config/global.yaml`)
 
 ```yaml
 data_sources:
-  - name: "至远彩色_2023年报"
-    ocr_tool: "ppstructv3"
-    ocr_out_dir: "/path/to/ppstructv3/output"
-    src_img_dir: "/path/to/source/images"
-    description: "使用 PPStructV3 的识别结果"
+  - 德_内蒙古银行照.yaml
+  - 对公_招商银行图.yaml
+  - A用户_单元格扫描流水.yaml
+  - B用户_扫描流水.yaml
+  - 至远彩色_2023年报.yaml
+```
+
+#### 2. 项目配置示例 (`config/B用户_扫描流水.yaml`)
+
+```yaml
+document:
+  name: "B用户_扫描流水"
+  base_dir: "/Users/zhch158/workspace/data/流水分析/B用户_扫描流水"
   
-  - name: "至远彩色_2023年报"
-    ocr_tool: "mineru"
-    ocr_out_dir: "/path/to/mineru/output"
-    src_img_dir: "/path/to/source/images"
-    description: "使用 MinerU 的识别结果"
+  ocr_results:
+    # PPStructV3
+    - tool: "ppstructv3"
+      result_dir: "ppstructurev3_client_results"
+      image_dir: "ppstructurev3_client_results/{{name}}"
+      description: "PPStructV3 图片合成结果"
+      enabled: true
+    
+    # PaddleOCR-VL
+    - tool: "paddleocr_vl"
+      result_dir: "paddleocr_vl_results"
+      image_dir: "paddleocr_vl_results/{{name}}"
+      description: "PaddleOCR VLM 图片合成结果"
+      enabled: true
+    
+    # MinerU
+    - tool: "mineru"
+      result_dir: "mineru_vllm_results"
+      image_dir: "mineru_vllm_results/{{name}}"
+      description: "MinerU 图片合成结果"
+      enabled: true
+    
+    # Dots OCR
+    - tool: "dots_ocr"
+      result_dir: "dotsocr_vllm_results"
+      image_dir: "dotsocr_vllm_results/{{name}}"
+      description: "Dots OCR 图片合成结果"
+      enabled: true
 ```
 
+**配置说明**:
+- `document.name`:项目名称
+- `base_dir`:项目根目录(绝对路径)
+- `ocr_results`:OCR 工具结果配置数组
+  - `tool`:工具标识(`ppstructv3` / `paddleocr_vl` / `mineru` / `dots_ocr`)
+  - `result_dir`:结果目录(相对于 `base_dir`)
+  - `image_dir`:图像目录(支持 `{{name}}` 模板变量)
+  - `description`:工具描述
+  - `enabled`:是否启用(`true` / `false`)
+
+**详细配置说明**见 [`config/README.md`](config/README.md)
+
 ## 📖 使用指南
 
 ### 1️⃣ 启动可视化验证工具
@@ -121,7 +170,7 @@ python run_streamlit_validator.py
 
 - 选择两个不同的 OCR 数据源
 - 点击「交叉验证」按钮运行批量验证
-- 查看详细的差异对比结果
+- 查看详细的差异对比结果(支持按严重度筛选)
 - 下载验证报告(Excel、JSON)
 
 #### 📊 表格分析
@@ -133,35 +182,116 @@ python run_streamlit_validator.py
 
 ### 2️⃣ 命令行对比工具
 
-使用 [comparator/compare_ocr_results.py](compare_ocr_results.py) 进行命令行对比
+使用 `comparator/compare_ocr_results.py` 进行命令行对比(详见 [`comparator/README.md`](comparator/README.md))
 
 ```bash
 # 基本对比
-python compare_ocr_results.py file1.md file2.md
+python comparator/compare_ocr_results.py file1.md file2.md
 
-# 使用流水表格模式
-python compare_ocr_results.py file1.md file2.md \
+# 使用流水表格模式(智能表头检测 + 多层表头识别)
+python comparator/compare_ocr_results.py file1.md file2.md \
     --table-mode flow_list \
     --similarity-algorithm ratio \
     -o output/comparison_result \
     -f both
 
-# 仅生成 JSON 报告
-python compare_ocr_results.py file1.md file2.md \
-    -f json -o report
+# 资产负债表对比(自动识别多层表头)
+python comparator/compare_ocr_results.py balance_sheet1.md balance_sheet2.md \
+    --table-mode flow_list \
+    -o balance_sheet_comparison
 ```
 
 **参数说明:**
 
 - `-o, --output`:输出文件名(不含扩展名)
 - `-f, --format`:输出格式(`json`、`markdown`、`both`)
-- `--table-mode`:表格比对模式(`standard`、`flow_list`)
-- `--similarity-algorithm`:相似度算法(`ratio`、`partial_ratio`、`token_sort_ratio`、`token_set_ratio`)
+- `--table-mode`:表格比对模式
+  - `standard`:标准表格(结构固定)
+  - `flow_list`:流水表格(智能表头检测、支持多层表头)
+- `--similarity-algorithm`:相似度算法
+  - `ratio`:标准相似度
+  - `partial_ratio`:部分匹配
+  - `token_sort_ratio`:排序后匹配
+  - `token_set_ratio`:集合匹配
 - `--ignore-images`:忽略图片内容对比
 
-### 3️⃣ 数字标准化工具
+**详细文档**:参见 [`comparator/README.md`](comparator/README.md)
+
+### 3️⃣ OCR 结果合并工具
+
+合并不同 OCR 工具的识别结果,提升准确性(详见 [`merger/README.md`](merger/README.md)):
+
+```bash
+# 合并 MinerU 和 PaddleOCR 结果
+python merger/merge_mineru_paddle_ocr.py \
+    --mineru-dir /path/to/mineru/output \
+    --paddle-dir /path/to/paddleocr/output \
+    --output-dir /path/to/merged/output
+
+# 合并 PaddleOCR-VL 和 PaddleOCR 结果
+python merger/merge_paddleocr_vl_paddleocr.py \
+    --paddleocr-vl-dir /path/to/paddleocr_vl/output \
+    --paddle-dir /path/to/paddleocr/output \
+    --output-dir /path/to/merged/output
+
+# 合并 Dots OCR 和 PaddleOCR 结果
+python merger/merge_dotsocr_paddleocr.py \
+    --dotsocr-dir /path/to/dotsocr/output \
+    --paddle-dir /path/to/paddleocr/output \
+    --output-dir /path/to/merged/output
+```
+
+**合并策略:**
+
+- **表格内容**:优先使用 VLM 工具(MinerU/PaddleOCR-VL/Dots OCR)的结果
+- **表格坐标**:使用 PaddleOCR 的全局 OCR 文本块坐标(更精确)
+- **文本内容**:智能匹配并合并
 
-使用 [`normalize_financial_numbers.py`](normalize_financial_numbers.py):
+**详细文档**:参见 [`merger/README.md`](merger/README.md)
+
+### 4️⃣ 批量处理工具
+
+批量处理 PDF 文档并合并 OCR 结果(详见 [`batch_ocr/README.md`](batch_ocr/README.md)):
+
+```bash
+# 批量处理 PDF 列表
+python batch_ocr/batch_process_pdf.py \
+    --config batch_ocr/processor_configs.yaml \
+    --pdf-list batch_ocr/pdf_list.txt
+
+# 批量合并 OCR 结果
+python batch_ocr/batch_merge_results.py \
+    --config batch_ocr/processor_configs.yaml \
+    --pdf-list batch_ocr/pdf_list.txt \
+    --merge-mode mineru_paddle
+```
+
+**配置文件示例** (`processor_configs.yaml`):
+
+```yaml
+processors:
+  mineru:
+    command: "magic-pdf"
+    args:
+      - "-p"
+      - "{pdf_path}"
+      - "-o"
+      - "{output_dir}"
+    output_structure: "auto/{pdf_name}/auto"
+  
+  paddleocr:
+    command: "paddleocr"
+    args:
+      - "--image_dir"
+      - "{image_dir}"
+
+```
+
+**详细文档**:参见 [`batch_ocr/README.md`](batch_ocr/README.md)
+
+### 5️⃣ 数字标准化工具
+
+使用 `normalize_financial_numbers.py`:
 
 ```python
 from normalize_financial_numbers import normalize_financial_numbers, normalize_json_file
@@ -188,16 +318,50 @@ ocr_verify/
 ├── ocr_validator_layout.py             # 布局管理
 ├── ocr_validator_utils.py              # 工具函数
 ├── ocr_validator_file_utils.py         # 文件处理
-├── compare_ocr_results.py              # OCR 结果对比
 ├── normalize_financial_numbers.py      # 数字标准化
-├── merge_mineru_paddle_ocr.py          # 合并 MinerU 和 Paddle OCR 结果
-├── config.yaml                         # 配置文件
 ├── styles.css                          # 样式文件
+├── requirements.txt                    # 依赖列表
+├── config/                             # 配置文件目录 ✨
+│   ├── global.yaml                    # 全局配置
+│   ├── 至远彩色_2023年报.yaml         # 年报类项目配置
+│   ├── A用户_单元格扫描流水.yaml      # 流水表格配置
+│   ├── B用户_扫描流水.yaml            # 流水表格配置
+│   ├── 德_内蒙古银行照.yaml           # 银行流水配置
+│   ├── 对公_招商银行图.yaml           # 银行流水配置
+│   └── README.md                      # 配置文档 ✨
+├── comparator/                         # OCR 结果对比模块
+│   ├── compare_ocr_results.py         # 命令行对比工具
+│   ├── ocr_comparator.py              # 核心对比器
+│   ├── table_comparator.py            # 表格对比器(✨ 支持多层表头)
+│   ├── paragraph_comparator.py        # 段落对比器
+│   ├── similarity_calculator.py       # 相似度计算
+│   ├── data_type_detector.py          # 数据类型检测
+│   ├── content_extractor.py           # 内容提取器
+│   ├── text_processor.py              # 文本处理器
+│   ├── report_generator.py            # 报告生成器
+│   └── README.md                      # 对比模块文档
+├── merger/                             # OCR 结果合并模块
+│   ├── merge_mineru_paddle_ocr.py     # MinerU + PaddleOCR 合并
+│   ├── merge_paddleocr_vl_paddleocr.py # PaddleOCR-VL + PaddleOCR 合并
+│   ├── merge_dotsocr_paddleocr.py     # Dots OCR + PaddleOCR 合并
+│   ├── merger_core.py                 # 合并核心逻辑
+│   ├── text_matcher.py                # 文本匹配器(fazz partial_ratio算法)
+│   ├── bbox_extractor.py              # 坐标提取器
+│   ├── data_processor.py              # 数据处理器
+│   ├── markdown_generator.py          # Markdown 生成器
+│   ├── unified_output_converter.py    # 统一输出转换器
+│   └── README.md                      # 合并模块文档
+├── batch_ocr/                          # 批量处理模块
+│   ├── batch_process_pdf.py           # 批量 PDF 处理
+│   ├── batch_merge_results.py         # 批量结果合并
+│   ├── processor_configs.yaml         # 处理器配置
+│   ├── pdf_list.txt                   # PDF 列表
+│   └── README.md                      # 批量处理文档
 ├── output/                             # 输出目录
-│   └── pre_validation/                 # 交叉验证结果
+│   └── pre_validation/                # 交叉验证结果
 ├── .streamlit/                         # Streamlit 配置
-│   └── config.toml                     # Streamlit 设置
-└── README.md                           # 项目文档
+│   └── config.toml                    # Streamlit 设置
+└── README.md                          # 项目文档(本文件)
 ```
 
 ## 🎯 核心功能详解
@@ -205,21 +369,21 @@ ocr_verify/
 ### 交叉验证流程
 
 1. **数据源选择**
+   - 在 Streamlit 界面选择 OCR 数据源(从配置文件加载)
+   - 选择验证数据源(用于交叉对比)
 
-   - 选择 OCR 数据源(如 PPStructV3)
-   - 选择验证数据源(如 MinerU)
 2. **批量验证**
-
    - 自动匹配相同页码的文件
    - 逐页进行差异检测
    - 生成详细验证报告
+
 3. **差异分析**
+   - **表格差异**:逐单元格对比(支持多层表头)
+   - **段落差异**:智能段落匹配
+   - **结构差异**:表头位置、行缺失等
+   - **严重度分级**:critical > high > medium > low
 
-   - 表格差异:逐单元格对比
-   - 段落差异:智能段落匹配
-   - 结构差异:表头位置、行缺失等
 4. **结果展示**
-
    - 差异列表(按类型、严重程度分类)
    - 统计图表(饼图、柱状图)
    - 详细对比视图(左右对照)
@@ -232,28 +396,120 @@ ocr_verify/
 - 逐行逐列对比
 - 适合财务报表、数据统计表
 
-#### 流水表格模式 (`flow_list`)
+#### 流水表格模式 (`flow_list`) ✨
+
+**智能表头检测:**
+
+```python
+# 自动检测表头位置(支持多层表头)
+header_row_idx = detect_table_header_row(table)
+
+# 检测策略:
+# 1. 关键词匹配(日期、金额、余额、资产、负债等)
+# 2. 下一行验证(数据行/分类行)
+# 3. 多层表头识别(资产负债表等)
+```
+
+**✨ 新增:多层表头识别**
+
+针对资产负债表等特殊表格:
+
+```python
+# 示例表格结构:
+# 第1行:['资产', '期末余额', '期初余额', '负债及所有者权益', '期末余额', '期初余额']  ← 总表头
+# 第2行:['流动资产:', '', '', '流动负债:', '', '']  ← 分类标题(分类行)
+# 第3行:['货币资金', '28,239,305.48', '68,162,260.60', ...]  ← 数据行
+
+def _is_category_row(row):
+    """识别分类行(如"流动资产:")"""
+    patterns = [
+        r'.*:$',  # 以冒号结尾
+    ]
+    # 返回 True 表示是分类行
+
+# 评分调整:
+# - 数据行:+0.2 分
+# - 分类行:+0.1 分(新增)
+```
+
+**列类型检测:**
+
+- `numeric`:数字金额
+- `datetime`:日期时间
+- `text_number`:文本型数字(如票据号)
+- `text`:普通文本
+
+**✨ 差异严重度改进:**
+
+```python
+# 基础严重度(由单元格对比决定)
+base_severity = {
+    'table_amount': 'high',        # 金额差异
+    'table_datetime': 'medium',    # 日期差异
+    'table_text': 'low/medium'     # 文本差异(根据相似度)
+}
+
+# 列类型冲突自动提升
+if col_idx in mismatched_columns:
+    if base_severity != 'high':
+        final_severity = 'high'  # 提升到 high
+```
+
+**适用场景:**
+
+- 银行流水表
+- 交易记录
+- **资产负债表**(✨ 多层表头)
+- **利润表**
+- 流水日志
+
+### 表格匹配算法
+
+智能匹配两个文件中的表格,支持:
+
+1. **行列数相似度** (30%)
+   - 行数相似度 (15%)
+   - 列数相似度 (15%) - ✨ 改进:容忍 1-2 列差异
+2. **表头相似度** (50%) - 最重要
+   - 精确匹配 (40%)
+   - 模糊匹配 (40%)
+   - 语义匹配 (20%) - 识别常见表头关键词
+3. **内容特征相似度** (20%)
+
+```python
+# 表格匹配示例
+matches = find_matching_tables(tables1, tables2)
+# 输出: [(0, 0, 95.2), (1, 1, 87.3)]
+# 格式: (文件1表格索引, 文件2表格索引, 相似度%)
+```
+
+### OCR 结果合并策略
+
+#### 1. MinerU + PaddleOCR 合并
 
-- 智能检测表头位置
-- 支持表头前内容对比
-- 自动列类型检测(数字、日期、文本)
-- 适合银行流水、交易记录等
+```python
+# 表格内容:优先 MinerU(VLM 更准确)
+# 表格坐标:使用 PaddleOCR 全局 OCR 坐标(更精确)
+merged_result = merge_mineru_paddleocr(mineru_json, paddle_json)
+```
 
-### 图像旋转处理
+#### 2. PaddleOCR-VL + PaddleOCR 合并
 
 ```python
-# 自动检测旋转角度
-detection_result = detect_image_orientation_by_opencv(image_path)
+# 表格内容:优先 PaddleOCR-VL
+# 表格坐标:使用 PaddleOCR 全局 OCR 坐标
+merged_result = merge_paddleocr_vl_paddleocr(vl_json, paddle_json)
+```
 
-# 手动调整旋转
-validator.layout_manager.rotated_angle = 90  # 顺时针 90 度
+#### 3. Dots OCR + PaddleOCR 合并
 
-# 坐标自动转换
-rotated_image, rotated_bboxes = rotate_image_and_coordinates(
-    image, angle, coordinates_list, rotate_coordinates=True
-)
+```python
+# 表格内容:优先 Dots OCR
+# 表格坐标:使用 PaddleOCR 全局 OCR 坐标
+merged_result = merge_dotsocr_paddleocr(dots_json, paddle_json)
 ```
 
+
 ## 📊 输出示例
 
 ### 交叉验证报告
@@ -269,9 +525,28 @@ rotated_image, rotated_bboxes = rotate_image_and_coordinates(
       "file1_value": "15.00",
       "file2_value": "15,00",
       "description": "金额不一致: 15.00 vs 15,00",
-      "severity": "medium",
+      "severity": "high",
       "column_name": "金额",
-      "column_type": "numeric"
+      "column_type": "numeric",
+      "row_index": 15,
+      "col_index": 4
+    },
+    {
+      "type": "table_header_position",
+      "position": "表头位置",
+      "file1_value": "第1行",
+      "file2_value": "第2行",
+      "description": "表头位置不一致: 文件1在第1行,文件2在第2行",
+      "severity": "high"
+    },
+    {
+      "type": "table_text",
+      "position": "第20行第3列",
+      "file1_value": "流动资产",
+      "file2_value": "流动 资产",
+      "description": "文本不一致: 流动资产 vs 流动 资产 [列类型冲突]",
+      "severity": "high",
+      "column_type_mismatch": true
     }
   ],
   "statistics": {
@@ -281,9 +556,10 @@ rotated_image, rotated_bboxes = rotate_image_and_coordinates(
     "datetime_differences": 3,
     "text_differences": 24,
     "paragraph_differences": 7,
-    "high_severity": 8,
-    "medium_severity": 20,
-    "low_severity": 14
+    "critical_severity": 2,
+    "high_severity": 11,
+    "medium_severity": 17,
+    "low_severity": 12
   }
 }
 ```
@@ -296,93 +572,261 @@ rotated_image, rotated_bboxes = rotate_image_and_coordinates(
 ## 统计信息
 - 总差异数量: **42**
 - 表格差异: **35**
-  - 金额差异: **8**
-  - 日期差异: **3**
-  - 文本差异: **24**
+  - 金额差异: **8** (严重度: high)
+  - 日期差异: **3** (严重度: medium)
+  - 文本差异: **24** (严重度: low/medium)
+  - 列类型冲突: **3** (严重度提升至: high)
 - 段落差异: **7**
 
-## 差异详情
+## 差异详情(按严重度分类)
+
+### ❌ 严重差异 (Critical)
+| 序号 | 位置 | 类型 | 原OCR结果 | 验证结果 | 描述 |
+|------|------|------|-----------|----------|------|
+| 1 | 表格列类型 | table_header_critical | 5列类型不一致 | 共10列 | 列类型差异过大 (50%) |
+
+### ⚠️ 高优先级差异 (High)
 | 序号 | 位置 | 类型 | 原OCR结果 | 验证结果 | 描述 |
 |------|------|------|-----------|----------|------|
 | 1 | 第15行第5列 | table_amount | 15.00 | 15,00 | 金额不一致 |
+| 2 | 第20行第3列 | table_text | 流动资产 | 流动 资产 | 文本不一致 [列类型冲突] |
+
+### ℹ️ 中优先级差异 (Medium)
+...
+
+### 💡 低优先级差异 (Low)
+...
 ```
 
 ## 🔧 高级配置
 
-### OCR 工具配置
+### 配置文件结构
+
+项目使用 YAML 配置文件管理数据源和工具参数(详见 [`config/README.md`](config/README.md))。
+
+**全局配置** (`config/global.yaml`):
 
-在 [`config.yaml`](config.yaml) 中配置工具参数:
+```yaml
+data_sources:
+  - 德_内蒙古银行照.yaml
+  - 对公_招商银行图.yaml
+  - A用户_单元格扫描流水.yaml
+  - B用户_扫描流水.yaml
+  - 至远彩色_2023年报.yaml
+```
+
+**项目配置** (`config/B用户_扫描流水.yaml`):
 
 ```yaml
-ocr:
-  tools:
-    ppstructv3:
-      name: "PPStructV3"
-      json_structure: "object"
-      rotation:
-        coordinates_are_pre_rotated: true
+document:
+  name: "B用户_扫描流水"
+  base_dir: "/Users/zhch158/workspace/data/流水分析/B用户_扫描流水"
   
-    mineru:
-      name: "MinerU"
-      json_structure: "array"
-      rotation:
-        coordinates_are_pre_rotated: false
+  ocr_results:
+    - tool: "ppstructv3"
+      result_dir: "ppstructurev3_client_results"
+      image_dir: "ppstructurev3_client_results/{{name}}"
+      description: "PPStructV3 图片合成结果"
+      enabled: true
+    
+    - tool: "mineru"
+      result_dir: "mineru_vllm_results"
+      image_dir: "mineru_vllm_results/{{name}}"
+      description: "MinerU 图片合成结果"
+      enabled: true
 ```
 
-### MinerU, PaddleOCR-VL表格单元格坐标使用 Paddle OCR全局OCR文本块坐标
+**配置参数说明**:
+- `document.name`:项目名称(用于模板变量替换)
+- `base_dir`:项目根目录(绝对路径)
+- `tool`:OCR 工具标识(`ppstructv3` / `paddleocr_vl` / `mineru` / `dots_ocr`)
+- `result_dir`:结果目录(相对于 `base_dir`)
+- `image_dir`:图像目录(支持 `{{name}}` 模板变量)
+- `enabled`:是否启用该数据源
 
-详见[merger-说明.md](merger/merger-说明.md)
+### 批量处理配置
+
+在 `batch_ocr/processor_configs.yaml` 中配置(详见 [`batch_ocr/README.md`](batch_ocr/README.md)):
+
+```yaml
+processors:
+  mineru:
+    command: "magic-pdf"
+    args:
+      - "-p"
+      - "{pdf_path}"
+      - "-o"
+      - "{output_dir}"
+      - "--method"
+      - "auto"
+    output_structure: "auto/{pdf_name}/auto"
+    
+  paddleocr:
+    command: "paddleocr"
+    args:
+      - "--image_dir"
+      - "{image_dir}"
+      - "--type"
+      - "structure"
+      - "--det_model_dir"
+      - "models/ch_PP-OCRv4_det_infer"
+      - "--rec_model_dir"
+      - "models/ch_PP-OCRv4_rec_infer"
+    output_structure: "{pdf_name}/ppstructure"
+
+merge:
+  mineru_paddle:
+    priority: "mineru"  # 表格内容优先级
+    coordinate_source: "paddleocr"  # 坐标来源
+    iou_threshold: 0.5  # IoU 匹配阈值
+```
 
 ### Streamlit 配置
 
-编辑 [`.streamlit/config.toml`](.streamlit/config.toml):
+编辑 `.streamlit/config.toml`:
 
 ```toml
 [theme]
 primaryColor = "#0288d1"
 backgroundColor = "#ffffff"
 secondaryBackgroundColor = "#f5f5f5"
+textColor = "#262730"
+font = "sans serif"
 
 [server]
 maxUploadSize = 200
 enableXsrfProtection = true
+enableCORS = false
+
+[browser]
+gatherUsageStats = false
 ```
 
 ## 🐛 常见问题
 
 ### Q1: 图像显示位置不正确?
 
-**A:** 检查 OCR 工具的坐标是否已预旋转,在 `config.yaml` 中调整 `coordinates_are_pre_rotated` 设置。
+**A:** 检查配置文件中的 OCR 工具坐标参数设置(不同工具的坐标处理方式可能不同)
 
 ### Q2: 交叉验证结果为空?
 
-**A:** 确保两个数据源包含相同页码的文件,且文件名格式为 `*_page_XXX.json`。
+**A:** 
+- 确保两个数据源包含相同页码的文件
+- 检查配置文件中的 `enabled: true` 设置
+- 验证 `base_dir` 和 `result_dir` 路径正确
 
 ### Q3: 表格对比差异过多?
 
-**A:** 尝试切换到 `flow_list` 模式,或调整相似度算法参数。
+**A:** 
+- 在命令行工具中使用 `--table-mode flow_list`(智能表头检测)
+- 调整相似度算法参数(如使用 `--similarity-algorithm token_set_ratio`)
+- ✨ **检查表格结构是否为多层表头(如资产负债表)** - 算法会自动识别
+
+### Q4: 表格坐标不准确?
+
+**A:** 使用合并工具结合 PaddleOCR 的全局 OCR 坐标:
+
+```bash
+python merger/merge_mineru_paddle_ocr.py \
+    --mineru-dir /path/to/mineru \
+    --paddle-dir /path/to/paddleocr \
+    --output-dir /path/to/output
+```
+
+### Q5: 如何处理资产负债表等多层表头?✨
+
+**A:** 使用 `flow_list` 模式,算法会自动检测多层表头:
+
+```bash
+python comparator/compare_ocr_results.py balance_sheet1.md balance_sheet2.md \
+    --table-mode flow_list
+```
+
+**识别逻辑:**
+1. 第1行:总表头(如"资产"、"负债")
+2. 第2行:分类标题(如"流动资产:")- 识别为分类行
+3. 第3行起:数据行
+
+**调试信息:**
+```
+📍 检测到表头在第 1 行 (得分: 0.87)
+   行数对比: 10 vs 10, 相似度: 100.0%
+   列数对比: 6 vs 6, 相似度: 100.0%
+   表头位置: 文件1第1行, 文件2第1行
+   表头相似度: 92.5%
+      精确匹配: 83%, 模糊匹配: 100%, 语义匹配: 100%
+```
+
+### Q6: 配置文件不生效?
+
+**A:** 
+- 检查 `global.yaml` 中是否正确引用了项目配置文件
+- 确认 YAML 语法正确(缩进必须用空格,不能用 Tab)
+- 确保配置文件在 `config/` 目录下
+- 重启 Streamlit 应用
+
+### Q7: 模板变量未替换?
+
+**A:** 
+- 确认使用了正确的模板变量语法:`{{name}}`
+- 检查 `document.name` 是否已定义
+- 查看 Streamlit 控制台的路径解析日志
+
+### Q8: 批量处理失败?
+
+**A:** 
+- 检查 `processor_configs.yaml` 配置是否正确
+- 确保 PDF 路径正确且可访问
+- 查看日志文件定位具体错误
+
+### Q9: 列类型冲突导致差异过多?✨
+
+**A:** 这是正常现象,列类型冲突会自动将差异严重度提升到 `high`:
+
+```json
+{
+  "type": "table_text",
+  "severity": "high",
+  "column_type_mismatch": true,
+  "description": "文本不一致 [列类型冲突]"
+}
+```
+
+**建议:**
+1. 检查两个 OCR 工具的列类型检测是否准确
+2. 如果某一工具明显错误,优先使用另一工具的结果
+3. 考虑使用合并工具优化结果
 
 ## 📝 开发说明
 
 ### 扩展开发
 
-- 新增 OCR 工具:在 `ocr_validator_utils.py` 中添加解析函数
-- 自定义对比算法:继承 `OCRResultComparator` 类
-- 新增渲染模式:在 `ocr_validator_layout.py` 中扩展
+#### 新增 OCR 工具
 
-## 🤝 贡献指南
+1. 在配置文件中添加工具配置
+2. 在 `merger/` 中实现合并逻辑(如需要)
+3. 更新 `config/README.md` 文档
 
-欢迎提交 Issue 和 Pull Request!
+#### 自定义对比算法
 
-1. Fork 本仓库
-2. 创建特性分支 (`git checkout -b feature/AmazingFeature`)
-3. 提交更改 (`git commit -m 'Add some AmazingFeature'`)
-4. 推送到分支 (`git push origin feature/AmazingFeature`)
-5. 提交 Pull Request
+```python
+from comparator.ocr_comparator import OCRResultComparator
 
-## 📄 许可证
+class CustomComparator(OCRResultComparator):
+    def compare_tables(self, table1, table2):
+        # 自定义对比逻辑
+        pass
+```
+
+#### 新增渲染模式
 
-本项目采用 MIT 许可证。详见 [LICENSE](LICENSE) 文件。
+在 `ocr_validator_layout.py` 中扩展:
+
+```python
+def render_custom_mode(self, content):
+    # 自定义渲染逻辑
+    pass
+```
 
 ## 📞 联系方式
 
@@ -392,6 +836,14 @@ enableXsrfProtection = true
 
 ## 🙏 致谢
 
+感谢以下开源项目的支持:
+
+- [PaddleOCR](https://github.com/PaddlePaddle/PaddleOCR) - 文档识别
+- [MinerU](https://github.com/opendatalab/MinerU) - 文档识别
+- [Dots OCR](https://github.com/rednote-hilab/dots.ocr.git) - 文档识别
+- [Streamlit](https://streamlit.io/) - Web 应用框架
+- [Plotly](https://plotly.com/) - 数据可视化
+
 ---
 
-**最后更新**: 2025年10月10日
+**最后更新**: 2025年11月7

+ 0 - 333
config.yaml

@@ -1,333 +0,0 @@
-# OCR验证工具配置文件
-
-# 样式配置
-styles:
-  font_size: 8
-  
-  colors:
-    primary: "#0288d1"
-    secondary: "#ff9800"
-    success: "#4caf50"
-    error: "#f44336"
-    warning: "#ff9800"
-    background: "#fafafa"
-    text: "#333333"
-  
-  layout:
-    default_zoom: 1.0
-    default_height: 800
-    sidebar_width: 1
-    content_width: 0.65
-
-# 界面配置
-ui:
-  page_title: "OCR可视化校验工具"
-  page_icon: "🔍"
-  layout: "wide"
-  sidebar_state: "expanded"
-  
-# OCR数据配置
-ocr:
-  min_text_length: 2
-  default_confidence: 1.0
-  exclude_texts: ["Picture", ""]
-  
-  # 图片方向检测配置
-  orientation_detection:
-    enabled: true
-    confidence_threshold: 0.3  # 置信度阈值
-    methods: ["opencv_analysis"]  # 检测方法
-    cache_results: true  # 缓存检测结果
-  
-  # OCR工具类型配置
-  tools:
-    dots_ocr:
-      name: "Dots OCR"
-      description: "专业VLM OCR"
-      json_structure: "array"  # JSON为数组格式
-      text_field: "text"
-      bbox_field: "bbox"
-      category_field: "category"
-      confidence_field: "confidence"
-      # 旋转处理配置
-      rotation:
-        coordinates_are_pre_rotated: false  # 坐标不是预旋转的
-        
-    ppstructv3:
-      name: "PPStructV3"
-      description: "PaddleOCR PP-StructureV3"
-      json_structure: "object"  # JSON为对象格式
-      parsing_results_field: "parsing_res_list"
-      text_field: "block_content"
-      bbox_field: "block_bbox"
-      rec_texts_field: "overall_ocr_res.rec_texts" # 针对表格中的文字块
-      rec_boxes_field: "overall_ocr_res.rec_boxes" # 针对表格中的文字块
-      category_field: "block_label"
-      confidence_field: "confidence"
-      # 旋转处理配置
-      rotation:
-        coordinates_are_pre_rotated: true  # 坐标已经是预旋转的
-      
-    table_recognition_v2:
-      name: "TableRecognitionV2"
-      description: "PaddleOCR Table Recognition V2"
-      json_structure: "object"
-      parsing_results_field: "table_res_list"
-      text_field: "pred_html"
-      bbox_field: "cell_box_list"            # 原先的 cell_box_listox 为笔误
-      rec_texts_field: "table_ocr_pred.rec_texts" # 针对表格中的文字块
-      rec_boxes_field: "table_ocr_pred.rec_boxes" # 针对表格中的文字块
-      category_field: "type"
-      confidence_field: "confidence"
-      rotation:
-        coordinates_are_pre_rotated: true
-    
-    mineru:
-      name: "MinerU"
-      description: "MinerU OCR"
-      json_structure: "array"  # JSON为数组格式
-      text_field: "text"
-      bbox_field: "bbox"
-      category_field: "type"
-      confidence_field: "confidence"
-      # 表格相关字段
-      table_body_field: "table_body"
-      table_cells_field: "table_cells"
-      img_path_field: "img_path"
-      # 旋转处理配置
-      rotation:
-        coordinates_are_pre_rotated: false
-  
-  # 自动检测工具类型的规则(按优先级从高到低)
-  auto_detection:
-    enabled: true
-    rules:
-      # Table Recognition V2 - 最高优先级
-      - tool_type: "table_recognition_v2"
-        conditions:
-          - type: "field_exists"
-            field: "table_res_list"
-          - type: "field_not_exists"
-            field: "parsing_res_list"
-        priority: 4
-      
-      # PPStructV3 - 第二优先级
-      - tool_type: "ppstructv3"
-        conditions:
-          - type: "field_exists"
-            field: "parsing_res_list"
-          - type: "field_exists"
-            field: "doc_preprocessor_res"
-        priority: 2
-      
-      # MinerU - 第三优先级
-      - tool_type: "mineru"
-        conditions:
-          - type: "field_exists"
-            field: "page_idx"
-          - type: "field_exists"
-            field: "type"
-          - type: "json_structure"
-            structure: "array"
-        priority: 1
-      
-      # Dots OCR - 最低优先级(默认)
-      - tool_type: "dots_ocr"
-        conditions:
-          - type: "json_structure"
-            structure: "array"
-          - type: "field_exists"
-            field: "category"
-        priority: 3
-
-data_sources:
-  - name: "德_内蒙古银行照"
-    ocr_tool: "ppstructv3"
-    ocr_out_dir: "/Users/zhch158/workspace/data/流水分析/德_内蒙古银行照/data_PPStructureV3_Results"
-    src_img_dir: "/Users/zhch158/workspace/data/流水分析/德_内蒙古银行照/data_PPStructureV3_Results/德_内蒙古银行照"
-    description: "德_内蒙古银行照使用PPStructV3的图片合成结果"
-
-  - name: "德_内蒙古银行照_PaddleOCR_VL"
-    ocr_tool: "ppstructv3"
-    ocr_out_dir: "/Users/zhch158/workspace/data/流水分析/德_内蒙古银行照/PaddleOCR_VL_Results"
-    src_img_dir: "/Users/zhch158/workspace/data/流水分析/德_内蒙古银行照/PaddleOCR_VL_Results/德_内蒙古银行照"
-    description: "德_内蒙古银行照使用PaddleOCR VLM的图片合成结果"
-
-  - name: "德_内蒙古银行照_PaddleOCR_VL_cell_bbox"
-    ocr_tool: "mineru"
-    ocr_out_dir: "/Users/zhch158/workspace/data/流水分析/德_内蒙古银行照/PaddleOCR_VL_Results_cell_bbox"
-    src_img_dir: "/Users/zhch158/workspace/data/流水分析/德_内蒙古银行照/PaddleOCR_VL_Results/德_内蒙古银行照"
-    description: "德_内蒙古银行照使用PaddleOCR VLM的图片合成结果, 整合PaddleOCR坐标"
-
-  - name: "德_内蒙古银行照"
-    ocr_tool: "mineru"
-    ocr_out_dir: "/Users/zhch158/workspace/data/流水分析/德_内蒙古银行照/mineru-vlm-2.5.3_Results"
-    src_img_dir: "/Users/zhch158/workspace/data/流水分析/德_内蒙古银行照/mineru-vlm-2.5.3_Results/德_内蒙古银行照"
-    description: "德_内蒙古银行照使用Mineru的图片合成结果"
-
-  - name: "德_内蒙古银行照_mineru_cell_bbox"
-    ocr_tool: "mineru"
-    ocr_out_dir: "/Users/zhch158/workspace/data/流水分析/德_内蒙古银行照/mineru-vlm-2.5.3_Results_cell_bbox"
-    src_img_dir: "/Users/zhch158/workspace/data/流水分析/德_内蒙古银行照/mineru-vlm-2.5.3_Results/德_内蒙古银行照"
-    description: "德_内蒙古银行照使用Mineru的图片合成结果, 整合PaddleOCR坐标"
-
-  - name: "德_内蒙古银行照"
-    ocr_tool: "dots_ocr"
-    ocr_out_dir: "/Users/zhch158/workspace/data/流水分析/德_内蒙古银行照/data_DotsOCR_Results"
-    src_img_dir: "/Users/zhch158/workspace/data/流水分析/德_内蒙古银行照/data_DotsOCR_Results/德_内蒙古银行照"
-    description: "德_内蒙古银行照使用Dots OCR的图片合成结果"
-
-  - name: "对公_招商银行图"
-    ocr_tool: "ppstructv3"
-    ocr_out_dir: "/Users/zhch158/workspace/data/流水分析/对公_招商银行图/data_PPStructureV3_Results"
-    src_img_dir: "/Users/zhch158/workspace/data/流水分析/对公_招商银行图/data_PPStructureV3_Results/对公_招商银行图"
-    description: "对公_招商银行图使用PPStructV3的图片合成结果"
-
-  - name: "对公_招商银行图_PaddleOCR_VL"
-    ocr_tool: "ppstructv3"
-    ocr_out_dir: "/Users/zhch158/workspace/data/流水分析/对公_招商银行图/PaddleOCR_VL_Results"
-    src_img_dir: "/Users/zhch158/workspace/data/流水分析/对公_招商银行图/PaddleOCR_VL_Results/对公_招商银行图"
-    description: "对公_招商银行图使用PaddleOCR VLM的图片合成结果"
-
-  - name: "对公_招商银行图_PaddleOCR_VL_cell_bbox"
-    ocr_tool: "mineru"
-    ocr_out_dir: "/Users/zhch158/workspace/data/流水分析/对公_招商银行图/PaddleOCR_VL_Results_cell_bbox"
-    src_img_dir: "/Users/zhch158/workspace/data/流水分析/对公_招商银行图/PaddleOCR_VL_Results/对公_招商银行图"
-    description: "对公_招商银行图使用PaddleOCR VLM的图片合成结果, 整合PaddleOCR坐标"
-
-  - name: "对公_招商银行图"
-    ocr_tool: "mineru"
-    ocr_out_dir: "/Users/zhch158/workspace/data/流水分析/对公_招商银行图/mineru-vlm-2.5.3_Results"
-    src_img_dir: "/Users/zhch158/workspace/data/流水分析/对公_招商银行图/mineru-vlm-2.5.3_Results/对公_招商银行图"
-    description: "对公_招商银行图使用Mineru的图片合成结果"
-
-  - name: "对公_招商银行图_mineru_cell_bbox"
-    ocr_tool: "mineru"
-    ocr_out_dir: "/Users/zhch158/workspace/data/流水分析/对公_招商银行图/mineru-vlm-2.5.3_Results_cell_bbox"
-    src_img_dir: "/Users/zhch158/workspace/data/流水分析/对公_招商银行图/mineru-vlm-2.5.3_Results/对公_招商银行图"
-    description: "对公_招商银行图使用Mineru的图片合成结果, 整合PaddleOCR坐标"
-
-  - name: "对公_招商银行图"
-    ocr_tool: "dots_ocr"
-    ocr_out_dir: "/Users/zhch158/workspace/data/流水分析/对公_招商银行图/data_DotsOCR_Results"
-    src_img_dir: "/Users/zhch158/workspace/data/流水分析/对公_招商银行图/data_DotsOCR_Results/对公_招商银行图"
-    description: "对公_招商银行图使用Dots OCR的图片合成结果"
-
-  - name: "A用户_单元格扫描流水"
-    ocr_tool: "ppstructv3"
-    ocr_out_dir: "/Users/zhch158/workspace/data/流水分析/A用户_单元格扫描流水/data_PPStructureV3_Results"
-    src_img_dir: "/Users/zhch158/workspace/data/流水分析/A用户_单元格扫描流水/data_PPStructureV3_Results/A用户_单元格扫描流水"
-    description: "A用户使用PPStructV3的单元格扫描结果"
-
-  - name: "A用户_单元格扫描流水_PaddleOCR_VL"
-    ocr_tool: "ppstructv3"
-    ocr_out_dir: "/Users/zhch158/workspace/data/流水分析/A用户_单元格扫描流水/PaddleOCR_VL_Results"
-    src_img_dir: "/Users/zhch158/workspace/data/流水分析/A用户_单元格扫描流水/PaddleOCR_VL_Results/A用户_单元格扫描流水"
-    description: "A用户使用PaddleOCR VLM的单元格扫描结果"
-
-  - name: "A用户_单元格扫描流水_PaddleOCR_VL_cell_bbox"
-    ocr_tool: "mineru"
-    ocr_out_dir: "/Users/zhch158/workspace/data/流水分析/A用户_单元格扫描流水/PaddleOCR_VL_Results_cell_bbox"
-    src_img_dir: "/Users/zhch158/workspace/data/流水分析/A用户_单元格扫描流水/PaddleOCR_VL_Results/A用户_单元格扫描流水"
-    description: "A用户使用PaddleOCR VLM的单元格扫描结果, 整合PaddleOCR坐标"
-
-  - name: "A用户_单元格扫描流水"
-    ocr_tool: "table_recognition_v2"
-    ocr_out_dir: "/Users/zhch158/workspace/data/流水分析/A用户_单元格扫描流水/table_recognition_v2_Results"
-    src_img_dir: "/Users/zhch158/workspace/data/流水分析/A用户_单元格扫描流水/data_PPStructureV3_Results/A用户_单元格扫描流水"
-    description: "A用户使用Table Recognition V2的单元格扫描结果"
-        
-  - name: "A用户_单元格扫描流水"
-    ocr_tool: "mineru"
-    ocr_out_dir: "/Users/zhch158/workspace/data/流水分析/A用户_单元格扫描流水/mineru-vlm-2.5.3_Results"
-    src_img_dir: "/Users/zhch158/workspace/data/流水分析/A用户_单元格扫描流水.img"
-    description: "A用户使用Mineru的识别结果"
-
-  - name: "A用户_单元格扫描流水_mineru_cell_bbox"
-    ocr_tool: "mineru"
-    ocr_out_dir: "/Users/zhch158/workspace/data/流水分析/A用户_单元格扫描流水/mineru-vlm-2.5.3_Results_cell_bbox"
-    src_img_dir: "/Users/zhch158/workspace/data/流水分析/A用户_单元格扫描流水.img"
-    description: "A用户使用Mineru VLM识别结果, 整合PaddleOCR坐标"
-
-  - name: "A用户_单元格扫描流水"
-    ocr_tool: "dots_ocr"
-    ocr_out_dir: "/Users/zhch158/workspace/data/流水分析/A用户_单元格扫描流水/data_DotsOCR_Results"
-    src_img_dir: "/Users/zhch158/workspace/data/流水分析/A用户_单元格扫描流水/data_DotsOCR_Results/A用户_单元格扫描流水"
-    description: "A用户使用Dots OCR的单元格扫描结果"
-    
-  - name: "B用户_扫描流水"
-    ocr_tool: "ppstructv3"
-    ocr_out_dir: "/Users/zhch158/workspace/data/流水分析/B用户_扫描流水/data_PPStructureV3_Results"
-    src_img_dir: "/Users/zhch158/workspace/data/流水分析/B用户_扫描流水/data_PPStructureV3_Results/B用户_扫描流水"
-    description: "B用户使用PPStructV3的扫描结果"
-
-  - name: "B用户_扫描流水_PaddleOCR_VL"
-    ocr_tool: "ppstructv3"
-    ocr_out_dir: "/Users/zhch158/workspace/data/流水分析/B用户_扫描流水/PaddleOCR_VL_Results"
-    src_img_dir: "/Users/zhch158/workspace/data/流水分析/B用户_扫描流水/PaddleOCR_VL_Results/B用户_扫描流水"
-    description: "B用户使用PaddleOCR VLM的扫描结果"
-
-  - name: "B用户_扫描流水_PaddleOCR_VL_cell_bbox"
-    ocr_tool: "mineru"
-    ocr_out_dir: "/Users/zhch158/workspace/data/流水分析/B用户_扫描流水/PaddleOCR_VL_Results_cell_bbox"
-    src_img_dir: "/Users/zhch158/workspace/data/流水分析/B用户_扫描流水/PaddleOCR_VL_Results/B用户_扫描流水"
-    description: "B用户使用PaddleOCR VLM的扫描结果, 整合PaddleOCR坐标"
-
-  - name: "B用户_扫描流水"
-    ocr_tool: "mineru"
-    ocr_out_dir: "/Users/zhch158/workspace/data/流水分析/B用户_扫描流水/mineru-vlm-2.5.3_Results"
-    src_img_dir: "/Users/zhch158/workspace/data/流水分析/B用户_扫描流水.img"
-    description: "B用户使用Mineru的扫描结果"
-
-  - name: "B用户_扫描流水_mineru_cell_bbox"
-    ocr_tool: "mineru"
-    ocr_out_dir: "/Users/zhch158/workspace/data/流水分析/B用户_扫描流水/mineru-vlm-2.5.3_Results_cell_bbox"
-    src_img_dir: "/Users/zhch158/workspace/data/流水分析/B用户_扫描流水.img"
-    description: "B用户使用Mineru的扫描结果, 整合PaddleOCR坐标"
-
-  - name: "B用户_扫描流水"
-    ocr_tool: "dots_ocr"
-    ocr_out_dir: "/Users/zhch158/workspace/data/流水分析/B用户_扫描流水/data_DotsOCR_Results"
-    src_img_dir: "/Users/zhch158/workspace/data/流水分析/B用户_扫描流水/data_DotsOCR_Results/B用户_扫描流水"
-    description: "B用户使用Dots OCR的扫描结果"
-
-  - name: "至远彩色_2023年报"
-    ocr_tool: "ppstructv3"
-    ocr_out_dir: "/Users/zhch158/workspace/data/至远彩色印刷工业有限公司/data_PPStructureV3_Results"
-    src_img_dir: "/Users/zhch158/workspace/data/至远彩色印刷工业有限公司/data_PPStructureV3_Results/2023年度报告母公司"
-    description: "至远彩色使用PPStructV3的2023年报"
-
-  - name: "至远彩色_2023年报_PaddleOCR"
-    ocr_tool: "ppstructv3"
-    ocr_out_dir: "/Users/zhch158/workspace/data/至远彩色印刷工业有限公司/PaddleOCR_VL_Results"
-    src_img_dir: "/Users/zhch158/workspace/data/至远彩色印刷工业有限公司/PaddleOCR_VL_Results/2023年度报告母公司"
-    description: "至远彩色使用PaddleOCR VLM的2023年报"
-
-  - name: "至远彩色_2023年报_PaddleOCR_cell_bbox"
-    ocr_tool: "mineru"
-    ocr_out_dir: "/Users/zhch158/workspace/data/至远彩色印刷工业有限公司/PaddleOCR_VL_Results_cell_bbox"
-    src_img_dir: "/Users/zhch158/workspace/data/至远彩色印刷工业有限公司/PaddleOCR_VL_Results/2023年度报告母公司"
-    description: "至远彩色使用PaddleOCR VLM的2023年报, 整合PaddleOCR坐标"
-
-  - name: "至远彩色_2023年报"
-    ocr_tool: "mineru"
-    ocr_out_dir: "/Users/zhch158/workspace/data/至远彩色印刷工业有限公司/mineru-vlm-2.5.3_Results"
-    src_img_dir: "/Users/zhch158/workspace/data/至远彩色印刷工业有限公司/mineru-vlm-2.5.3_Results/2023年度报告母公司"
-    description: "至远彩色使用mineru的2023年报"
-
-  - name: "至远彩色_2023年报_mineru_cell_bbox"
-    ocr_tool: "mineru"
-    ocr_out_dir: "/Users/zhch158/workspace/data/至远彩色印刷工业有限公司/mineru-vlm-2.5.3_Results_cell_bbox"
-    src_img_dir: "/Users/zhch158/workspace/data/至远彩色印刷工业有限公司/mineru-vlm-2.5.3_Results/2023年度报告母公司"
-    description: "至远彩色使用mineru的2023年报, 整合PaddleOCR坐标"
-
-  - name: "至远彩色_2023年报"
-    ocr_tool: "dots_ocr"
-    ocr_out_dir: "/Users/zhch158/workspace/data/至远彩色印刷工业有限公司/data_DotsOCR_Results"
-    src_img_dir: "/Users/zhch158/workspace/data/至远彩色印刷工业有限公司/data_DotsOCR_Results/2023年度报告母公司"
-    description: "至远彩色使用Dots OCR的2023年报"
-
-# 预校验结果文件路径
-pre_validation:
-  out_dir: "./output/pre_validation/"
-

+ 479 - 0
config/README.md

@@ -0,0 +1,479 @@
+# 📋 配置文件说明
+
+本目录包含 OCR 验证系统的所有配置文件,用于管理数据源、OCR 工具参数和项目特定配置。
+
+## 📁 文件结构
+
+```
+config/
+├── global.yaml                    # 全局配置(必需)
+├── 至远彩色_2023年报.yaml         # 年报类项目配置
+├── A用户_单元格扫描流水.yaml      # 流水表格配置
+├── B用户_扫描流水.yaml            # 流水表格配置
+├── 德_内蒙古银行照.yaml           # 银行流水配置
+├── 对公_招商银行图.yaml           # 银行流水配置
+└── README.md                      # 配置文档(本文件)
+```
+
+## 🔧 配置文件类型
+
+### 1. 全局配置 (`global.yaml`)
+
+**用途**:引用所有项目特定配置文件,作为配置入口。
+
+**示例**:
+
+```yaml
+data_sources:
+  - 德_内蒙古银行照.yaml
+  - 对公_招商银行图.yaml
+  - A用户_单元格扫描流水.yaml
+  - B用户_扫描流水.yaml
+  - 至远彩色_2023年报.yaml
+```
+
+**说明**:
+- 全局配置文件仅列出需要加载的项目配置文件
+- 每个项目的具体配置在单独的 YAML 文件中
+- 系统启动时会自动加载所有引用的配置文件
+
+### 2. 项目特定配置
+
+**用途**:定义每个项目的文档信息和 OCR 工具结果路径。
+
+#### 配置结构说明
+
+```yaml
+document:
+  name: "项目名称"
+  base_dir: "/绝对路径/到/项目根目录"
+  
+  ocr_results:
+    - tool: "工具标识"
+      result_dir: "结果目录名"
+      image_dir: "图像目录路径(支持模板变量)"
+      description: "工具描述"
+      enabled: true/false
+```
+
+#### 模板变量
+
+配置文件支持以下模板变量:
+
+| 变量 | 说明 | 示例 |
+|------|------|------|
+| `{{name}}` | 项目名称(来自 `document.name`) | `"B用户_扫描流水"` |
+
+**示例**:
+```yaml
+image_dir: "paddleocr_vl_results/{{name}}"
+# 实际路径:paddleocr_vl_results/B用户_扫描流水
+```
+
+## 📝 配置参数详解
+
+### 文档配置 (`document`)
+
+| 参数 | 类型 | 必需 | 说明 | 示例 |
+|------|------|------|------|------|
+| `name` | string | ✅ | 项目名称 | `"B用户_扫描流水"` |
+| `base_dir` | string | ✅ | 项目根目录(绝对路径) | `"/Users/zhch158/workspace/data/流水分析/B用户_扫描流水"` |
+
+### OCR 结果配置 (`ocr_results`)
+
+| 参数 | 类型 | 必需 | 说明 | 示例 |
+|------|------|------|------|------|
+| `tool` | string | ✅ | OCR 工具标识 | `"ppstructv3"` / `"paddleocr_vl"` / `"mineru"` / `"dots_ocr"` |
+| `result_dir` | string | ✅ | OCR 结果目录(相对于 `base_dir`) | `"ppstructurev3_client_results"` |
+| `image_dir` | string | ✅ | 图像目录路径(支持模板变量 `{{name}}`) | `"ppstructurev3_client_results/{{name}}` |
+| `description` | string | ✅ | 工具描述 | `"PPStructV3 图片合成结果"` |
+| `enabled` | boolean | ✅ | 是否启用该数据源 | `true` / `false` |
+
+### 支持的 OCR 工具标识
+
+| 工具标识 | 工具名称 | 适用场景 |
+|---------|---------|---------|
+| `ppstructv3` | PPStructV3 | 结构化文档、表格 |
+| `paddleocr_vl` | PaddleOCR-VL | VLM 文档理解 |
+| `mineru` | MinerU | VLM 表格识别 |
+| `dots_ocr` | Dots OCR | VLM 专业识别 |
+
+**说明**:
+- `mineru` 工具标识也用于 PaddleOCR-VL、Dots OCR 等工具的合并结果
+- 当 `result_dir` 包含 `cell_bbox` 时,表示该结果已与 PaddleOCR 坐标合并
+
+## 🎯 配置示例
+
+### 示例 1:流水表格配置 (`B用户_扫描流水.yaml`)
+
+```yaml
+document:
+  name: "B用户_扫描流水"
+  base_dir: "/Users/zhch158/workspace/data/流水分析/B用户_扫描流水"
+  
+  ocr_results:
+    # PPStructV3
+    - tool: "ppstructv3"
+      result_dir: "ppstructurev3_client_results"
+      image_dir: "ppstructurev3_client_results/{{name}}"
+      description: "PPStructV3 图片合成结果"
+      enabled: true
+    
+    # PaddleOCR-VL
+    - tool: "paddleocr_vl"
+      result_dir: "paddleocr_vl_results"
+      image_dir: "paddleocr_vl_results/{{name}}"
+      description: "PaddleOCR VLM 图片合成结果"
+      enabled: true
+    
+    # PaddleOCR-VL (带 cell bbox)
+    - tool: "mineru"  # 格式同 MinerU
+      result_dir: "paddleocr_vl_results_cell_bbox"
+      image_dir: "paddleocr_vl_results/{{name}}"
+      description: "PaddleOCR VLM + PaddleOCR 坐标"
+      enabled: true
+    
+    # MinerU
+    - tool: "mineru"
+      result_dir: "mineru_vllm_results"
+      image_dir: "mineru_vllm_results/{{name}}"
+      description: "MinerU 图片合成结果"
+      enabled: true
+    
+    # MinerU (带 cell bbox)
+    - tool: "mineru"
+      result_dir: "mineru_vllm_results_cell_bbox"
+      image_dir: "mineru_vllm_results/{{name}}"
+      description: "MinerU + PaddleOCR 坐标"
+      enabled: true
+    
+    # DotsOCR
+    - tool: "dots_ocr"
+      result_dir: "dotsocr_vllm_results"
+      image_dir: "dotsocr_vllm_results/{{name}}"
+      description: "Dots OCR 图片合成结果"
+      enabled: true
+  
+    # DotsOCR (带 cell bbox)
+    - tool: "mineru"
+      result_dir: "dotsocr_vllm_results_cell_bbox"
+      image_dir: "dotsocr_vllm_results/{{name}}"
+      description: "Dots OCR + PaddleOCR 坐标"
+      enabled: true
+```
+
+**目录结构**:
+```
+/Users/zhch158/workspace/data/流水分析/B用户_扫描流水/
+├── ppstructurev3_client_results/
+│   └── B用户_扫描流水/              # {{name}} 替换后
+│       └── *.jpg
+├── paddleocr_vl_results/
+│   └── B用户_扫描流水/
+│       └── *.jpg
+├── paddleocr_vl_results_cell_bbox/
+│   └── *.json
+├── mineru_vllm_results/
+│   └── B用户_扫描流水/
+│       └── *.jpg
+├── mineru_vllm_results_cell_bbox/
+│   └── *.json
+├── dotsocr_vllm_results/
+│   └── B用户_扫描流水/
+│       └── *.jpg
+└── dotsocr_vllm_results_cell_bbox/
+    └── *.json
+```
+
+## 🛠️ 配置最佳实践
+
+### 1. 目录结构规范
+
+```
+项目根目录/
+├── data/
+│   └── 流水分析/
+│       └── B用户_扫描流水/                    # base_dir
+│           ├── ppstructurev3_client_results/  # result_dir
+│           │   ├── B用户_扫描流水/            # image_dir ({{name}})
+│           │   │   ├── page_001.jpg
+│           │   │   └── page_002.jpg
+│           │   └── *.json
+│           ├── paddleocr_vl_results/
+│           │   ├── B用户_扫描流水/
+│           │   │   └── *.jpg
+│           │   └── *.json
+│           └── mineru_vllm_results_cell_bbox/
+│               └── *.json
+└── ocr_verify/
+    └── config/
+        ├── global.yaml
+        └── B用户_扫描流水.yaml
+```
+
+### 2. 路径配置建议
+
+- **使用绝对路径**:`base_dir` 必须是绝对路径
+- **result_dir 使用相对路径**:相对于 `base_dir`
+- **image_dir 支持模板变量**:使用 `{{name}}` 引用项目名称
+- **路径分隔符**:统一使用 `/`
+
+### 3. 工具选择建议
+
+| 场景 | 推荐工具组合 | 配置示例 |
+|------|-------------|---------|
+| 财务报表 | MinerU + MinerU (cell bbox) | `tool: "mineru"` + `result_dir` 包含 `cell_bbox` |
+| 银行流水 | Dots OCR + PaddleOCR-VL | `tool: "dots_ocr"` + `tool: "paddleocr_vl"` |
+| 复杂表格 | 多工具交叉验证 | 启用所有 `enabled: true` 的工具 |
+
+### 4. 模板变量使用
+
+**支持的位置**:
+- `image_dir` 路径中
+
+**变量来源**:
+- `{{name}}`:来自 `document.name`
+
+**示例**:
+```yaml
+document:
+  name: "B用户_扫描流水"
+  
+ocr_results:
+  - image_dir: "paddleocr_vl_results/{{name}}"
+    # 实际路径:paddleocr_vl_results/B用户_扫描流水
+```
+
+### 5. 合并结果配置
+
+当使用合并工具(如 `merge_mineru_paddle_ocr.py`)生成带坐标的结果时:
+
+```yaml
+ocr_results:
+  # 原始 MinerU 结果
+  - tool: "mineru"
+    result_dir: "mineru_vllm_results"
+    image_dir: "mineru_vllm_results/{{name}}"
+    description: "MinerU 图片合成结果"
+    enabled: true
+  
+  # 合并后的结果(MinerU + PaddleOCR 坐标)
+  - tool: "mineru"
+    result_dir: "mineru_vllm_results_cell_bbox"
+    image_dir: "mineru_vllm_results/{{name}}"
+    description: "MinerU + PaddleOCR 坐标"
+    enabled: true
+```
+
+**说明**:
+- 合并结果后的`tool` 统一到**mineru**格式的工具
+- `result_dir` 使用不同的目录名(通常包含 `cell_bbox`)
+- `image_dir` 可以复用原始工具的图像路径
+
+## 🔍 添加新项目配置
+
+### 步骤 1:创建文档配置文件
+
+在 `config/` 目录下创建新的 YAML 文件,如 `新文档名.yaml`:
+
+```yaml
+document:
+  name: "新文档名"
+  base_dir: "/绝对路径/到/新项目"
+  
+  ocr_results:
+    - tool: "ppstructv3"
+      result_dir: "ppstructv3_results"
+      image_dir: "ppstructv3_results/{{name}}"
+      description: "PPStructV3 识别结果"
+      enabled: true
+    
+    - tool: "mineru"
+      result_dir: "mineru_results"
+      image_dir: "mineru_results/{{name}}"
+      description: "MinerU 识别结果"
+      enabled: true
+```
+
+### 步骤 2:在 global.yaml 中引用
+
+编辑 `global.yaml`,添加新配置文件:
+
+```yaml
+data_sources:
+  - 德_内蒙古银行照.yaml
+  - 对公_招商银行图.yaml
+  - A用户_单元格扫描流水.yaml
+  - B用户_扫描流水.yaml
+  - 至远彩色_2023年报.yaml
+  - 新文档名.yaml          # 新增
+```
+
+### 步骤 3:验证配置
+
+```bash
+# 验证 YAML 语法
+python -c "import yaml; yaml.safe_load(open('config/新文档名.yaml'))"
+
+# 启动应用测试
+python -m streamlit run streamlit_ocr_validator.py
+```
+
+## 🔧 调试配置
+
+### 验证配置文件语法
+
+```bash
+# 验证单个配置文件
+python -c "import yaml; yaml.safe_load(open('config/B用户_扫描流水.yaml'))"
+
+# 验证全局配置
+python -c "import yaml; yaml.safe_load(open('config/global.yaml'))"
+
+# 查看解析后的配置
+python -c "
+import yaml
+with open('config/B用户_扫描流水.yaml') as f:
+    config = yaml.safe_load(f)
+    print(yaml.dump(config, default_flow_style=False, allow_unicode=True))
+"
+```
+
+### 检查路径有效性
+
+```bash
+# macOS/Linux
+ls -la /Users/zhch158/workspace/data/流水分析/B用户_扫描流水
+
+# 检查结果目录
+ls -la /Users/zhch158/workspace/data/流水分析/B用户_扫描流水/ppstructurev3_client_results
+
+# 检查图像目录(替换模板变量后)
+ls -la /Users/zhch158/workspace/data/流水分析/B用户_扫描流水/ppstructurev3_client_results/B用户_扫描流水
+```
+
+## 🐛 常见问题
+
+### Q1: 配置文件不生效?
+
+**A:** 
+1. 检查 `global.yaml` 中是否正确引用了项目配置文件
+2. 确认 YAML 语法正确(缩进必须用空格,不能用 Tab)
+3. 确保配置文件在 `config/` 目录下
+4. 重启 Streamlit 应用
+
+### Q2: 找不到 OCR 输出文件?
+
+**A:** 
+- 检查 `base_dir` 路径是否正确(必须是绝对路径)
+- 检查 `result_dir` 是否存在于 `base_dir` 下
+- 确认 `image_dir` 的模板变量 `{{name}}` 是否正确替换
+- 确保目录存在且包含 JSON 和图像文件
+
+### Q3: 模板变量未替换?
+
+**A:** 
+- 确认使用了正确的模板变量语法:`{{name}}`
+- 检查 `document.name` 是否已定义
+- 查看 Streamlit 控制台的路径解析日志
+
+### Q4: 合并结果无法加载?
+
+**A:** 
+- 确认合并结果的 `result_dir` 存在
+- 检查 `tool` 标识是否正确(通常与原始工具一致)
+- 确保 `enabled: true`
+
+### Q5: enabled 参数的作用?
+
+**A:** 
+- `enabled: true`:该数据源会显示在 Streamlit 数据源列表中
+- `enabled: false`:该数据源不会加载,但配置保留(方便临时禁用)
+
+## 📚 参考资料
+
+- [主项目 README](../README.md) - 系统总览
+- [Comparator 模块文档](../comparator/README.md) - 对比算法详解
+- [Merger 模块文档](../merger/README.md) - OCR 结果合并
+- [Batch OCR 模块文档](../batch_ocr/README.md) - 批量处理工具
+
+## 📋 配置文件模板
+
+### 基础模板
+
+```yaml
+document:
+  name: "项目名称"
+  base_dir: "/绝对路径/到/项目根目录"
+  
+  ocr_results:
+    - tool: "工具标识"
+      result_dir: "结果目录名"
+      image_dir: "图像目录路径"
+      description: "工具描述"
+      enabled: true
+```
+
+### 多工具模板
+
+```yaml
+document:
+  name: "项目名称"
+  base_dir: "/绝对路径/到/项目根目录"
+  
+  ocr_results:
+    # PPStructV3
+    - tool: "ppstructv3"
+      result_dir: "ppstructv3_results"
+      image_dir: "ppstructv3_results/{{name}}"
+      description: "PPStructV3 识别结果"
+      enabled: true
+    
+    # PaddleOCR-VL
+    - tool: "paddleocr_vl"
+      result_dir: "paddleocr_vl_results"
+      image_dir: "paddleocr_vl_results/{{name}}"
+      description: "PaddleOCR-VL 识别结果"
+      enabled: true
+    
+    # MinerU
+    - tool: "mineru"
+      result_dir: "mineru_results"
+      image_dir: "mineru_results/{{name}}"
+      description: "MinerU 识别结果"
+      enabled: true
+    
+    # Dots OCR
+    - tool: "dots_ocr"
+      result_dir: "dotsocr_results"
+      image_dir: "dotsocr_results/{{name}}"
+      description: "Dots OCR 识别结果"
+      enabled: true
+```
+
+### 包含合并结果的模板
+
+```yaml
+document:
+  name: "项目名称"
+  base_dir: "/绝对路径/到/项目根目录"
+  
+  ocr_results:
+    # 原始结果
+    - tool: "mineru"
+      result_dir: "mineru_results"
+      image_dir: "mineru_results/{{name}}"
+      description: "MinerU 原始结果"
+      enabled: true
+    
+    # 合并结果(带 cell bbox)
+    - tool: "mineru"
+      result_dir: "mineru_results_cell_bbox"
+      image_dir: "mineru_results/{{name}}"
+      description: "MinerU + PaddleOCR 坐标"
+      enabled: true
+```
+
+---
+
+**最后更新**: 2025年11月7日

+ 1 - 1
streamlit_validator_result.py

@@ -205,7 +205,7 @@ def _display_differences_dataframe(comparison_result: dict):
             return 'background-color: #e8f5e8; color: #2e7d32'
         return ''
     
-    styled_df = df_differences.style.applymap(
+    styled_df = df_differences.style.map(
         highlight_severity, 
         subset=['严重程度']
     ).format({'序号': '{:d}'})