# Invoice Master POC v2 自动发票字段提取系统 - 使用 YOLOv11 + PaddleOCR 从瑞典 PDF 发票中提取结构化数据。 ## 项目概述 本项目实现了一个完整的发票字段自动提取流程: 1. **自动标注**: 利用已有 CSV 结构化数据 + OCR 自动生成 YOLO 训练标注 2. **模型训练**: 使用 YOLOv11 训练字段检测模型 3. **推理提取**: 检测字段区域 -> OCR 提取文本 -> 字段规范化 ### 架构 项目采用 **monorepo + 三包分离** 架构,训练和推理可独立部署: ``` packages/ ├── shared/ # 共享库 (PDF, OCR, 规范化, 匹配, 工具) ├── training/ # 训练服务 (GPU, 按需启动) └── inference/ # 推理服务 (常驻运行) ``` | 服务 | 部署目标 | GPU | 生命周期 | |------|---------|-----|---------| | **Inference** | Azure App Service | 可选 | 常驻 7x24 | | **Training** | Azure ACI | 必需 | 按需启动/销毁 | 两个服务通过共享 PostgreSQL 数据库通信。推理服务通过 API 触发训练任务,训练服务从数据库拾取任务执行。 ### 当前进度 | 指标 | 数值 | |------|------| | **已标注文档** | 9,738 (9,709 成功) | | **总体字段匹配率** | 94.8% (82,604/87,121) | | **测试** | 922 passed | | **模型 mAP@0.5** | 93.5% | **各字段匹配率:** | 字段 | 匹配率 | 说明 | |------|--------|------| | supplier_accounts(Bankgiro) | 100.0% | 供应商 Bankgiro | | supplier_accounts(Plusgiro) | 100.0% | 供应商 Plusgiro | | Plusgiro | 99.4% | 支付 Plusgiro | | OCR | 99.1% | OCR 参考号 | | Bankgiro | 99.0% | 支付 Bankgiro | | InvoiceNumber | 98.9% | 发票号码 | | InvoiceDueDate | 95.9% | 到期日期 | | InvoiceDate | 95.5% | 发票日期 | | Amount | 91.3% | 金额 | | supplier_organisation_number | 78.2% | 供应商组织号 (CSV 数据质量问题) | ## 运行环境 本项目**必须**在 **WSL + Conda** 环境中运行。 ### 系统要求 | 环境 | 要求 | |------|------| | **WSL** | WSL 2 + Ubuntu 22.04 | | **Conda** | Miniconda 或 Anaconda | | **Python** | 3.11+ (通过 Conda 管理) | | **GPU** | NVIDIA GPU + CUDA 12.x (强烈推荐) | | **数据库** | PostgreSQL (存储标注结果) | ## 安装 ```bash # 1. 进入 WSL wsl -d Ubuntu-22.04 # 2. 创建 Conda 环境 conda create -n invoice-py311 python=3.11 -y conda activate invoice-py311 # 3. 进入项目目录 cd /mnt/c/Users/yaoji/git/ColaCoder/invoice-master-poc-v2 # 4. 安装三个包 (editable mode) pip install -e packages/shared pip install -e packages/training pip install -e packages/inference ``` ## 项目结构 ``` invoice-master-poc-v2/ ├── packages/ │ ├── shared/ # 共享库 │ │ ├── setup.py │ │ └── shared/ │ │ ├── pdf/ # PDF 处理 (提取, 渲染, 检测) │ │ ├── ocr/ # PaddleOCR 封装 + 机器码解析 │ │ ├── normalize/ # 字段规范化 (10 种 normalizer) │ │ ├── matcher/ # 字段匹配 (精确/子串/模糊) │ │ ├── utils/ # 工具 (验证, 清理, 模糊匹配) │ │ ├── data/ # DocumentDB, CSVLoader │ │ ├── config.py # 全局配置 (数据库, 路径, DPI) │ │ └── exceptions.py # 异常定义 │ │ │ ├── training/ # 训练服务 (GPU, 按需) │ │ ├── setup.py │ │ ├── Dockerfile │ │ ├── run_training.py # 入口 (--task-id 或 --poll) │ │ └── training/ │ │ ├── cli/ # train, autolabel, analyze_*, validate │ │ ├── yolo/ # db_dataset, annotation_generator │ │ ├── processing/ # CPU/GPU worker pool, task dispatcher │ │ └── data/ # training_db, autolabel_report │ │ │ └── inference/ # 推理服务 (常驻) │ ├── setup.py │ ├── Dockerfile │ ├── run_server.py # Web 服务器入口 │ └── inference/ │ ├── cli/ # infer, serve │ ├── pipeline/ # YOLO 检测, 字段提取, 解析器 │ ├── web/ # FastAPI 应用 │ │ ├── api/v1/ # REST API (admin, public, batch) │ │ ├── schemas/ # Pydantic 数据模型 │ │ ├── services/ # 业务逻辑 │ │ ├── core/ # 认证, 调度器, 限流 │ │ └── workers/ # 后台任务队列 │ ├── validation/ # LLM 验证器 │ ├── data/ # AdminDB, AsyncRequestDB, Models │ └── azure/ # ACI 训练触发器 │ ├── migrations/ # 数据库迁移 │ ├── 001_async_tables.sql │ ├── 002_nullable_admin_token.sql │ └── 003_training_tasks.sql ├── frontend/ # React 前端 (Vite + TypeScript) ├── tests/ # 测试 (922 tests) ├── docker-compose.yml # 本地开发 (postgres + inference + training) ├── run_server.py # 快捷启动脚本 └── runs/train/ # 训练输出 (weights, curves) ``` ## 支持的字段 | 类别 ID | 字段名 | 说明 | |---------|--------|------| | 0 | invoice_number | 发票号码 | | 1 | invoice_date | 发票日期 | | 2 | invoice_due_date | 到期日期 | | 3 | ocr_number | OCR 参考号 (瑞典支付系统) | | 4 | bankgiro | Bankgiro 号码 | | 5 | plusgiro | Plusgiro 号码 | | 6 | amount | 金额 | | 7 | supplier_organisation_number | 供应商组织号 | | 8 | payment_line | 支付行 (机器可读格式) | | 9 | customer_number | 客户编号 | ## 快速开始 ### 1. 自动标注 ```bash # 使用双池模式 (CPU + GPU) python -m training.cli.autolabel \ --dual-pool \ --cpu-workers 3 \ --gpu-workers 1 # 单线程模式 python -m training.cli.autolabel --workers 4 ``` ### 2. 训练模型 ```bash # 从预训练模型开始训练 python -m training.cli.train \ --model yolo11n.pt \ --epochs 100 \ --batch 16 \ --name invoice_fields \ --dpi 150 # 低内存模式 python -m training.cli.train \ --model yolo11n.pt \ --epochs 100 \ --name invoice_fields \ --low-memory # 从检查点恢复训练 python -m training.cli.train \ --model runs/train/invoice_fields/weights/last.pt \ --epochs 100 \ --name invoice_fields \ --resume ``` ### 3. 推理 ```bash # 命令行推理 python -m inference.cli.infer \ --model runs/train/invoice_fields/weights/best.pt \ --input path/to/invoice.pdf \ --output result.json \ --gpu ``` ### 4. Web 应用 ```bash # 从 Windows PowerShell 启动 wsl bash -c "source ~/miniconda3/etc/profile.d/conda.sh && conda activate invoice-py311 && cd /mnt/c/Users/yaoji/git/ColaCoder/invoice-master-poc-v2 && python run_server.py --port 8000" # 启动前端 cd frontend && npm install && npm run dev # 访问 http://localhost:5173 ``` ### 5. Docker 本地开发 ```bash docker-compose up # inference: http://localhost:8000 # training: 轮询模式自动拾取任务 ``` ## 训练触发流程 推理服务通过 API 触发训练,训练在独立的 GPU 实例上执行: ``` Inference API PostgreSQL Training (ACI) | | | POST /admin/training/trigger | | |-> INSERT training_tasks ------>| status=pending | |-> Azure SDK: create ACI --------------------------------> 启动 | | | | |<-- SELECT pending -----+ | |--- UPDATE running -----+ | | 执行训练... | |<-- UPDATE completed ---+ | | + model_path | | | + metrics 自动关机 | | | GET /admin/training/{id} | | |-> SELECT training_tasks ------>| | +-- return status + metrics | | ``` ## Web API 端点 **Public API:** | 方法 | 端点 | 描述 | |------|------|------| | GET | `/api/v1/health` | 健康检查 | | POST | `/api/v1/infer` | 上传文件并推理 | | GET | `/api/v1/results/{filename}` | 获取可视化图片 | | POST | `/api/v1/async/infer` | 异步推理 | | GET | `/api/v1/async/status/{task_id}` | 查询异步任务状态 | **Admin API** (需要 `X-Admin-Token` header): | 方法 | 端点 | 描述 | |------|------|------| | POST | `/api/v1/admin/auth/login` | 管理员登录 | | GET | `/api/v1/admin/documents` | 文档列表 | | POST | `/api/v1/admin/documents/upload` | 上传 PDF | | GET | `/api/v1/admin/documents/{id}` | 文档详情 | | PATCH | `/api/v1/admin/documents/{id}/status` | 更新文档状态 | | POST | `/api/v1/admin/documents/{id}/annotations` | 创建标注 | | POST | `/api/v1/admin/training/trigger` | 触发训练任务 | | GET | `/api/v1/admin/training/{id}/status` | 查询训练状态 | ## Python API ```python from inference.pipeline import InferencePipeline # 初始化 pipeline = InferencePipeline( model_path='runs/train/invoice_fields/weights/best.pt', confidence_threshold=0.25, use_gpu=True, dpi=150, enable_fallback=True ) # 处理 PDF result = pipeline.process_pdf('invoice.pdf') print(result.fields) # {'InvoiceNumber': '12345', 'Amount': '1234.56', ...} print(result.confidence) # {'InvoiceNumber': 0.95, 'Amount': 0.92, ...} # 交叉验证 if result.cross_validation: print(f"OCR match: {result.cross_validation.ocr_match}") ``` ```python from inference.pipeline.payment_line_parser import PaymentLineParser from inference.pipeline.customer_number_parser import CustomerNumberParser # Payment Line 解析 parser = PaymentLineParser() result = parser.parse("# 94228110015950070 # 15658 00 8 > 48666036#14#") print(f"OCR: {result.ocr_number}, Amount: {result.amount}") # Customer Number 解析 parser = CustomerNumberParser() result = parser.parse("Said, Shakar Umj 436-R Billo") print(f"Customer Number: {result}") # "UMJ 436-R" ``` ## DPI 配置 系统所有组件统一使用 **150 DPI**。DPI 必须在训练和推理时保持一致。 | 组件 | 配置位置 | |------|---------| | 全局常量 | `packages/shared/shared/config.py` -> `DEFAULT_DPI = 150` | | Web 推理 | `packages/inference/inference/web/config.py` -> `ModelConfig.dpi` | | CLI 推理 | `python -m inference.cli.infer --dpi 150` | | 自动标注 | `packages/shared/shared/config.py` -> `AUTOLABEL['dpi']` | ## 数据库架构 | 数据库 | 用途 | 存储内容 | |--------|------|----------| | **PostgreSQL** | 标注结果 | `documents`, `field_results`, `training_tasks` | | **SQLite** (AdminDB) | Web 应用 | 文档管理, 标注编辑, 用户认证 | ## 测试 ```bash # 运行所有测试 DB_PASSWORD=xxx pytest tests/ -q # 运行并查看覆盖率 DB_PASSWORD=xxx pytest tests/ --cov=packages --cov-report=term-missing ``` | 指标 | 数值 | |------|------| | **测试总数** | 922 | | **通过率** | 100% | ## 技术栈 | 组件 | 技术 | |------|------| | **目标检测** | YOLOv11 (Ultralytics) | | **OCR 引擎** | PaddleOCR v5 (PP-OCRv5) | | **PDF 处理** | PyMuPDF (fitz) | | **数据库** | PostgreSQL + psycopg2 | | **Web 框架** | FastAPI + Uvicorn | | **深度学习** | PyTorch + CUDA 12.x | | **部署** | Docker + Azure ACI (训练) / App Service (推理) | ## 许可证 MIT License