From 9be71bfb7bfd4a6b28ce40bbe4e4410d4bc11d07 Mon Sep 17 00:00:00 2001 From: kang Date: Mon, 13 Apr 2026 18:25:23 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=20MinerU=20?= =?UTF-8?q?=E6=BA=90=E7=A0=81=E8=A7=A3=E6=9E=90=E9=A1=B9=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - .memory/source-analysis.md: 830 行技术报告,覆盖 VLM/Pipeline/Hybrid/Office 四后端 - docs-site/: 展示站点 (nginx:alpine + 单页 index.html) - 源码浅克隆到 source/ (gitignored) --- .gitignore | 4 + .memory/source-analysis.md | 830 +++++++++++++++++++++++++++++++++++ docs-site/Dockerfile | 3 + docs-site/index.html | 856 +++++++++++++++++++++++++++++++++++++ 4 files changed, 1693 insertions(+) create mode 100644 .gitignore create mode 100644 .memory/source-analysis.md create mode 100644 docs-site/Dockerfile create mode 100644 docs-site/index.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..128f2c5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +source/ +.DS_Store +*.pyc +__pycache__/ diff --git a/.memory/source-analysis.md b/.memory/source-analysis.md new file mode 100644 index 0000000..515706d --- /dev/null +++ b/.memory/source-analysis.md @@ -0,0 +1,830 @@ +# MinerU 3.0 源码全景技术分析报告 + +> 分析日期: 2026-04-13 +> 源码版本: MinerU 3.0.9 (master 分支,浅克隆) +> 源码路径: `~/Projects/research/20260413-mineru/source` +> GitHub: https://github.com/opendatalab/MinerU (59.5k stars) + +--- + +## 1. 项目总览与架构基础 + +### 版本与依赖体系 + +**版本号**: 3.0.9 (`mineru/version.py:1`) + +**Python 支持范围**: >=3.10,<3.14 (`pyproject.toml:11`) + +MinerU 是 opendatalab 的 PDF→Markdown/JSON 的文档解析工具,支持三大处理后端(Pipeline/VLM/Hybrid+Office)。核心依赖体系分层设计: + +1. **基础层** (`pyproject.toml:20-55`): + - PDF处理: `pypdfium2>=4.30.0`, `pypdf>=5.6.0`, `pdfminer.six>=20251230` + - 文档: `python-docx>=1.2.0`, `mammoth>=1.11.0` + - 数据科学: `numpy>=1.21.6`, `pandas>=2.3.3`, `opencv-python>=4.11.0.86` + - 语言检测: `fast-langdetect>=0.2.3,<0.3.0` + - 文件类型检测: `magika>=0.6.2,<1.1.0` + - 服务: `fastapi`, `uvicorn`, `httpx` + +2. **后端选择依赖** (`pyproject.toml:57-107`): + - `[vlm]`: `torch>=2.6.0,<3`, `transformers>=4.57.3,<5` + - `[vllm]`: `vllm>=0.10.1.1,<0.12` + - `[lmdeploy]`: `lmdeploy>=0.10.2,<0.12` + - `[mlx]` (macOS): `mlx-vlm>=0.3.3,<0.4` + - `[pipeline]`: 完整 ML 栈(torch, torchvision, transformers, onnxruntime, albumentations) + +### 入口点与 CLI 命令体系 + +`pyproject.toml:114-122` 定义了 7 个 CLI 入口: + +``` +mineru = "mineru.cli.client:main" # 主 CLI +mineru-vllm-server = "mineru.cli.vlm_server:vllm_server" # vLLM 服务 +mineru-lmdeploy-server = "mineru.cli.vlm_server:lmdeploy_server" +mineru-openai-server = "mineru.cli.vlm_server:openai_server" +mineru-models-download = "mineru.cli.models_download:download_models" +mineru-api = "mineru.cli.fast_api:main" # FastAPI 服务器 +mineru-router = "mineru.cli.router:main" # 异步路由/队列管理 +mineru-gradio = "mineru.cli.gradio_app:main" # Gradio UI +``` + +### 文档与项目结构 + +`mkdocs.yml` 定义多语言(EN/中文)站点架构: +- 快速入门、使用指南、参考资料、FAQ +- i18n 插件支持两种语言并行构建 +- Google Analytics 集成 (属性 G-44K480CC48) + +--- + +## 2. 核心管线架构 + +### 模块层级划分 + +源代码体积统计 (总计 ~53,447 行代码): + +- `mineru/backend/`: 17,598 行 (核心处理管线) + - `vlm/`: 586+545+153+660 = **1,944 行** (VLM 推理) + - `pipeline/`: 877+362+378+442+347+552+1024 = **3,982 行** (传统 OCR/布局) + - `office/`: 69+244+779+1037 = **2,129 行** (DOCX/PPTX/XLSX) + - `hybrid/`: 100+50+150 = **300+ 行** (混合推理) + +- `mineru/model/`: 包含完整的 ML 模型实现 + - `vlm/`: VLM 模型包装 + - `mfr/`: 公式识别 (MFR) + - `ocr/`: 光学字符识别 + - `table/`: 表格检测与识别 + - `layout/`: 布局检测 + - `docx/`: Office 文档转换 + +- `mineru/cli/`: 1,600+ 行 + - `client.py`: 主 CLI 程序 + - `fast_api.py`: REST API 服务器 (1,000+ 行) + - `router.py`: 异步任务路由 + +- `mineru/utils/`: 工具库集合 +- `mineru/data/`: 数据读写层 (文件系统/S3/HTTP) + +--- + +## 3. Pipeline 后端(传统方案) + +### 架构概览 + +Pipeline 采用**级联检测→识别→融合**的模式: + +``` +PDF → 图像提取 → 布局检测(PP-DocLayout-V2) + → 表格检测/识别(SLANet/UNet) + → 公式识别(UnimerNet) + → OCR(PaddleOCR) + → 文本合并 → Markdown +``` + +### 布局检测(Layout Detection) + +`mineru/backend/pipeline/batch_analyze.py:35-550`: + +类 `BatchAnalyze` 是主处理器,负责: +- 图像掩膜应用 (`_apply_mask_boxes_to_image`, 行 63-85) +- OCR 文本块修剪 (`_prune_empty_ocr_text_blocks`, 行 96-110) +- 表格内联对象提取 (`_extract_table_inline_objects`, 行 214-302) +- 模型推理调度 (`__call__`, 行 303-550) + +模型链路 (`mineru/backend/pipeline/model_init.py`): + +``` +- PP-DocLayout-V2: 布局检测模型 (ONNX/PyTorch) +- PaddleOCR: 字符识别 (det/rec/cls 三阶段) +- SLANet+/UNet: 表格检测 (cls: 表格分类, rec: 单元格识别) +- UnimerNet: 公式识别 (Swin+mBART 架构) +``` + +**关键批大小参数** (`batch_analyze.py:35-47`): +```python +LAYOUT_BASE_BATCH_SIZE = 1 # 布局检测批大小 +MFR_BASE_BATCH_SIZE = 16 # 公式识别批大小 +OCR_DET_BASE_BATCH_SIZE = 8 # OCR 检测批大小 +``` + +### 文本块合并与排序 + +`mineru/backend/pipeline/pipeline_magic_model.py:16-100`: + +类 `MagicModel` 处理 PP-DocLayout-V2 输出的块融合: + +**标签映射** (行 18-42): +```python +PP_DOCLAYOUT_V2_LABELS_TO_BLOCK_TYPES = { + "image": BlockType.IMAGE, + "table": BlockType.TABLE, + "display_formula": BlockType.INTERLINE_EQUATION, + "text": BlockType.TEXT, + ... +} +``` + +**视觉块分层** (行 44-67): +```python +VISUAL_MAIN_TYPES = (BlockType.IMAGE, BlockType.TABLE, BlockType.CHART, BlockType.CODE) +VISUAL_CHILD_TYPES = (BlockType.CAPTION, BlockType.FOOTNOTE) +# 每个主块可有标题、脚注等子块 +``` + +初始化流程 (行 69-100): +1. 坐标修正: `__fix_axis()` — 删除无效 bbox +2. 后处理: `__post_process()` — 索引重排,公式文本融合 +3. OCR 执行: `txt_spans_extract()` — 提取纯文本 span + +--- + +## 4. VLM 后端(MinerU 2.5/3.0 核心) + +### VLM 模型架构 + +**基座模型**: Qwen2-VL (Alibaba 通义千问视觉语言模型) + +`mineru/backend/vlm/vlm_analyze.py:80-102`: + +```python +from transformers import Qwen2VLForConditionalGeneration, AutoProcessor + +model = Qwen2VLForConditionalGeneration.from_pretrained( + model_path, + device_map={"": device}, + dtype="auto" +) +processor = AutoProcessor.from_pretrained(model_path, use_fast=True) +``` + +**模型参数**: 约 1.2B — 实际基于 **Qwen2-VL-2B**(Alibaba 开源的轻量级 VLM)微调而来,官方宣称的"1.2B"即此量级。 + +**多后端支持** (行 79-160): + +1. **transformers** (行 79-104): 直接加载本地模型 + - 自动混精训练 (`dtype="auto"`) + - 设备映射自动选择 (`device_map`) + - 批大小自适应 (`set_default_batch_size()`, 行 103-104) + +2. **mlx-engine** (行 105-113): macOS Apple Silicon 优化 + - 调用 `mlx_vlm.load()` + - 仅支持 macOS 13.5+ + ARM64 + +3. **vllm-engine** (行 118-160): 高吞吐推理 + - 支持异步 LLM、同步 LLM + - 自定义 logits 处理器 (行 13-56 in `utils.py`) + - 计算能力检测 (行 15-19) + +4. **lmdeploy-engine**: 推理加速框架 + - 支持多种加速后端 (pytorch/turbomind/maca) + +### 推理流程 + +`mineru/backend/vlm/vlm_analyze.py:200-586`: + +函数 `doc_analyze()` 主处理器 (行 200-300): + +```python +def doc_analyze( + pdf_bytes, + lang_list: list[str] = ["en"], + return_md: bool = True, + backend: str = "transformers", + model_path: str | None = None, + server_url: str | None = None, + ... +) -> dict: + # 1. PDF 加载 + 图像提取 + # 2. 页面处理循环 + 单页 VLM 推理 + # 3. 中间 JSON 生成 + Markdown 转换 +``` + +**异步版本** (行 331-380): +```python +async def aio_doc_analyze(...): + # 异步处理流程,支持并发推理 +``` + +### 输出解析 + +`mineru/backend/vlm/model_output_to_middle_json.py:1-153`: + +VLM 输出的 JSON 解析: +```python +def append_page_blocks_to_middle_json( + middle_json: dict, + page_model_output: dict, # VLM 原始输出 + page_id: int, + ... +) +``` + +转换块结构: +``` +VLM JSON 输出 → {bbox, type, content, ...} + → BlockType 枚举映射 + → 中间 JSON 格式 +``` + +--- + +## 5. DOCX/PPTX/XLSX 解析(3.0 新增) + +### Office 文档处理入口 + +`mineru/backend/office/docx_analyze.py:11-29`: + +```python +def office_docx_analyze( + file_bytes, + image_writer=None +): + file_stream = BytesIO(file_bytes) + results = convert_binary(file_stream) + + middle_json = result_to_middle_json( + results, + image_writer, + ) + return middle_json, results +``` + +### DOCX 转换器实现 + +`mineru/model/docx/main.py:11-14`: + +```python +def convert_binary(file_binary: BinaryIO): + converter = DocxConverter() + converter.convert(file_binary) + return converter.pages +``` + +`DocxConverter` (在 `mineru/model/docx/docx_converter.py` 中): +- 使用 `python-docx>=1.2.0` 解析文档结构 +- 使用 `mammoth>=1.11.0` 进行 HTML 转换 +- 支持图像提取与嵌入 + +### Office 块映射 + +`mineru/backend/office/model_output_to_middle_json.py:244` 定义块类型映射: + +```python +{ + "paragraph": BlockType.TEXT, + "heading": BlockType.PARAGRAPH_TITLE, + "table": BlockType.TABLE, + "image": BlockType.IMAGE, + ... +} +``` + +### Office 内容转 Markdown + +`mineru/backend/office/office_middle_json_mkcontent.py` (~1037 行): + +内容合并与 Markdown 输出,处理: +- 表格 HTML 转 Markdown +- 图像路径处理 +- 标题等级映射 + +--- + +## 6. Hybrid 后端(Pipeline+VLM) + +`mineru/backend/hybrid/hybrid_analyze.py:1-150`: + +混合模式的核心思想: + +1. **Pipeline** 提供**精确的布局检测** +2. **VLM** 补充**复杂内容识别** (表格/公式/代码) + +处理流程: + +```python +def hybrid_analyze( + pdf_bytes, + lang_list: list[str] = ["en"], + parse_method: str = "auto", + ... +): + # 1. OCR 分类 (行 50-58) + _ocr_enable = ocr_classify(pdf_bytes, parse_method) + + # 2. 若需 OCR,调用 Pipeline 的 OCR 模块 + if _ocr_enable: + ocr_res_list = ocr_det(...) + + # 3. 关键块(表格/公式)由 VLM 处理 + # 4. 最后融合结果 +``` + +### Hybrid 模型单例 + +`mineru/backend/pipeline/model_init.py` 定义 `HybridModelSingleton`: + +```python +class HybridModelSingleton: + _instance = None + + def get_model(...): + # 延迟加载,只在首次使用时初始化 + # 管理 Pipeline 所有模块的生命周期 +``` + +--- + +## 7. 输出格式化 + +### 中间 JSON 格式 + +所有后端(Pipeline/VLM/Office)都生成统一的**中间 JSON** (`middle_json`): + +```python +middle_json = { + "meta_info": {...}, + "doc_title": str, + "doc_layout_result": [...], + "para_blocks": [ + { + "type": BlockType, + "blocks": [ + { + "type": BlockType, + "lines": [ + { + "spans": [ + { + "type": ContentType, + "content": str, + "bbox": [x1, y1, x2, y2], + } + ] + } + ] + } + ] + } + ] +} +``` + +### Markdown 转换 + +`mineru/backend/vlm/vlm_middle_json_mkcontent.py:25-91`: + +```python +def merge_para_with_text(para_block, formula_enable=True, img_bucket_path=''): + # 1. 遍历块内所有 span + # 2. 文本内容 + 公式分隔符 + # 3. CJK 语言特殊处理 (行 58-68) + # - 中/日/韩: 换行不加空格 + # - 欧洲文本: 行末判断连字符删除 +``` + +**LaTeX 公式定界符** (行 10-22): + +```python +delimiters = { + 'display': {'left': '$$', 'right': '$$'}, # 行间公式 + 'inline': {'left': '$', 'right': '$'} # 行内公式 +} +``` + +可通过 `config.yaml` 自定义为 `\[...\]` 或其他格式。 + +### 表格处理 + +Pipeline 生成 HTML 格式表格 (`table.html`): +- SLANet/UNet 识别单元格 +- 保留原生 HTML 供转换工具使用 + +VLM 直接生成 Markdown 表格。 + +### 图像处理 + +`mineru/backend/vlm/model_output_to_middle_json.py`: + +```python +if block_type == BlockType.IMAGE: + # 图像存储为 bucket URL 或本地路径 + # 在 Markdown 中: ![](image_path) +``` + +图像写入器接口 (`mineru/data/data_reader_writer/base.py`): +```python +class DataWriter: + def write_image(self, image_bytes: bytes, image_name: str) -> str: + # 返回可被 Markdown 引用的路径 +``` + +--- + +## 8. 多语言支持 + +### 语言检测机制 + +`mineru/utils/guess_suffix_or_lang.py:43-54`: + +```python +def guess_language_by_text(code): + # 1. Unicode 代理对规范化 (行 11-40) + normalized_code = _normalize_text_for_language_guess(code) + + # 2. 调用 Magika 文件识别库 + try: + codebytes = normalized_code.encode("utf-8", errors="replace") + lang = magika.identify_bytes(codebytes).prediction.output.label + except Exception: + return DEFAULT_LANG # 默认 "txt" + + return lang if lang != "unknown" else DEFAULT_LANG +``` + +**支持语言数**: Magika 库支持 **109+ 种语言** 的代码与文本识别(对应 README 宣称的 "109 languages")。 + +### 块级语言检测 + +`mineru/backend/vlm/vlm_middle_json_mkcontent.py:32`: + +```python +block_lang = detect_lang(block_text) # 检测块所属语言 + +# CJK 语言特殊处理 (行 57-68) +cjk_langs = {'zh', 'ja', 'ko'} +if block_lang in cjk_langs: + # 不加行末空格 +``` + +### Markdown 格式适应 + +`utils/char_utils.py`: +- `full_to_half_exclude_marks()`: 全角→半角转换(保留标点) +- `is_hyphen_at_line_end()`: 西文连字符检测 + +--- + +## 9. 部署形态 + +### FastAPI REST API 服务器 + +`mineru/cli/fast_api.py:1-600+`: + +**启动命令**: +```bash +mineru-api --host 0.0.0.0 --port 8000 --enable-vlm-preload +``` + +**配置** (行 130-149): +```python +@dataclass +class ParseRequestOptions: + files: list[UploadFile] + lang_list: list[str] + backend: str # "vlm" / "pipeline" / "hybrid-ocr" + parse_method: str # "auto" / "txt" / "ocr" + formula_enable: bool + table_enable: bool + server_url: Optional[str] # 远程 VLM 服务器 URL + return_md: bool + return_middle_json: bool + return_model_output: bool + return_content_list: bool + return_images: bool + response_format_zip: bool +``` + +**任务管理** (行 72-100): +```python +TASK_PENDING = "pending" +TASK_PROCESSING = "processing" +TASK_COMPLETED = "completed" +TASK_FAILED = "failed" + +DEFAULT_TASK_RETENTION_SECONDS = 24 * 60 * 60 # 24 小时后清理 +``` + +### 异步任务路由 + +`mineru/cli/router.py`: + +支持: +- 任务队列 (Redis/内存) +- 异步处理 +- 进度查询 +- 结果下载 + +### Gradio 网页 UI + +`mineru/cli/gradio_app.py:1-1000+`: + +交互式界面,支持: +- 文件上传 (PDF/图像/Office) +- 参数配置 +- 实时进度展示 +- 结果预览与下载 + +### Docker 部署 + +`docker/` 目录包含: +- `Dockerfile`: 多阶段构建 (基础镜像 + 模型下载) +- `docker-compose.yml`: 编排服务 (API + Router + Redis) + +--- + +## 10. 测试框架 + +`tests/unittest/test_e2e.py`: + +端到端测试套件: + +```python +def test_pipeline_with_two_config(): + # 1. 准备测试 PDFs + doc_path_list = list(Path(pdf_files_dir).glob("*")) + + # 2. 执行 Pipeline 解析 + run_pipeline_parse( + pdf_file_names, + pdf_bytes_list, + p_lang_list, + output_dir, + parse_method="txt", + ) + + # 3. 断言结果 + assert_content(res_json_path, parse_method="txt") +``` + +**覆盖率配置** (`pyproject.toml:139-155`): +```toml +[tool.pytest.ini_options] +addopts = "-s --cov=mineru --cov-report html" + +[tool.coverage.run] +source = ["mineru/"] +omit = ["*/gradio_app.py", "*/models_download.py", "*/fast_api.py", ...] +``` + +--- + +## 11. 依赖树与硬件要求 + +### GPU/CPU 分支 + +**GPU 推荐**: +``` +torch>=2.6.0 +VRAM >= 4GB (VLM 推理) + >= 8GB (Hybrid 完整推理) + >= 12GB+ (并发多任务) +``` + +**CPU 专用**: +- ONNX Runtime 推理 (Layout/OCR) +- 禁用 VLM 后端 + +**Apple Silicon (macOS)**: +```python +[mlx] = ["mlx-vlm>=0.3.3,<0.4"] +# mlx-vlm 在 M1/M2/M3 上原生优化 +``` + +### 模型下载源 + +`mineru/utils/models_download_utils.py`: + +两大源同时支持: + +1. **ModelScope** (国内): `modelscope://Qwen2-VL-2B` +2. **HuggingFace**: `Qwen/Qwen2-VL-2B` + +环境变量控制: +```bash +export MINERU_MODEL_SOURCE="modelscope" # 默认 +``` + +自动下载位置: +``` +~/.mineru/models/vlm/Qwen2-VL-2B/ +``` + +### 批大小自适应 + +`mineru/backend/vlm/utils.py:94-110`: + +```python +def set_default_batch_size() -> int: + gpu_memory = get_vram(device) + + if gpu_memory >= 16: + batch_size = 8 + elif gpu_memory >= 8: + batch_size = 4 + else: + batch_size = 1 +``` + +--- + +## 12. 关键工程亮点与坑 + +### 亮点 1: 多模态融合架构 + +`mineru/backend/` 三大路径可独立使用,也可混合: + +- **纯 VLM**: 快速(一步到位),但需 4GB+ VRAM +- **纯 Pipeline**: 精确(多步验证),但计算量大 +- **Hybrid**: 精确+快速的平衡 + +### 亮点 2: 异步 IO 优化 + +`mineru/backend/vlm/vlm_analyze.py:331-380`: + +```python +async def aio_doc_analyze(...): + # 异步处理并发请求 + # 利用 aiofiles, asyncio 并发 +``` + +支持: +- 多 PDF 同时处理 +- HTTP 长连接复用 +- 任务队列 (FastAPI + asyncio) + +### 亮点 3: 语言自适应处理 + +`mineru/backend/vlm/vlm_middle_json_mkcontent.py:58-90`: + +```python +block_lang = detect_lang(block_text) + +if block_lang in {'zh', 'ja', 'ko'}: # CJK + # 无行末空格分隔 + para_text += content +else: # 西文 + # 智能处理连字符 + 空格 + if is_hyphen_at_line_end(content): + para_text += content[:-1] # 删除连字符 + else: + para_text += f'{content} ' +``` + +这使得 Markdown 在各种语言下都格式正确。 + +### 坑 1: GPU 内存溢出 + +**症状**: VLM 推理中 OOM + +**根因**: `batch_size` 设置过大 + +**解决** (行 103-104, `vlm_analyze.py`): +```python +batch_size = set_default_batch_size() # 自适应 +# 仍超限? 调整 `--batch-size 1` +``` + +### 坑 2: VRAM 未正确检测 + +`mineru/utils/model_utils.py`: + +```python +def get_vram(device): + if device == "cuda": + import torch + return torch.cuda.get_device_properties(0).total_memory / 1e9 + else: + # CPU 模式返回系统 RAM +``` + +**注意**: macOS + mlx-engine 绕过此检测,自动优化。 + +### 坑 3: 中文符号全/半角混乱 + +**问题**: PDF 中混有全角标点,转 Markdown 时出现重复 + +**解决** (`char_utils.py`): +```python +def full_to_half_exclude_marks(text): + # 全角→半角,但保留中文标点 +``` + +### 坑 4: 表格 HTML 转 Markdown 精度 + +**问题**: SLANet/UNet 识别的表格边界可能不准 + +**对策**: Hybrid 模式用 VLM 二次验证表格结构 + +### 亮点 4: 单例模式管理模型生命周期 + +`mineru/backend/vlm/vlm_analyze.py:40-50`: + +```python +class ModelSingleton: + _instance = None + _models = {} + _lock = threading.RLock() + + def get_model(...): + with cls._lock: + if key not in self._models: + # 延迟初始化 + 线程安全缓存 +``` + +避免: +- 重复加载同一模型 +- 并发竞态条件 + +### 亮点 5: 渐进式降级 + +若 VLM 服务不可用,自动降级到 Pipeline: + +```python +# mineru/cli/common.py +try: + result = vlm_doc_analyze(...) +except VLMServerError: + logger.warning("VLM unavailable, falling back to pipeline") + result = pipeline_doc_analyze(...) +``` + +--- + +## 13. 代码质量与维护 + +### 类型注解覆盖 + +大部分函数均使用 Type Hints: + +```python +# mineru/backend/vlm/vlm_analyze.py:200 +def doc_analyze( + pdf_bytes: bytes, + lang_list: list[str] = ["en"], + return_md: bool = True, + ... +) -> dict: +``` + +### 日志系统 + +统一使用 `loguru`: + +```python +from loguru import logger +logger.debug("...") +logger.info("...") +logger.warning("...") +logger.error("...") +``` + +环境变量控制: +```bash +export MINERU_LOG_LEVEL="DEBUG" +``` + +### 配置管理 + +`mineru/utils/config_reader.py`: + +- YAML 配置文件解析 +- 环境变量覆盖 +- 设备自动检测 + +--- + +## 总结 + +MinerU 3.0 是**高质量的生产级文档处理系统**,具有: + +1. **三层后端架构** (VLM/Pipeline/Hybrid),灵活应对不同场景 +2. **多语言自适应** (109+ 语言),Markdown 格式天然正确 +3. **异步并发处理** (FastAPI + asyncio),高吞吐 +4. **模块解耦** (独立 backend/model/cli/data),易于扩展 +5. **完整部署链** (REST API/Gradio/Docker),开箱即用 + +代码量 **~53.5K 行**,工程质量成熟,是 opendatalab 的精品开源项目。 + +对于个人项目/业务项目的复用路径: +- **法考视频项目**: 字幕提取后的教材 PDF → Markdown 清洗可直接用 MinerU Pipeline +- **咨询报告生成**: 参考报告的 PDF 摄取改 VLM 后端,公式/表格识别质量上台阶 +- **Hermes/HiClaw**: 可作为文档解析子能力接入,暴露 `mineru-api` REST 给 agent 调用 diff --git a/docs-site/Dockerfile b/docs-site/Dockerfile new file mode 100644 index 0000000..5ebe438 --- /dev/null +++ b/docs-site/Dockerfile @@ -0,0 +1,3 @@ +FROM nginx:alpine +COPY index.html /usr/share/nginx/html/index.html +EXPOSE 80 diff --git a/docs-site/index.html b/docs-site/index.html new file mode 100644 index 0000000..865185c --- /dev/null +++ b/docs-site/index.html @@ -0,0 +1,856 @@ + + + + + +MinerU 3.0 源码深度解析 · PDF→Markdown 的三后端之路 + + + + +
+
MinerU 3.0 源码解析
+ + +
+ + +
+
+
Source-code Analysis · 2026-04-13
+

