MinerU
由上海人工智能实验室开源的高质量PDF解析工具,能精准地将包含图片、公式、表格的复杂PDF转换为Markdown和JSON等机器可读的格式。
安装准备
在开始安装前,需要做好以下准备工作:
- 系统环境:确保你的系统是 Windows、Linux 或 macOS。
- Python版本:请安装 Python 3.10 到 3.13 之间的版本,这是稳定运行的前提。
- 虚拟环境(推荐):强烈建议使用Conda或Venv创建一个独立的Python虚拟环境,以避免包冲突。
# 使用Conda创建环境示例conda create -n mineru_env python=3.11conda activate mineru_env
- 硬件要求:
- CPU:推荐8核心以上。
- 内存:推荐32GB。
- GPU(可选):如果需要进行GPU加速,推荐使用NVIDIA Turing架构及以上(如RTX 20/30/40系列)且显存不小于8GB的显卡,并确保已安装合适版本的CUDA驱动。
详细安装步骤
MinerU使用 HuggingFace 和 ModelScope 作为模型仓库,用户可以根据需要切换模型源或使用本地模型。
- HuggingFace 是默认的模型源,在全球范围内提供了优异的加载速度和极高稳定性。
- ModelScope 是中国大陆地区用户的最佳选择,提供了无缝兼容的SDK模块,适用于无法访问HuggingFace的用户。
方法一:使用pip或uv安装MinerU
1、安装MinerU
在激活的虚拟环境中,执行以下命令安装MinerU。国内用户建议使用国内镜像源以加速下载。
# 使用阿里云镜像安装pip install --upgrade pip -i https://mirrors.aliyun.com/pypi/simplepip install uv -i https://mirrors.aliyun.com/pypi/simpleuv pip install -U "mineru[core]" -i https://mirrors.aliyun.com/pypi/simple
> uv 是一个用 Rust 编写的高速 Python 包管理器和项目工作流工具,由 Astral 公司开发(也是 Ruff 的开发者)。它旨在替代 pip、pip-tools、virtualenv、poetry 等工具,提供极快的性能和现代化的开发体验。uv 是一个用 Rust 编写的高速 Python 包管理器和项目工作流工具,由 Astral 公司开发(也是 Ruff 的开发者)。它旨在替代 pip、pip-tools、virtualenv、poetry 等工具,提供极快的性能和现代化的开发体验。
2、下载模型
MinerU的功能依赖预训练模型,安装后需要下载模型文件。
# 默认从Huggingface下载,国内网络可能较慢mineru-models-download
国内用户,更推荐使用Modelscope源,速度更快:
# 通过环境变量切换# 在任何情况下可以通过设置环境变量来切换模型源,这适用于所有命令行工具和API调用。exportMINERU_MODEL_SOURCE=modelscope# 查看echo$MINERU_MODEL_SOURCEmineru-models-download# 或import osos.environ["MINERU_MODEL_SOURCE"]="modelscope"
其余方法可参考官网:快速开始 - MinerU
配置本地模型路径
让MINERU使用本地模型,主要通过修改其配置文件来实现。
- 找到或创建配置文件:MINERU的配置文件通常是 mineru.json 或 magic-pdf.json 。它可能位于你的用户主目录(例如 C:\Users\用户名\mineru.json )或项目目录下。如果不存在,你可以根据模板创建一个 。
- 编辑配置文件:在配置文件中,你需要指定本地模型文件的位置。关键在于正确设置 models-dir 字段 。
如果你的Pipeline模式和VLM模式模型存放在不同路径,可以这样配置:
{"models-dir": {"pipeline": "/path/to/your/pipeline/models","vlm": "/path/to/your/vlm/models"}}
如果所有模型都在同一个目录下,可以直接指定根路径:
{"models-dir": "/path/to/your/all/models"}
{"bucket_info": {"bucket-name-1": ["ak","sk","endpoint"],"bucket-name-2": ["ak","sk","endpoint"]},"latex-delimiter-config": {"display": {"left": "$$","right": "$$"},"inline": {"left": "$","right": "$"}},"llm-aided-config": {"title_aided": {"api_key": "your_api_key","base_url": "https://dashscope.aliyuncs.com/compatible-mode/v1","model": "qwen3-next-80b-a3b-instruct","enable_thinking": false,"enable": false}},"models-dir": {"pipeline": "D:\\modelscope\\hub\\models\\OpenDataLab\\PDF-Extract-Kit-1___0","vlm": "D:\\modelscope\\hub\\models\\OpenDataLab\\MinerU2___5-2509-1___2B"},"config_version": "1.3.1"}
使用本地模型
- 设置环境变量:通过设置环境变量 MINERU_MODEL_SOURCE=local,告诉MINERU从本地路径读取模型 。
exportMINERU_MODEL_SOURCE=local
- Docker部署时的注意事项:如果你通过Docker部署,需要在启动容器时,将存放本地模型的目录挂载到容器内部,并在容器内正确设置上述环境变量和配置文件路径 。
配置选项
语言支持
# 支持的语言['ch','ch_server','ch_lite','en','korean','japan','chinese_cht','ta','te','ka']
后端选项详解
Pipeline 后端
- 特点:通用性强,支持多种文档类型
- 方法选项:
- vlm-transformers:通用VLM
- vlm-vllm-engine:高性能推理引擎
- vlm-http-client:HTTP客户端模式
- vlm-mlx-engine:macOS优化引擎
输出文件类型
1、可视化文件:
- {filename}_layout.pdf - 布局边界框
- {filename}_span.pdf - 文本跨度边界框
2、内容文件:
- {filename}.md - Markdown格式
- {filename}_content_list.json - 结构化内容
3、中间文件:
- {filename}_middle.json - 中间结果
- {filename}_model.json - 模型原始输出
Python调用示例
import osimport copyimport jsonfrom pathlib import Pathfrom loguru import loggerfrom mineru.cli.common import convert_pdf_bytes_to_bytes_by_pypdfium2, prepare_env, read_fnfrom mineru.data.data_reader_writer import FileBasedDataWriterfrom mineru.utils.draw_bbox import draw_layout_bbox, draw_span_bboxfrom mineru.utils.enum_class import MakeModefrom mineru.backend.vlm.vlm_analyze import doc_analyze as vlm_doc_analyzefrom mineru.backend.pipeline.pipeline_analyze import doc_analyze as pipeline_doc_analyzefrom mineru.backend.pipeline.pipeline_middle_json_mkcontent import union_make as pipeline_union_makefrom mineru.backend.pipeline.model_json_to_middle_json import result_to_middle_json as pipeline_result_to_middle_jsonfrom mineru.backend.vlm.vlm_middle_json_mkcontent import union_make as vlm_union_makefrom mineru.utils.guess_suffix_or_lang import guess_suffix_by_pathdefdo_parse(output_dir,# Output directory for storing parsing resultspdf_file_names:list[str],# List of PDF file names to be parsedpdf_bytes_list:list[bytes],# List of PDF bytes to be parsedp_lang_list:list[str],# List of languages for each PDF, default is 'ch' (Chinese)backend="pipeline",# The backend for parsing PDF, default is 'pipeline'parse_method="auto",# The method for parsing PDF, default is 'auto'formula_enable=True,# Enable formula parsingtable_enable=True,# Enable table parsingserver_url=None,# Server URL for vlm-http-client backendf_draw_layout_bbox=True,# Whether to draw layout bounding boxesf_draw_span_bbox=True,# Whether to draw span bounding boxesf_dump_md=True,# Whether to dump markdown filesf_dump_middle_json=True,# Whether to dump middle JSON filesf_dump_model_output=True,# Whether to dump model output filesf_dump_orig_pdf=True,# Whether to dump original PDF filesf_dump_content_list=True,# Whether to dump content list filesf_make_md_mode=MakeMode.MM_MD,# The mode for making markdown content, default is MM_MDstart_page_id=0,# Start page ID for parsing, default is 0end_page_id=None,# End page ID for parsing, default is None (parse all pages until the end of the document)):if backend =="pipeline":for idx, pdf_bytes inenumerate(pdf_bytes_list):new_pdf_bytes = convert_pdf_bytes_to_bytes_by_pypdfium2(pdf_bytes, start_page_id, end_page_id)pdf_bytes_list[idx]= new_pdf_bytesinfer_results, all_image_lists, all_pdf_docs, lang_list, ocr_enabled_list = pipeline_doc_analyze(pdf_bytes_list, p_lang_list, parse_method=parse_method, formula_enable=formula_enable,table_enable=table_enable)for idx, model_list inenumerate(infer_results):model_json = copy.deepcopy(model_list)pdf_file_name = pdf_file_names[idx]local_image_dir, local_md_dir = prepare_env(output_dir, pdf_file_name, parse_method)image_writer, md_writer = FileBasedDataWriter(local_image_dir), FileBasedDataWriter(local_md_dir)images_list = all_image_lists[idx]pdf_doc = all_pdf_docs[idx]_lang = lang_list[idx]_ocr_enable = ocr_enabled_list[idx]middle_json = pipeline_result_to_middle_json(model_list, images_list, pdf_doc, image_writer, _lang, _ocr_enable, formula_enable)pdf_info = middle_json["pdf_info"]pdf_bytes = pdf_bytes_list[idx]_process_output(pdf_info, pdf_bytes, pdf_file_name, local_md_dir, local_image_dir,md_writer, f_draw_layout_bbox, f_draw_span_bbox, f_dump_orig_pdf,f_dump_md, f_dump_content_list, f_dump_middle_json, f_dump_model_output,f_make_md_mode, middle_json, model_json, is_pipeline=True)else:if backend.startswith("vlm-"):backend = backend[4:]f_draw_span_bbox =Falseparse_method ="vlm"for idx, pdf_bytes inenumerate(pdf_bytes_list):pdf_file_name = pdf_file_names[idx]pdf_bytes = convert_pdf_bytes_to_bytes_by_pypdfium2(pdf_bytes, start_page_id, end_page_id)local_image_dir, local_md_dir = prepare_env(output_dir, pdf_file_name, parse_method)image_writer, md_writer = FileBasedDataWriter(local_image_dir), FileBasedDataWriter(local_md_dir)middle_json, infer_result = vlm_doc_analyze(pdf_bytes, image_writer=image_writer, backend=backend, server_url=server_url)pdf_info = middle_json["pdf_info"]_process_output(pdf_info, pdf_bytes, pdf_file_name, local_md_dir, local_image_dir,md_writer, f_draw_layout_bbox, f_draw_span_bbox, f_dump_orig_pdf,f_dump_md, f_dump_content_list, f_dump_middle_json, f_dump_model_output,f_make_md_mode, middle_json, infer_result, is_pipeline=False)def_process_output(pdf_info,pdf_bytes,pdf_file_name,local_md_dir,local_image_dir,md_writer,f_draw_layout_bbox,f_draw_span_bbox,f_dump_orig_pdf,f_dump_md,f_dump_content_list,f_dump_middle_json,f_dump_model_output,f_make_md_mode,middle_json,model_output=None,is_pipeline=True):"""处理输出文件"""if f_draw_layout_bbox:draw_layout_bbox(pdf_info, pdf_bytes, local_md_dir,f"{pdf_file_name}_layout.pdf")if f_draw_span_bbox:draw_span_bbox(pdf_info, pdf_bytes, local_md_dir,f"{pdf_file_name}_span.pdf")if f_dump_orig_pdf:md_writer.write(f"{pdf_file_name}_origin.pdf",pdf_bytes,)image_dir =str(os.path.basename(local_image_dir))if f_dump_md:make_func = pipeline_union_make if is_pipeline else vlm_union_makemd_content_str = make_func(pdf_info, f_make_md_mode, image_dir)md_writer.write_string(f"{pdf_file_name}.md",md_content_str,)if f_dump_content_list:make_func = pipeline_union_make if is_pipeline else vlm_union_makecontent_list = make_func(pdf_info, MakeMode.CONTENT_LIST, image_dir)md_writer.write_string(f"{pdf_file_name}_content_list.json",json.dumps(content_list, ensure_ascii=False, indent=4),)if f_dump_middle_json:md_writer.write_string(f"{pdf_file_name}_middle.json",json.dumps(middle_json, ensure_ascii=False, indent=4),)if f_dump_model_output:md_writer.write_string(f"{pdf_file_name}_model.json",json.dumps(model_output, ensure_ascii=False, indent=4),)logger.info(f"local output dir is {local_md_dir}")defparse_doc(path_list:list[Path],output_dir,lang="ch",backend="pipeline",method="auto",server_url=None,start_page_id=0,end_page_id=None):"""Parameter description:path_list: List of document paths to be parsed, can be PDF or image files.output_dir: Output directory for storing parsing results.lang: Language option, default is 'ch', optional values include['ch', 'ch_server', 'ch_lite', 'en', 'korean', 'japan', 'chinese_cht', 'ta', 'te', 'ka']。Input the languages in the pdf (if known) to improve OCR accuracy. Optional.Adapted only for the case where the backend is set to "pipeline"backend: the backend for parsing pdf:pipeline: More general.vlm-transformers: More general.vlm-vllm-engine: Faster(engine).vlm-http-client: Faster(client).without method specified, pipeline will be used by default.method: the method for parsing pdf:auto: Automatically determine the method based on the file type.txt: Use text extraction method.ocr: Use OCR method for image-based PDFs.Without method specified, 'auto' will be used by default.Adapted only for the case where the backend is set to "pipeline".server_url: When the backend is `http-client`, you need to specify the server_url, for example:`http://127.0.0.1:30000`start_page_id: Start page ID for parsing, default is 0end_page_id: End page ID for parsing, default is None (parse all pages until the end of the document)"""try:file_name_list =[]pdf_bytes_list =[]lang_list =[]for path in path_list:file_name =str(Path(path).stem)pdf_bytes = read_fn(path)file_name_list.append(file_name)pdf_bytes_list.append(pdf_bytes)lang_list.append(lang)do_parse(output_dir=output_dir,pdf_file_names=file_name_list,pdf_bytes_list=pdf_bytes_list,p_lang_list=lang_list,backend=backend,parse_method=method,server_url=server_url,start_page_id=start_page_id,end_page_id=end_page_id)except Exception as e:logger.exception(e)if __name__ =='__main__':"""如果您由于网络问题无法下载模型,可以设置环境变量MINERU_MODEL_SOURCE为modelscope使用免代理仓库下载模型"""os.environ["MINERU_MODEL_SOURCE"]="local"# "modelscope"# args__dir__ = os.path.dirname(os.path.abspath(__file__))pdf_files_dir = os.path.join(__dir__,"picture")output_dir = os.path.join(__dir__,"output_MinerU")pdf_suffixes =["pdf"]image_suffixes =["png","jpeg","jp2","webp","gif","bmp","jpg"]doc_path_list =[]for doc_path in Path(pdf_files_dir).glob('*'):if guess_suffix_by_path(doc_path)in pdf_suffixes + image_suffixes:doc_path_list.append(doc_path)"""Use pipeline mode if your environment does not support VLM"""parse_doc(doc_path_list, output_dir, backend="pipeline")"""To enable VLM mode, change the backend to 'vlm-xxx'"""# parse_doc(doc_path_list, output_dir, backend="vlm-transformers") # more general.# parse_doc(doc_path_list, output_dir, backend="vlm-mlx-engine") # faster than transformers in macOS 13.5+.# parse_doc(doc_path_list, output_dir, backend="vlm-vllm-engine") # faster(engine).# parse_doc(doc_path_list, output_dir, backend="vlm-http-client", server_url="http://127.0.0.1:30000") # faster(client).
核心函数解析
1. do_parse() - 主解析函数
output_dir:解析结果的输出目录路径
pdf_file_names:要解析的PDF文件名列表(字符串列表)
pdf_bytes_list:要解析的PDF字节数据列表(字节列表)
p_lang_list:每个PDF对应的语言列表,默认是中文(‘ch’)
backend:解析PDF的后端引擎,默认’pipeline’
parse_method:解析方法,默认’auto’(自动选择)
formula_enable:是否启用公式解析,默认True
table_enable:是否启用表格解析,默认True
server_url:VLM HTTP客户端后端使用的服务器URL
f_draw_layout_bbox:是否绘制布局边界框,默认True
f_draw_span_bbox:是否绘制文本跨度边界框,默认True
f_dump_md:是否输出Markdown文件,默认True
f_dump_middle_json:是否输出中间JSON文件,默认True
f_dump_model_output:是否输出模型原始输出文件,默认True
f_dump_orig_pdf:是否输出原始PDF文件,默认True
f_dump_content_list:是否输出内容列表文件,默认True
f_make_md_mode:生成Markdown内容的模式,默认是MM_MD
start_page_id:解析起始页码,默认0(第一页)
end_page_id:解析结束页码,默认None(解析到文档末尾)
> 支持两种后端模式:
- pipeline 后端:通用解析,支持 OCR 和文本提取
- vlm 后端:基于视觉语言模型,支持多种推理引擎- vlm 后端:基于视觉语言模型,支持多种推理引擎
2. _process_output() - 输出处理函数
def_process_output(pdf_info,# PDF信息字典pdf_bytes,# PDF字节数据pdf_file_name,# PDF文件名local_md_dir,# 本地Markdown目录local_image_dir,# 本地图像目录md_writer,# Markdown写入器f_draw_layout_bbox,# 是否绘制布局边界框f_draw_span_bbox,# 是否绘制跨度边界框f_dump_orig_pdf,# 是否转储原始PDFf_dump_md,# 是否转储Markdownf_dump_content_list,# 是否转储内容列表f_dump_middle_json,# 是否转储中间JSONf_dump_model_output,# 是否转储模型输出f_make_md_mode,# Markdown生成模式middle_json,# 中间JSON数据model_output=None,# 模型原始输出is_pipeline=True# 是否为pipeline后端):"""处理输出文件"""
3. parse_doc() - 用户接口函数
defparse_doc(path_list:list[Path],# 要解析的文档路径列表output_dir,# 解析结果输出目录lang="ch",# 语言选项,默认是中文backend="pipeline",# 解析后端,默认pipelinemethod="auto",# 解析方法,默认autoserver_url=None,# 服务器URL(用于vlm-http-client)start_page_id=0,# 起始页码end_page_id=None# 结束页码):
> 提供简化的用户接口,支持多种语言和解析配置。
使用Docker部署Mineru
一、Docker镜像构建
1.1 下载与构建镜像
# 下载Dockerfile文件wget https://gcore.jsdelivr.net/gh/opendatalab/MinerU@master/docker/china/Dockerfile# 打包docker镜像docker build -t mineru:latest -f Dockerfile .
1.2 Dockerfile配置说明
# 基础镜像选择(根据GPU架构选择)# 计算能力≥8.0(Ampere及以上架构)FROM docker.m.daocloud.io/vllm/vllm-openai:v0.10.1.1# 计算能力<8.0(Turing及更早架构)# FROM docker.m.daocloud.io/vllm/vllm-openai:v0.10.2# 配置Ubuntu国内镜像源并安装依赖RUN sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list && \sed -i 's/security.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list && \apt-get update && \apt-get install -y \fonts-noto-core \fonts-noto-cjk \fontconfig \libgl1 && \fc-cache -fv && \apt-get clean && \rm -rf /var/lib/apt/lists/*# 安装Mineru核心包RUN python3 -m pip install -U 'mineru[core]' -i https://mirrors.aliyun.com/pypi/simple --break-system-packages && \python3 -m pip cache purge# 下载模型文件RUN /bin/bash -c "mineru-models-download -s modelscope -m all"# 设置入口点ENTRYPOINT ["/bin/bash", "-c", "export MINERU_MODEL_SOURCE=local && exec \"$@\"", "--"]
> GPU架构说明:
- 查看GPU计算能力:CUDA GPU列表
- vLLM v0.10.1.1 支持计算能力≥8.0的显卡
- vLLM v0.10.2 支持更早架构的显卡
二、启动Docker容器
2.1 基础启动命令
docker run --gpus all --shm-size 32g -p 30000:30000 -p 7860:7860 -p 8000:8000 --ipc=host -it mineru:latest /bin/bash
2.2 端口映射说明
- 30000: OpenAI兼容服务器端口
- 7860: Gradio WebUI端口
- 8000: FastAPI接口端口
2.3 vLLM加速要求
使用vLLM加速VLM模型推理需满足:
- 硬件要求:Volta及以上架构GPU,显存≥8GB
- 驱动要求:NVIDIA驱动支持CUDA 12.8+
- 容器配置:已正确挂载GPU设备
2.4 容器停止后如何重新启动服务
# 启动指定容器docker start <容器ID或名称># 进入容器交互终端docker exec -it <容器ID或名称> /bin/bash
2.5 通过配置环境变量来使用本地模型
exportMINERU_MODEL_SOURCE=local
三、服务启动与使用
3.1 启动OpenAI兼容服务器
# 默认启动(自动选择引擎)mineru-openai-server# 指定vLLM引擎mineru-openai-server --engine vllm --port 30000# 指定lmdeploy引擎mineru-openai-server --engine lmdeploy --server-port 30000
3.2 启动FastAPI服务
mineru-api --host 0.0.0.0 --port 8000
> 访问API文档:http://127.0.0.1:8000/docs
3.3 启动Gradio WebUI
# 通用后端mineru-gradio --server-name 0.0.0.0 --server-port 7860# 启用vLLM加速mineru-gradio --server-name 0.0.0.0 --server-port 7860 --enable-vllm-engine true# 启用lmdeploy加速mineru-gradio --server-name 0.0.0.0 --server-port 7860 --enable-lmdeploy-engine true
> 访问WebUI:http://127.0.0.1:7860
3.4 HTTP客户端调用
# 连接到OpenAI兼容服务器mineru -p <input_path> -o <output_path> -b vlm-http-client -u http://127.0.0.1:30000
3.5 所有vllm/lmdeploy官方支持的参数都可用通过命令行参数传递给 MinerU,包括以下命令:mineru、mineru-openai-server、mineru-gradio、mineru-api
mineru-openai-server --engine vllm --port 30000 --gpu-memory-utilization 0.8 --max-model-len 7520 --max-num-batched-tokens 32768
四、API参数详解
4.1 基本参数
| 参数 | 类型 | 说明 | 示例 |
|---|---|---|---|
| files | array | 待解析文件列表 | [“doc.pdf”, “img.png”] |
| output_dir | string | 输出目录 | “./output” |
4.2 解析配置
| 参数 | 类型 | 说明 | 选项 |
|---|---|---|---|
| backend | string | 解析引擎 | pipeline、vlm-transformers、vlm-vllm-async-engine、vlm-lmdeploy-engine、vlm-http-client |
| parse_method | string | PDF解析方法 | auto、txt、ocr |
| lang_list | array | OCR语言设置 | ch、en、korean、japan等 |
4.3 功能开关
| 参数 | 类型 | 说明 |
|---|---|---|
| formula_enable | boolean | 公式识别开关 |
| table_enable | boolean | 表格识别开关 |
| start_page_id | integer | 起始页码(0开始) |
| end_page_id | integer | 结束页码 |
4.4 服务器配置
| 参数 | 类型 | 说明 | 示例 |
|---|---|---|---|
| server_url | string | OpenAI兼容服务器地址 | “http://127.0.0.1:30000“ |
4.5 输出选项
- return_md:返回Markdown格式
- return_middle_json:返回中间JSON
- return_model_output:返回模型原始输出
- return_content_list:返回内容列表
- return_images:返回提取的图片
- response_format_zip:打包为ZIP文件(默认JSON)
import requestsimport pathlibimport osimport jsonimport timefrom typing import List, Optional, Dict, Anyfrom datetime import datetimeAPI_URL ="http://localhost:8000/file_parse"INPUT_DIR ="./images"OUTPUT_DIR ="./output"# 支持的图片格式SUPPORTED_EXTENSIONS ={'.jpg','.jpeg','.png','.bmp','.tiff','.tif','.gif','.pdf'}defparse_file(file_path: pathlib.Path,output_dir:str= OUTPUT_DIR,lang_list: Optional[List[str]]=None,backend:str="vlm-transformers",parse_method:str="auto",formula_enable:bool=False,table_enable:bool=True,server_url: Optional[str]=None,return_md:bool=True,return_middle_json:bool=False,return_model_output:bool=False,return_content_list:bool=False,return_images:bool=False,response_format_zip:bool=False,start_page_id:int=0,end_page_id:int=0):"""解析单个文件并保存结果参数说明:-----------file_path (pathlib.Path): 需要解析的文件路径output_dir (str): 解析结果的输出目录lang_list (List[str], optional): OCR语言设置,提高识别准确率- 'ch'/'ch_server'/'ch_lite': 简体中文- 'en': 英文- 'korean': 韩文- 'japan': 日文- 其他语言选项...backend (str): 解析后端引擎选择- 'pipeline': 通用型,功能全面- 'vlm-transformers': 通用但较慢- 'vlm-mlx-engine': 快速(需Apple Silicon + macOS 13.5+)- 'vlm-vllm-async-engine': 快速(需vllm库)- 'vlm-lmdeploy-engine': 快速(需lmdeploy库)- 'vlm-http-client': 快速(连接OpenAI兼容服务器)parse_method (str): PDF解析方法(仅pipeline后端)- 'auto': 自动判断- 'txt': 文本提取(适用于可选中文本的PDF)- 'ocr': OCR识别(适用于扫描版/图片PDF)formula_enable (bool): 是否启用公式识别table_enable (bool): 是否启用表格识别server_url (str, optional): OpenAI兼容服务器地址(仅vlm-http-client后端)return_md (bool): 是否返回Markdown格式内容return_middle_json (bool): 是否返回中间JSONreturn_model_output (bool): 是否返回模型原始输出return_content_list (bool): 是否返回内容列表return_images (bool): 是否返回提取的图片response_format_zip (bool): 是否打包为ZIP文件返回(默认返回JSON)start_page_id (int): 解析起始页码(从0开始计数)end_page_id (int): 解析结束页码(从0开始计数)"""start_time = time.time()# 创建输出目录output_path = pathlib.Path(output_dir)output_path.mkdir(exist_ok=True)# 为当前文件创建输出子目录file_output_dir = output_path / file_path.stemfile_output_dir.mkdir(exist_ok=True)print(f"[{datetime.now().strftime('%H:%M:%S')}] 开始处理文件: {file_path.name}")try:# 准备multipart/form-data请求files =[('files',(file_path.name,open(file_path,'rb'),'application/octet-stream'))]# 准备表单数据data ={'output_dir':str(file_output_dir),'backend': backend,'parse_method': parse_method,'formula_enable':str(formula_enable).lower(),'table_enable':str(table_enable).lower(),'return_md':str(return_md).lower(),'return_middle_json':str(return_middle_json).lower(),'return_model_output':str(return_model_output).lower(),'return_content_list':str(return_content_list).lower(),'return_images':str(return_images).lower(),'response_format_zip':str(response_format_zip).lower(),'start_page_id':str(start_page_id),'end_page_id':str(end_page_id)}# 添加可选参数if lang_list:# 修复:lang_list 应该以数组形式传递for lang in lang_list:data['lang_list']= langif server_url:data['server_url']= server_url# 发送请求print(f" 发送请求到 {API_URL}...")request_start = time.time()response = requests.post(API_URL, files=files, data=data)request_time = time.time()- request_startprint(f" 请求完成,耗时: {request_time:.2f}秒")if response.status_code !=200:print(f" 错误: API返回状态码 {response.status_code}")print(f" 错误信息: {response.text[:500]}")# 只显示前500字符return# 根据返回格式处理响应if response_format_zip:# 保存ZIP文件zip_filename = file_output_dir /f"{file_path.stem}_results.zip"withopen(zip_filename,'wb')as f:f.write(response.content)print(f" 已保存ZIP文件到: {zip_filename}")else:# 解析JSON响应result = response.json()# 保存完整的响应JSON以便调试debug_filename = file_output_dir /f"{file_path.stem}_debug.json"withopen(debug_filename,'w', encoding='utf-8')as f:json.dump(result, f, ensure_ascii=False, indent=2)print(f" 已保存调试JSON到: {debug_filename}")# 根据实际API响应结构处理数据# API返回格式: {"backend": "...", "version": "...", "results": {"filename": {"md_content": "..."}}}if'results'in result and result['results']:for filename, file_result in result['results'].items():# 保存markdown内容if'md_content'in file_result:md_content = file_result['md_content']md_filename = file_output_dir /f"{filename}.md"withopen(md_filename,'w', encoding='utf-8')as f:f.write(md_content)print(f" 已保存Markdown到: {md_filename}")# 保存中间JSON(如果API返回)if return_middle_json and'middle_json'in file_result:json_filename = file_output_dir /f"{filename}_middle.json"withopen(json_filename,'w', encoding='utf-8')as f:json.dump(file_result['middle_json'], f, ensure_ascii=False, indent=2)print(f" 已保存中间JSON到: {json_filename}")# 保存模型输出(如果API返回)if return_model_output and'model_output'in file_result:json_filename = file_output_dir /f"{filename}_model_output.json"withopen(json_filename,'w', encoding='utf-8')as f:json.dump(file_result['model_output'], f, ensure_ascii=False, indent=2)print(f" 已保存模型输出到: {json_filename}")# 保存内容列表(如果API返回)if return_content_list and'content_list'in file_result:json_filename = file_output_dir /f"{filename}_content_list.json"withopen(json_filename,'w', encoding='utf-8')as f:json.dump(file_result['content_list'], f, ensure_ascii=False, indent=2)print(f" 已保存内容列表到: {json_filename}")# 兼容旧版API格式:直接返回markdown字段elif'markdown'in result:md_content = result['markdown']md_filename = file_output_dir /f"{file_path.stem}.md"withopen(md_filename,'w', encoding='utf-8')as f:f.write(md_content)print(f" 已保存Markdown到: {md_filename}")else:print(f" 警告: API响应中没有找到预期的数据结构")print(f" 响应结构: {list(result.keys())ifisinstance(result,dict)else'非字典类型'}")total_time = time.time()- start_timeprint(f" 处理完成,总耗时: {total_time:.2f}秒\n")except Exception as e:print(f" 处理文件 {file_path.name} 时出错: {e}")import tracebacktraceback.print_exc()print()finally:# 确保文件被关闭for file_info in files:ifhasattr(file_info[1][1],'close'):file_info[1][1].close()defprocess_all_files(input_dir:str= INPUT_DIR,output_dir:str= OUTPUT_DIR,**kwargs):"""处理输入目录中的所有支持的文件参数说明:-----------input_dir (str): 输入目录路径,包含需要处理的文件output_dir (str): 输出目录路径,用于保存处理结果**kwargs: 其他参数,将传递给parse_file函数- 包括: lang_list, backend, parse_method, formula_enable, table_enable等"""start_time = time.time()input_path = pathlib.Path(input_dir)ifnot input_path.exists():print(f"输入目录不存在: {input_dir}")return# 创建输出目录output_path = pathlib.Path(output_dir)output_path.mkdir(exist_ok=True)# 获取所有支持的文件all_files =[]for ext in SUPPORTED_EXTENSIONS:all_files.extend(input_path.glob(f"*{ext}"))all_files.extend(input_path.glob(f"*{ext.upper()}"))# 去重并排序all_files =sorted(set(all_files))ifnot all_files:print(f"在 {input_dir} 目录中未找到支持的图片或PDF文件")returnprint(f"找到 {len(all_files)} 个待处理文件")# 处理每个文件file_count =0for file_path in all_files:if file_path.is_file():parse_file(file_path, output_dir=output_dir,**kwargs)file_count +=1total_time = time.time()- start_timeprint(f"所有文件处理完成! 共处理了 {file_count} 个文件")print(f"总运行时间: {total_time:.2f}秒,平均每个文件: {total_time /max(file_count,1):.2f}秒")defprocess_single_file(file_path:str,output_dir:str= OUTPUT_DIR,**kwargs):"""处理单个文件参数说明:-----------file_path (str): 需要处理的文件路径output_dir (str): 输出目录路径,用于保存处理结果**kwargs: 其他参数,将传递给parse_file函数- 包括: lang_list, backend, parse_method, formula_enable, table_enable等"""start_time = time.time()file_path_obj = pathlib.Path(file_path)ifnot file_path_obj.exists():print(f"文件不存在: {file_path}")returnif file_path_obj.suffix.lower()notin SUPPORTED_EXTENSIONS:print(f"不支持的文件格式: {file_path_obj.suffix}")print(f"支持的格式: {', '.join(SUPPORTED_EXTENSIONS)}")returnparse_file(file_path_obj, output_dir=output_dir,**kwargs)total_time = time.time()- start_timeprint(f"单文件处理完成,总耗时: {total_time:.2f}秒")# 使用示例if __name__ =="__main__":total_start_time = time.time()print("="*60)print("MinerU API 客户端 - 文件解析工具")print(f"开始时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")print("="*60)# 示例1: 基本用法 - 处理所有图片,提取表格# print("\n示例1: 基本用法 - 处理所有图片,提取表格")# print("-" * 40)# process_all_files(# input_dir="./images",# output_dir="./output",# table_enable=True, # 启用表格识别# return_md=True, # 返回Markdown格式# backend="vlm-transformers" # 使用通用但较慢的后端# )# exit()# 示例2: 处理PDF文件,支持中文OCR# print("\n示例2: 处理PDF文件,支持中文OCR")# print("-" * 40)# # 确保有PDF文件# pdf_files = list(pathlib.Path("./images").glob("*.pdf"))# if pdf_files:# parse_file(# file_path=pdf_files[0],# output_dir="./output/pdf_example",# lang_list=["ch", "en"], # 设置中文和英文OCR# backend="pipeline", # 使用pipeline后端# parse_method="auto", # 自动判断解析方法# table_enable=True, # 启用表格识别# formula_enable=False, # 不启用公式识别# return_md=True, # 返回Markdown格式# return_content_list=True # 返回内容列表# )# exit()# 示例3: 使用vlm-http-client后端(需要服务器)print("\n示例3: 使用vlm-http-client后端(需要服务器)")print("-"*40)print("注意: 此示例需要先启动OpenAI兼容服务器")# 取消注释并填写实际的服务器URLparse_file(file_path=pathlib.Path("./images/sample.jpg"),output_dir="./output/vlm_example",backend="vlm-http-client",# 使用HTTP客户端后端server_url="http://127.0.0.1:30000",# 服务器地址table_enable=True,return_md=True)exit()# 示例4: 批量处理特定类型的文件# print("\n示例4: 批量处理PNG文件")# print("-" * 40)# png_files = list(pathlib.Path("./images").glob("*.png"))# for i, png_file in enumerate(png_files[:2]): # 只处理前2个,避免太多# print(f"处理第 {i + 1} 个PNG文件: {png_file.name}")# parse_file(# file_path=png_file,# output_dir="./output/png_files",# backend="pipeline", # 使用pipeline后端# parse_method="ocr", # 使用OCR解析方法# table_enable=True, # 启用表格识别# return_md=True, # 返回Markdown格式# start_page_id=0,# end_page_id=0# )total_time = time.time()- total_start_timeprint("\n"+"="*60)print(f"所有示例执行完成!")print(f"总运行时间: {total_time:.2f}秒")print(f"结束时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")print("="*60)
常见问题
1、MinerU 在 Docker 中部署时出现 CUDA 错误:flash-attn 兼容性问题与解决方案
问题描述及原因
在 Windows 系统下使用 RTX 5060 显卡通过 Docker 部署 MinerU 时,可能出现以下 CUDA 相关错误,导致服务启动失败:
CUDA error (/__w/xformers/xformers/third_party/flash-attention/hopper/flash_fwd_launch_template.h:188): invalid argumentRuntimeError: Engine core initialization failed. See root cause above.
该错误通常与 vllm-flash-attn 在视觉模块中存在兼容性问题有关,系统已自动回退至 xformers 后端。为解决此问题,可尝试手动安装正确版本的 flash-attn。
解决方案:安装 flash-attn
# 通过以下命令安装指定版本的 flash-attn:pip install flash-attn==2.8.3# --verbose 是 pip 命令的一个可选参数,用于显示详细的安装过程信息。pip install flash-attn==2.8.3 --verbose
若安装过程缓慢,可直接从以下链接下载预编译的 wheel 文件,并放入 Docker 容器中安装:
# 安装过程信息会显示安装的哪个版本https://github.com/Dao-AILab/flash-attention/releases/download/v2.8.3/flash_attn-2.8.3+cu12torch2.7cxx11abiTRUE-cp312-cp312-linux_x86_64.whl
下载后,在 Docker 内执行:
pip install /path/to/flash_attn-2.8.3+cu12torch2.7cxx11abiTRUE-cp312-cp312-linux_x86_64.whl
MinerU 输出文件说明
Mineru 命令执行后,除了输出主要的 markdown 文件外,还会生成多个辅助文件用于调试、质检和进一步处理。
可视化调试文件
- 模型输出(使用原始输出):
- model.json
- 调试和验证(使用可视化文件):
- layout.pdf
- spans.pdf
- 内容提取(使用简化文件):
- *.md
- content_list.json
- 二次开发(使用结构化文件):
- middle.json
布局分析文件 (layout.pdf)
文件命名格式:{原文件名}_layout.pdf
功能说明:
- 可视化展示每一页的布局分析结果
- 每个检测框右上角的数字表示阅读顺序
- 使用不同背景色块区分不同类型的内容块
使用场景:
- 检查布局分析是否正确
- 确认阅读顺序是否合理
- 调试布局相关问题

文本片段文件 (spans.pdf)
> 仅适用于 pipeline 后端
文件命名格式:{原文件名}_spans.pdf
功能说明:
- 根据 span 类型使用不同颜色线框标注页面内容
- 用于质量检查和问题排查
使用场景:
- 快速排查文本丢失问题
- 检查行内公式识别情况
- 验证文本分割准确性

结构化数据文件
> pipeline 后端 输出结果
模型推理结果 (model.json)
文件命名格式:{原文件名}_model.json
数据结构定义
from pydantic import BaseModel, Fieldfrom enum import IntEnumclass CategoryType(IntEnum):"""内容类别枚举"""title = 0 # 标题plain_text = 1 # 文本abandon = 2 # 包括页眉页脚页码和页面注释figure = 3 # 图片figure_caption = 4 # 图片描述table = 5 # 表格table_caption = 6 # 表格描述table_footnote = 7 # 表格注释isolate_formula = 8 # 行间公式formula_caption = 9 # 行间公式的标号embedding = 13 # 行内公式isolated = 14 # 行间公式text = 15 # OCR 识别结果class PageInfo(BaseModel):"""页面信息"""page_no: int = Field(description="页码序号,第一页的序号是 0", ge=0)height: int = Field(description="页面高度", gt=0)width: int = Field(description="页面宽度", ge=0)class ObjectInferenceResult(BaseModel):"""对象识别结果"""category_id: CategoryType = Field(description="类别", ge=0)poly: list[float] = Field(description="四边形坐标,格式为 [x0,y0,x1,y1,x2,y2,x3,y3]")score: float = Field(description="推理结果的置信度")latex: str | None = Field(description="LaTeX 解析结果", default=None)html: str | None = Field(description="HTML 解析结果", default=None)class PageInferenceResults(BaseModel):"""页面推理结果"""layout_dets: list[ObjectInferenceResult] = Field(description="页面识别结果")page_info: PageInfo = Field(description="页面元信息")# 完整的推理结果inference_result: list[PageInferenceResults] = []
坐标系统说明
poly 坐标格式:[x0, y0, x1, y1, x2, y2, x3, y3]
- 分别表示左上、右上、右下、左下四点的坐标
- 坐标原点在页面左上角

示例数据
[{"layout_dets": [{"category_id": 2,"poly": [99.1906967163086,100.3119125366211,730.3707885742188,100.3119125366211,730.3707885742188,245.81326293945312,99.1906967163086,245.81326293945312],"score": 0.9999997615814209}],"page_info": {"page_no": 0,"height": 2339,"width": 1654}},{"layout_dets": [{"category_id": 5,"poly": [99.13092803955078,2210.680419921875,497.3183898925781,2210.680419921875,497.3183898925781,2264.78076171875,99.13092803955078,2264.78076171875],"score": 0.9999997019767761}],"page_info": {"page_no": 1,"height": 2339,"width": 1654}}]
中间处理结果 (middle.json)
文件命名格式:{原文件名}_middle.json
顶层结构
| 字段名 | 类型 | 说明 |
|---|---|---|
| pdf_info | list[dict] | 每一页的解析结果数组 |
| _backend | string | 解析模式:pipeline 或 vlm |
| _version_name | string | MinerU 版本号 |
页面信息结构 (pdf_info)
| 字段名 | 说明 |
|---|---|
| preproc_blocks | PDF 预处理后的未分段中间结果 |
| page_idx | 页码,从 0 开始 |
| page_size | 页面的宽度和高度 [width, height] |
| images | 图片块信息列表 |
| tables | 表格块信息列表 |
| interline_equations | 行间公式块信息列表 |
| discarded_blocks | 需要丢弃的块信息 |
| para_blocks | 分段后的内容块结果 |
块结构层次
一级块 (table | image)└── 二级块└── 行 (line)└── 片段 (span)
一级块字段
| 字段名 | 说明 |
|---|---|
| type | 块类型:table 或 image |
| bbox | 块的矩形框坐标 [x0, y0, x1, y1] |
| blocks | 包含的二级块列表 |
二级块字段
| 字段名 | 说明 |
|---|---|
| type | 块类型(详见下表) |
| bbox | 块的矩形框坐标 |
| lines | 包含的行信息列表 |
二级块类型
| 类型 | 说明 |
|---|---|
| image_body | 图像本体 |
| image_caption | 图像描述文本 |
| image_footnote | 图像脚注 |
| table_body | 表格本体 |
| table_caption | 表格描述文本 |
| table_footnote | 表格脚注 |
| text | 文本块 |
| title | 标题块 |
| index | 目录块 |
| list | 列表块 |
| interline_equation | 行间公式块 |
行和片段结构
行 (line) 字段:
- bbox:行的矩形框坐标
- spans:包含的片段列表
片段 (span) 字段:
- bbox:片段的矩形框坐标
- type:片段类型(image、table、text、inline_equation、interline_equation)
- content | img_path:文本内容或图片路径
示例数据
{"pdf_info": [{"preproc_blocks": [{"type": "text","bbox": [52,61.956024169921875,294,82.99800872802734],"lines": [{"bbox": [52,61.956024169921875,294,72.0000228881836],"spans": [{"bbox": [54.0,61.956024169921875,296.2261657714844,72.0000228881836],"content": "dependent on the service headway and the reliability of the departure ","type": "text","score": 1.0}]}]}],"layout_bboxes": [{"layout_bbox": [52,61,294,731],"layout_label": "V","sub_layout": []}],"page_idx": 0,"page_size": [612.0,792.0],"_layout_tree": [],"images": [],"tables": [],"interline_equations": [],"discarded_blocks": [],"para_blocks": [{"type": "text","bbox": [52,61.956024169921875,294,82.99800872802734],"lines": [{"bbox": [52,61.956024169921875,294,72.0000228881836],"spans": [{"bbox": [54.0,61.956024169921875,296.2261657714844,72.0000228881836],"content": "dependent on the service headway and the reliability of the departure ","type": "text","score": 1.0}]}]}]}],"_backend": "pipeline","_version_name": "0.6.1"}
内容列表 (content_list.json)
文件命名格式:{原文件名}_content_list.json
功能说明
这是一个简化版的 middle.json,按阅读顺序平铺存储所有可读内容块,去除了复杂的布局信息,便于后续处理。
内容类型
| 类型 | 说明 |
|---|---|
| image | 图片 |
| table | 表格 |
| text | 文本/标题 |
| equation | 行间公式 |
文本层级标识
通过 text_level 字段区分文本层级:
- 无 text_level 或 text_level: 0:正文文本
- text_level: 1:一级标题
- text_level: 2:二级标题
- 以此类推…
通用字段
- 所有内容块都包含
page_idx字段,表示所在页码(从0开始)。 - 所有内容块都包含
bbox 字段,表示内容块的边界框坐标[x0, y0, x1, y1]映射在0-1000范围内的结果。
示例数据
[{"type": "text","text": "The response of flow duration curves to afforestation ","text_level": 1,"bbox": [62,480,946,904],"page_idx": 0},{"type": "image","img_path": "images/a8ecda1c69b27e4f79fce1589175a9d721cbdc1cf78b4cc06a015f3746f6b9d8.jpg","image_caption": ["Fig. 1. Annual flow duration curves of daily flows from Pine Creek, Australia, 1989–2000. "],"image_footnote": [],"bbox": [62,480,946,904],"page_idx": 1},{"type": "equation","img_path": "images/181ea56ef185060d04bf4e274685f3e072e922e7b839f093d482c29bf89b71e8.jpg","text": "$$\nQ _ { \\% } = f ( P ) + g ( T )\n$$","text_format": "latex","bbox": [62,480,946,904],"page_idx": 2},{"type": "table","img_path": "images/e3cb413394a475e555807ffdad913435940ec637873d673ee1b039e3bc3496d0.jpg","table_caption": ["Table 2 Significance of the rainfall and time terms "],"table_footnote": ["indicates that the rainfall term was significant at the $5 \\%$ level, $T$ indicates that the time term was significant at the $5 \\%$ level, \\* represents significance at the $10 \\%$ level, and na denotes too few data points for meaningful analysis. "],"table_body": "<html><body><table><tr><td rowspan=\"2\">Site</td><td colspan=\"10\">Percentile</td></tr><tr><td>10</td><td>20</td><td>30</td><td>40</td><td>50</td><td>60</td><td>70</td><td>80</td><td>90</td><td>100</td></tr><tr><td>Traralgon Ck</td><td>P</td><td>P,*</td><td>P</td><td>P</td><td>P,</td><td>P,</td><td>P,</td><td>P,</td><td>P</td><td>P</td></tr><tr><td>Redhill</td><td>P,T</td><td>P,T</td><td>,*</td><td>**</td><td>P.T</td><td>P,*</td><td>P*</td><td>P*</td><td>*</td><td>,*</td></tr><tr><td>Pine Ck</td><td></td><td>P,T</td><td>P,T</td><td>P,T</td><td>P,T</td><td>T</td><td>T</td><td>T</td><td>na</td><td>na</td></tr><tr><td>Stewarts Ck 5</td><td>P,T</td><td>P,T</td><td>P,T</td><td>P,T</td><td>P.T</td><td>P.T</td><td>P,T</td><td>na</td><td>na</td><td>na</td></tr><tr><td>Glendhu 2</td><td>P</td><td>P,T</td><td>P,*</td><td>P,T</td><td>P.T</td><td>P,ns</td><td>P,T</td><td>P,T</td><td>P,T</td><td>P,T</td></tr><tr><td>Cathedral Peak 2</td><td>P,T</td><td>P,T</td><td>P,T</td><td>P,T</td><td>P,T</td><td>*,T</td><td>P,T</td><td>P,T</td><td>P,T</td><td>T</td></tr><tr><td>Cathedral Peak 3</td><td>P.T</td><td>P.T</td><td>P,T</td><td>P,T</td><td>P,T</td><td>T</td><td>P,T</td><td>P,T</td><td>P,T</td><td>T</td></tr><tr><td>Lambrechtsbos A</td><td>P,T</td><td>P</td><td>P</td><td>P,T</td><td>*,T</td><td>*,T</td><td>*,T</td><td>*,T</td><td>*,T</td><td>T</td></tr><tr><td>Lambrechtsbos B</td><td>P,T</td><td>P,T</td><td>P,T</td><td>P,T</td><td>P,T</td><td>P,T</td><td>P,T</td><td>P,T</td><td>T</td><td>T</td></tr><tr><td>Biesievlei</td><td>P,T</td><td>P.T</td><td>P,T</td><td>P,T</td><td>*,T</td><td>*,T</td><td>T</td><td>T</td><td>P,T</td><td>P,T</td></tr></table></body></html>","bbox": [62,480,946,904],"page_idx": 5}]
VLM 后端 输出结果
模型推理结果 (model.json)
文件命名格式:{原文件名}_model.json
文件格式说明
- 该文件为 VLM 模型的原始输出结果,包含两层嵌套list,外层表示页面,内层表示该页的内容块
- 每个内容块都是一个dict,包含 type、bbox、angle、content 字段
支持的内容类型
{"text": "文本","title": "标题","equation": "行间公式","image": "图片","image_caption": "图片描述","image_footnote": "图片脚注","table": "表格","table_caption": "表格描述","table_footnote": "表格脚注","phonetic": "拼音","code": "代码块","code_caption": "代码描述","ref_text": "参考文献","algorithm": "算法块","list": "列表","header": "页眉","footer": "页脚","page_number": "页码","aside_text": "装订线旁注","page_footnote": "页面脚注"}
坐标系统说明
bbox 坐标格式:[x0, y0, x1, y1]
- 分别表示左上、右下两点的坐标
- 坐标原点在页面左上角
- 坐标为相对于原始页面尺寸的百分比,范围在0-1之间
示例数据
[[{"type": "header","bbox": [0.077,0.095,0.18,0.181],"angle": 0,"score": null,"block_tags": null,"content": "ELSEVIER","format": null,"content_tags": null},{"type": "title","bbox": [0.157,0.228,0.833,0.253],"angle": 0,"score": null,"block_tags": null,"content": "The response of flow duration curves to afforestation","format": null,"content_tags": null}]]
中间处理结果 (middle.json)
文件命名格式:{原文件名}_middle.json
文件格式说明
vlm 后端的 middle.json 文件结构与 pipeline 后端类似,但存在以下差异:
list变成二级block,增加sub_type字段区分list类型:- text(文本类型)
- ref_text(引用类型)
- 增加
code类型block,code类型包含两种"sub_type":- 分别是code和algorithm
- 至少有code_body, 可选code_caption
discarded_blocks内元素type增加以下类型:- header(页眉)
- footer(页脚)
- page_number(页码)
- aside_text(装订线文本)
- page_footnote(脚注)
- 所有
block增加angle字段,用来表示旋转角度,0,90,180,270
示例数据
list block 示例
{"bbox": [174,155,818,333],"type": "list","angle": 0,"index": 11,"blocks": [{"bbox": [174,157,311,175],"type": "text","angle": 0,"lines": [{"bbox": [174,157,311,175],"spans": [{"bbox": [174,157,311,175],"type": "text","content": "H.1 Introduction"}]}],"index": 3},{"bbox": [175,182,464,229],"type": "text","angle": 0,"lines": [{"bbox": [175,182,464,229],"spans": [{"bbox": [175,182,464,229],"type": "text","content": "H.2 Example: Divide by Zero without Exception Handling"}]}],"index": 4}],"sub_type": "text"}
code block 示例
{"type": "code","bbox": [114,780,885,1231],"blocks": [{"bbox": [114,780,885,1231],"lines": [{"bbox": [114,780,885,1231],"spans": [{"bbox": [114,780,885,1231],"type": "text","content": "1 // Fig. H.1: DivideByZeroNoExceptionHandling.java \n2 // Integer division without exception handling. \n3 import java.util.Scanner; \n4 \n5 public class DivideByZeroNoExceptionHandling \n6 { \n7 // demonstrates throwing an exception when a divide-by-zero occurs \n8 public static int quotient( int numerator, int denominator ) \n9 { \n10 return numerator / denominator; // possible division by zero \n11 } // end method quotient \n12 \n13 public static void main(String[] args) \n14 { \n15 Scanner scanner = new Scanner(http://System.in); // scanner for input \n16 \n17 System.out.print(\"Please enter an integer numerator: \"); \n18 int numerator = scanner.nextInt(); \n19 System.out.print(\"Please enter an integer denominator: \"); \n20 int denominator = scanner.nextInt(); \n21"}]}],"index": 17,"angle": 0,"type": "code_body"},{"bbox": [867,160,1280,189],"lines": [{"bbox": [867,160,1280,189],"spans": [{"bbox": [867,160,1280,189],"type": "text","content": "Algorithm 1 Modules for MCTSteg"}]}],"index": 19,"angle": 0,"type": "code_caption"}],"index": 17,"sub_type": "code"}
内容列表 (content_list.json)
文件命名格式:{原文件名}_content_list.json
文件格式说明
vlm 后端的 content_list.json 文件结构与 pipeline 后端类似,伴随本次middle.json的变化,做了以下调整:
- 新增code类型,code类型包含两种”sub_type”:
- 分别是code和algorithm
- 至少有code_body, 可选code_caption
- 新增list类型,list类型包含两种”sub_type”:
- text
- ref_text
- 增加所有所有discarded_blocks的输出内容
- header
- footer
- page_number
- aside_text
- page_footnote
示例数据
code 类型 content
{"type": "code","sub_type": "algorithm","code_caption": ["Algorithm 1 Modules for MCTSteg"],"code_body": "1: function GETCOORDINATE(d) \n2: $x \\gets d / l$ , $y \\gets d$ mod $l$ \n3: return $(x, y)$ \n4: end function \n5: function BESTCHILD(v) \n6: $C \\gets$ child set of $v$ \n7: $v' \\gets \\arg \\max_{c \\in C} \\mathrm{UCTScore}(c)$ \n8: $v'.n \\gets v'.n + 1$ \n9: return $v'$ \n10: end function \n11: function BACK PROPAGATE(v) \n12: Calculate $R$ using Equation 11 \n13: while $v$ is not a root node do \n14: $v.r \\gets v.r + R$ , $v \\gets v.p$ \n15: end while \n16: end function \n17: function RANDOMSEARCH(v) \n18: while $v$ is not a leaf node do \n19: Randomly select an untried action $a \\in A(v)$ \n20: Create a new node $v'$ \n21: $(x, y) \\gets \\mathrm{GETCOORDINATE}(v'.d)$ \n22: $v'.p \\gets v$ , $v'.d \\gets v.d + 1$ , $v'.\\Gamma \\gets v.\\Gamma$ \n23: $v'.\\gamma_{x,y} \\gets a$ \n24: if $a = -1$ then \n25: $v.lc \\gets v'$ \n26: else if $a = 0$ then \n27: $v.mc \\gets v'$ \n28: else \n29: $v.rc \\gets v'$ \n30: end if \n31: $v \\gets v'$ \n32: end while \n33: return $v$ \n34: end function \n35: function SEARCH(v) \n36: while $v$ is fully expanded do \n37: $v \\gets$ BESTCHILD(v) \n38: end while \n39: if $v$ is not a leaf node then \n40: $v \\gets$ RANDOMSEARCH(v) \n41: end if \n42: return $v$ \n43: end function","bbox": [510,87,881,740],"page_idx": 0}
list 类型 content
{"type": "list","sub_type": "text","list_items": ["H.1 Introduction","H.2 Example: Divide by Zero without Exception Handling","H.3 Example: Divide by Zero with Exception Handling","H.4 Summary"],"bbox": [174,155,818,333],"page_idx": 0}
discarded 类型 content
[{"type": "header","text": "Journal of Hydrology 310 (2005) 253-265","bbox": [363,164,623,177],"page_idx": 0},{"type": "page_footnote","text": "* Corresponding author. Address: Forest Science Centre, Department of Sustainability and Environment, P.O. Box 137, Heidelberg, Vic. 3084, Australia. Tel.: +61 3 9450 8719; fax: +61 3 9450 8644.","bbox": [71,815,915,841],"page_idx": 0}]