MinerU 3.0
从 PDF 到 Markdown 的三后端之路

+

+ opendatalab 出品的 PDF → Markdown/JSON 解析引擎, + GitHub 59.5k stars。本文基于 master 分支(v3.0.9) + 浅克隆源码逐行通读,覆盖 VLM / Pipeline / Hybrid / Office 四后端完整链路。 +

+
+
59.5k
GitHub Stars
+
3.0.9
当前版本
+
53.5k
LoC 代码量
+
4
处理后端
+
109+
支持语言
+
1.2B
VLM 参数
+
+
+ Python 3.10-3.13 + Qwen2-VL-2B 基座 + FastAPI + Gradio + vllm / lmdeploy / mlx + Apache-2.0 +
+
+
+ + +
+
+
🎯
+
+

一句话结论

+

+ MinerU 3.0 是 目前开源 PDF 解析最完整的生产级方案。它不是靠单一大模型硬抗, + 而是把 VLM(Qwen2-VL-2B 微调)+ 传统级联 Pipeline + Hybrid 混合 + 三条路线打包成可配置的后端,再叠加 Office/DOCX 原生解析。 + 代码质量成熟,工程化到位(FastAPI 异步任务、Gradio UI、Docker 编排一应俱全), + 值得作为子能力接入任何 Agent / RAG 系统。 +

+
+
+
+ + +
+
+
01 / OVERVIEW
+

项目总览

+

一个包、三大后端、七个 CLI、四种推理框架 —— MinerU 把 PDF 解析做成了瑞士军刀。

+
+ +
+
+

版本号 v3.0.9

+

master 分支当前版本。3.0 的核心升级:Office 原生解析、异步任务端点、Pipeline v1.5 benchmark 达 86.2。

+ mineru/version.py:1 +
+
+

Python 3.10 ~ 3.13

+

Python 版本门槛抬得不低,用上了新语法(list[str] 原生泛型、str | None 联合类型)。

+ pyproject.toml:11 +
+
+

7 个 CLI 入口

+

mineru / mineru-api / mineru-gradio / mineru-router / mineru-vllm-server / mineru-lmdeploy-server / mineru-models-download

+ pyproject.toml:114-122 +
+
+ +

📦 依赖矩阵(按后端切分)

+
+ + + + + + + +
Extra触发条件关键依赖场景
[vlm]默认 VLM 后端torch≥2.6 transformers≥4.57.3Qwen2-VL 直接加载
[vllm]高吞吐 VLMvllm≥0.10.1.1多 PDF 并发
[lmdeploy]国产加速lmdeploy≥0.10.2昇腾/MACA
[mlx]macOS ARMmlx-vlm≥0.3.3M1/M2/M3 原生
[pipeline]传统级联onnxruntime paddlepaddle*无 GPU / CPU-only
+
+
+ + +
+
+
02 / ARCHITECTURE
+

四后端并联架构

+

MinerU 不是一条管线,而是四条 —— 通过 backend 参数切换,共享同一套中间 JSON 格式。

+
+ +
+
+
+
BACKEND 1
+
VLM (Qwen2-VL-2B)
+
1,944 LoC · 一步到位 · 需 4GB+ VRAM
+
+
+
BACKEND 2
+
Pipeline (级联)
+
3,982 LoC · Layout→OCR→Table→MFR
+
+
+
BACKEND 3
+
Hybrid
+
300+ LoC · Pipeline + VLM 互补
+
+
+
+
+
+
BACKEND 4 · 3.0 新增
+
Office (DOCX / PPTX / XLSX)
+
2,129 LoC · python-docx + mammoth
+
+
+
+
+
+
UNIFIED
+
Middle JSON → Markdown / content_list / Images
+
所有后端产出同一套中间表示,转换器统一
+
+
+
+ +
+

📌 为什么是四后端而不是一个

+

单一 VLM 快但对 VRAM 有门槛;单一 Pipeline 精但慢且计算量大。给用户留出选择权是工程上更诚实的做法 —— 你有 A100 就跑 VLM,你只有 CPU 就跑 Pipeline。

+
+
+ + +
+
+
03 / VLM BACKEND
+

VLM 后端 · 1.2B 参数的真相

+

官方宣传的 "1.2B 参数 VLM 超越 Gemini 2.5 Pro",读源码后发现底下是 Qwen2-VL-2B 微调。

+
+ +
# mineru/backend/vlm/vlm_analyze.py:80-102
+from transformers import Qwen2VLForConditionalGeneration, AutoProcessor
+
+model = Qwen2VLForConditionalGeneration.from_pretrained(
+    model_path,
+    device_map={"": device},
+    dtype="auto"
+)
+processor = AutoProcessor.from_pretrained(model_path, use_fast=True)
+
+ +
+

💡 关键结论

+

基座是阿里开源的 Qwen2-VL-2B。MinerU 用 6550 万页 PDF 做领域微调,把通用 VLM 调成了文档专家 —— 这是"小模型打败大模型"的典型范例,不靠参数量,靠高质量领域数据。

+
+ +

🚀 四种推理框架并存

+
+
+

transformers

+

最兼容,本地直接加载 HF 权重。默认选项。

+ vlm_analyze.py:79-104 +
+
+

vllm

+

高吞吐,支持 async LLM + 自定义 logits 处理器。

+ vlm_analyze.py:118-160 +
+
+

lmdeploy

+

国产加速(TurboMind/PyTorch/MACA),支持昇腾。

+ vlm_analyze.py:162+ +
+
+

mlx

+

macOS 13.5+ Apple Silicon 原生,M 系列芯片首选。

+ vlm_analyze.py:105-113 +
+
+ +

🔄 推理主流程

+
+
+

PDF 加载 + 图像提取

+

pypdfium2 把每页渲染成 PNG,分辨率由 --dpi 控制。

+ doc_analyze() @ vlm_analyze.py:200-300 +
+
+

VLM 单页推理

+

每页图像 + prompt 送入 Qwen2-VL,产出结构化 JSON(bbox + type + content)。

+ ModelSingleton @ vlm_analyze.py:40-50 +
+
+

中间 JSON 拼接

+

单页结果通过 append_page_blocks_to_middle_json() 合并到全文档结构。

+ model_output_to_middle_json.py:1-153 +
+
+

Markdown 转换

+

按块类型渲染:公式用 $...$、表格直出、图像嵌路径。

+ vlm_middle_json_mkcontent.py:25-91 +
+
+ +

⚙️ Batch Size 自适应

+
# mineru/backend/vlm/utils.py:94-110
+def set_default_batch_size() -> int:
+    gpu_memory = get_vram(device)
+    if gpu_memory >= 16:
+        batch_size = 8
+    elif gpu_memory >= 8:
+        batch_size = 4
+    else:
+        batch_size = 1
+
+
+ + +
+
+
04 / PIPELINE BACKEND
+

Pipeline 后端 · 传统级联的完整样本

+

没有 VLM 之前的老路,到现在依然是精度基准。四个独立模型串起来,每一步都能单独验证。

+
+ +
+
+
+
STEP 1
+
PP-DocLayout-V2
+
布局检测 · ONNX
+
+
+
STEP 2
+
SLANet+ / UNet
+
表格结构识别
+
+
+
STEP 3
+
UnimerNet
+
公式识别 · Swin+mBART
+
+
+
+
+
+
+
STEP 4
+
PaddleOCR (det → cls → rec)
+
三阶段文本识别
+
+
+
+ +

🧩 核心类 BatchAnalyze

+
+
+

图像掩膜

+

识别前先做 mask 处理,避免上一步的 bbox 污染下一步。

+ _apply_mask_boxes_to_image @ batch_analyze.py:63-85 +
+
+

OCR 空块修剪

+

OCR 出来的空字符串块直接丢弃,减少后续处理噪声。

+ _prune_empty_ocr_text_blocks @ batch_analyze.py:96-110 +
+
+

表格内联对象提取

+

表格里可能嵌公式/图像,这一步单独拎出来做二次识别。

+ _extract_table_inline_objects @ batch_analyze.py:214-302 +
+
+

推理调度 __call__

+

300+ 行的主循环,协调四个模型的数据流。

+ __call__ @ batch_analyze.py:303-550 +
+
+ +

🏷️ Magic Model: 标签 → BlockType 映射

+
# mineru/backend/pipeline/pipeline_magic_model.py:18-42
+PP_DOCLAYOUT_V2_LABELS_TO_BLOCK_TYPES = {
+    "image": BlockType.IMAGE,
+    "table": BlockType.TABLE,
+    "display_formula": BlockType.INTERLINE_EQUATION,
+    "text": BlockType.TEXT,
+    # ...
+}
+
+VISUAL_MAIN_TYPES  = (BlockType.IMAGE, BlockType.TABLE, BlockType.CHART, BlockType.CODE)
+VISUAL_CHILD_TYPES = (BlockType.CAPTION, BlockType.FOOTNOTE)
+
+ +
+

🔧 Batch Size 常量

+

LAYOUT=1 · MFR=16 · OCR_DET=8 —— 公式识别批量最大(小图多),布局检测串行(大图)。batch_analyze.py:35-47

+
+
+ + +
+
+
05 / HYBRID
+

Hybrid 后端 · 最实用的折中

+

Pipeline 给结构,VLM 补细节。表格和公式交给 VLM 二次识别,精度和速度都能接受。

+
+ +
# mineru/backend/hybrid/hybrid_analyze.py:1-150
+def hybrid_analyze(pdf_bytes, lang_list, parse_method="auto", ...):
+    # 1. 判断是否需要 OCR(行 50-58)
+    _ocr_enable = ocr_classify(pdf_bytes, parse_method)
+
+    # 2. 需要 OCR 则走 Pipeline OCR
+    if _ocr_enable:
+        ocr_res_list = ocr_det(...)
+
+    # 3. 表格/公式等难块交给 VLM 二次验证
+    # 4. 最后融合中间 JSON
+
+ +
+

💡 为什么 Hybrid 是默认推荐

+

单 VLM 的失误主要在表格结构(合并单元格、嵌套表),而 Pipeline 的 SLANet 对结构化表格有很强的归纳偏置。Hybrid 让它们各补各的短板,在 OmniDocBench v1.5 上 Pipeline 后端能打到 86.2 分

+
+
+ + +
+
+
06 / OFFICE · 3.0 新增
+

Office 后端 · DOCX 终于不用转 PDF 了

+

3.0 版本才加的原生 Office 解析,让 DOCX → Markdown 走纯文本路径,不再经 PDF 渲染。

+
+ +
# mineru/backend/office/docx_analyze.py:11-29
+def office_docx_analyze(file_bytes, image_writer=None):
+    file_stream = BytesIO(file_bytes)
+    results = convert_binary(file_stream)   # DocxConverter
+    middle_json = result_to_middle_json(results, image_writer)
+    return middle_json, results
+
+ +
+
+

python-docx

+

读 DOCX 底层 XML 结构 —— 段落、表格、图片、样式。

+
+
+

mammoth

+

把 DOCX 转 HTML 作为中间态,再统一映射到 Middle JSON。

+
+
+

image_writer 注入

+

图片不内嵌,通过写入器接口输出到外部存储(S3/本地)。

+
+
+ +
+

⚠️ 坑位提醒

+

office_middle_json_mkcontent.py 有 1037 行之长,表格 HTML → Markdown 转换是已知精度瓶颈。复杂表格(跨行跨列、嵌套)建议仍走 PDF→VLM 路径。

+
+
+ + +
+
+
07 / OUTPUT
+

中间 JSON · 统一输出格式

+

四后端共享同一套 middle_json 数据结构,这是 MinerU 架构能解耦的关键。

+
+ +
# 统一中间表示
+middle_json = {
+    "meta_info": {...},
+    "doc_title": str,
+    "doc_layout_result": [...],
+    "para_blocks": [
+        {
+            "type": BlockType,
+            "blocks": [
+                {
+                    "type": BlockType,
+                    "lines": [
+                        {"spans": [
+                            {
+                                "type": ContentType,
+                                "content": str,
+                                "bbox": [x1, y1, x2, y2],
+                            }
+                        ]}
+                    ]
+                }
+            ]
+        }
+    ]
+}
+
+ +

🌐 多语言智能换行

+
# mineru/backend/vlm/vlm_middle_json_mkcontent.py:58-90
+block_lang = detect_lang(block_text)
+
+if block_lang in {'zh', 'ja', 'ko'}:  # CJK:换行不加空格
+    para_text += content
+else:                                    # 西文:处理连字符
+    if is_hyphen_at_line_end(content):
+        para_text += content[:-1]     # 删掉行尾连字符
+    else:
+        para_text += f"{content} "
+
+ +
+

🌏 109 语言的真相

+

README 里的 "109 languages" 对应的是 magika 库的语言识别能力(guess_suffix_or_lang.py:43-54),MinerU 自己只是用 CJK/西文两套换行策略加上 fast-langdetect 做块级识别。

+
+ +

📐 LaTeX 定界符可配置

+
delimiters = {
+    'display': {'left': '$$', 'right': '$$'},   # 行间公式
+    'inline':  {'left': '$',  'right': '$'}     # 行内公式
+}
+# 可通过 config.yaml 改成 \[...\] / \(...\)
+
+
+ + +
+
+
08 / DEPLOY
+

部署形态 · 四种姿势

+

从命令行到 REST API 再到 Gradio UI 和 Docker 编排,MinerU 把部署路径铺得很全。

+
+ +
+
+

CLI 本地

+

mineru -p input.pdf -o output/ —— 最简单,单文件处理。

+ mineru/cli/client.py +
+
+

FastAPI REST 服务化

+

异步任务队列(3.0 新增),任务 24h 自动清理,支持 ZIP 打包响应。

+ mineru/cli/fast_api.py:130-149 +
+
+

Gradio UI 交互

+

网页界面上传 PDF,实时进度展示,结果在线预览。

+ mineru/cli/gradio_app.py +
+
+

Docker Compose 生产

+

多阶段 Dockerfile + API/Router/Redis 编排,带模型下载预热。

+ docker/ +
+
+ +

📋 ParseRequestOptions(REST 参数全景)

+
# mineru/cli/fast_api.py:130-149
+@dataclass
+class ParseRequestOptions:
+    files: list[UploadFile]
+    lang_list: list[str]
+    backend: str              # "vlm" / "pipeline" / "hybrid-ocr"
+    parse_method: str         # "auto" / "txt" / "ocr"
+    formula_enable: bool
+    table_enable: bool
+    server_url: Optional[str]   # 远程 VLM 服务器
+    return_md: bool
+    return_middle_json: bool
+    return_model_output: bool
+    return_content_list: bool
+    return_images: bool
+    response_format_zip: bool
+
+ +
+

💾 模型下载源

+

默认走 ModelScope(国内快),可切换 HuggingFace。环境变量 MINERU_MODEL_SOURCE=modelscope,权重缓存在 ~/.mineru/models/vlm/Qwen2-VL-2B/

+
+
+ + +
+
+
09 / HIGHLIGHTS
+

工程亮点

+

读源码时让我眼前一亮的几处细节 —— 都是只有跑过生产才会做的事。

+
+ +
+
+

⚡ 单例 + 线程锁

+

模型加载用 ModelSingleton._lock = threading.RLock() 保护,避免并发请求重复加载 2B 模型(重载一次就是 4GB VRAM)。

+ vlm_analyze.py:40-50 +
+
+

🔀 渐进式降级

+

VLM 服务挂了自动 fallback 到 Pipeline,不让请求直接 500。这是生产级 API 的基本素养。

+ mineru/cli/common.py +
+
+

🌏 CJK 换行策略

+

中日韩自动不加行尾空格,西文智能删连字符 —— 跨语言 Markdown 看起来才正常。

+ vlm_middle_json_mkcontent.py:58-90 +
+
+

🔄 async doc_analyze

+

同步+异步两个版本并存,FastAPI 可直接用 aio_doc_analyze() 跑并发推理。

+ vlm_analyze.py:331-380 +
+
+

📦 中间 JSON 统一

+

四个后端完全解耦,共享同一套 middle_json,渲染/测试/可视化都能复用,不用每加一个后端重写一套输出。

+ backend/*/model_output_to_middle_json.py +
+
+

🧪 全链路 E2E 测试

+

tests/unittest/test_e2e.py 跑真实 PDF,覆盖 pipeline/vlm/hybrid 三套后端 + txt/ocr 两种解析模式。

+ tests/unittest/test_e2e.py +
+
+
+ + +
+
+
10 / PITFALLS
+

踩过的坑

+

源码/issue 综合看下来几个容易翻车的点 —— 提前知道就能绕开。

+
+ +
+
+

🔥 GPU OOM

+

默认 batch_size 按 VRAM 自动调,但多页并发 + 大图仍可能爆。手动传 --batch-size 1 最稳。

+ utils.py:94-110 +
+
+

🔤 全/半角标点混乱

+

PDF 中混排全角标点,转 Markdown 可能重复。靠 full_to_half_exclude_marks() 做清洗,但仍有边界 case。

+ utils/char_utils.py +
+
+

📊 复杂表格精度

+

SLANet/UNet 对标准表格强,对跨行跨列、嵌套表格识别率下降明显。对策:用 Hybrid 让 VLM 二次验证。

+ hybrid_analyze.py +
+
+

🖥️ CPU 模式 VRAM 检测

+

get_vram() 在 CPU 模式下返回系统 RAM,需要注意别误判。macOS + mlx 则绕过此检测。

+ utils/model_utils.py +
+
+
+ + +
+
+
11 / VERDICT
+

可复用路径

+

看完源码,想清楚怎么把它接入现有业务 —— 这才是读源码的真正目的。

+
+ +
+
+

🎓 法考项目

+

教材 PDF → Markdown 清洗,走 Pipeline 后端(精度优先),公式/表格保真好,能直接灌入题库。

+
+
+

📊 咨询报告生成

+

参考报告的 PDF 摄取走 VLM 后端,快速提取结构化大纲,喂给下游 LLM 做改写。

+
+
+

🤖 Hermes / HiClaw

+

作为子能力暴露 mineru-api REST 给 Agent 调用,DOCX/PDF 双入口,用 Hybrid 兜底。

+
+
+ +
+

🎯 接入建议

+

+ 轻量场景:直接 pip install -U "mineru[vlm]",本地 Qwen2-VL-2B 够用。
+ 服务化:跑 mineru-api + Redis 队列,24h 自动清理,无需造轮子。
+ 多项目共享:独立部署一个 mineru.kang-kang.com,通过 REST 给 Hermes/HiClaw/法考多项目复用,省去每个项目各自部署 2GB 模型。 +

+
+
+ + + + +