本地用docling实现pdf转markdown操作笔记

docling原理悉知

Docling 是一个开源的 python 文档处理库,由 IBM 开发,用于将 PDFDOCXPPTXXLSX、图像、HTML 等文档转换为结构化的 MarkdownJSON 格式,为构建 AI 驱动的 RAG/QA 应用提供了高效、便捷的解决方案。

其使用的技术可以总结为:

1.布局分析模型 首先,Docling使用一个布局分析模型,这是一个对象检测器,用于预测给定页面图像上各种元素的边界框和类别。

2.表格结构识别模型:其次,Docling使用TableFormer 表格结构识别模型模型。它可以根据输入图像预测给定表格的逻辑行和列结构。推理依赖于PyTorch。

3.OCR文字识别:Docling还提供了可选的OCR支持,例如用于扫描件PDF 。默认情况下,Docling使用EasyOCR 引擎,该引擎以高分辨率(216 dpi)页面图像进行OCR,以捕获小字体细节。

4.处理管道:Docling实现了一个线性处理管道,按顺序对每个文档执行操作。每个文档首先由PDF后端解析,以检索程序化文本标记和渲染每页的位图图像。然后,标准模型管道独立应用于文档中的每一页,以提取特征和内容,如布局和表格结构。最后,所有页面的结果汇总并通过后处理阶段传递,以增强元数据、检测文档语言、推断阅读顺序并最终组装一个可序列化为JSON或Markdown 的类型化文档对象。

Docling处理阶段:

1.预处理阶段:图像增强、倾斜校正、分辨率调整。

2.内容提取阶段:OCR识别(大模型)、布局分析(大模型)、元素关联。

1.布局模型:文档元素检测:识别文档中的文本块、表格、图像、标题等元素。

2.元素分类:将检测到的元素分类为不同的类型。

3.阅读顺序确定:确定文档元素的逻辑阅读顺序。

4.结构化输出:为后续处理步骤提供结构化的文档表示。

3.结构增强阶段:公式转换、表格结构化、引用解析。

本地化部署

步骤1:创建虚拟环境

python 复制代码
#创建虚拟环境
conda create -n doclingenv python=3.11 -y
#激活虚拟环境
conda activate doclingenv

步骤2:安装相关依赖

python 复制代码
# 安装docling
pip install docling

在下载的时候观察到会自动下载cpu版本的torch。运行下述代码检测是否安装了支持gpu版本的torch:

python 复制代码
import torch

# 检查CUDA是否可用
print("CUDA是否可用:", torch.cuda.is_available())

if torch.cuda.is_available():
    # 查看可用GPU数量
    print("可用GPU数量:", torch.cuda.device_count())
    
    # 查看当前使用的GPU索引
    print("当前GPU索引:", torch.cuda.current_device())
    
    # 查看GPU名称
    print("GPU名称:", torch.cuda.get_device_name(torch.cuda.current_device()))
else:
    print("未检测到可用的GPU,PyTorch将使用CPU进行计算")

发现,应该在安装docling库时自动下载了支持gpu版本的torch,这为后续使用gpu加速来计算提供了便利。

步骤3:运行下述代码

python 复制代码
from docling.document_converter import DocumentConverter

source = "test.pdf"  
output = "01.md"

converter = DocumentConverter()
result = converter.convert(source)

with open(output, "w", encoding = "utf-8") as f:
    f.write(result.document.export_to_markdown())

print("docling已完成解析!")

报错:

#网络无法访问 Hugging Face,导致 docling 初始化时无法自动下载必需的布局模型。

阅读下述链接可以发现

​​​​​​​Docling学习笔记(含本地部署教程)_docling本地部署-CSDN博客

想要用本地下载好的模型,必须学习docling的源码然后传递参数。好在上述博客已经对源码进行了深度学习,我们只需按照步骤来操作如何定义使用自己的模型。

步骤4:下载模型

首先,安装库:

python 复制代码
pip install modelscope

下载模型:ms-agent/docling-models。这里边包括了布局检测和表格模型。

布局检测模型:给 PDF 页面 "分区" ------ 把页面图像中的内容按 "布局类型" 分开,比如识别出哪里是标题(Title)、哪里是表格(Table)、哪里是公式(Formula)、哪里是脚注(Footnote)等,共 11 种布局组件(完整列表见表格第一列)。技术基础:基于 RT-DETR 模型(一种高效的目标检测模型)实现,能快速且准确地定位不同内容区域。

TableFormer(表格结构识别模型):专门处理 "表格" 的结构化提取------ 当 Layout Model 识别出 "这是一个表格" 后,TableFormer 会进一步分析表格的行、列、单元格(比如哪几行是表头、单元格是否跨行跨列),最终把 PDF 中的 "图片表格" 转成可编辑的 "结构化表格"(对应你看到的 Markdown 表格)。工作流程:依赖 Layout Model 的输出(先找到表格在哪里),再聚焦表格区域做精细化分析。

下载easyocr模型

下载模型脚本:

python 复制代码
import os
from modelscope import snapshot_download

# 定义主目录:当前目录下的 docling_model
main_dir = os.path.join(os.getcwd(), "docling_model")

# 为两个模型分别创建独立的子目录
docling_subdir = os.path.join(main_dir, "docling-models")  # docling模型子目录
easyocr_subdir = os.path.join(main_dir, "easyocr-models")  # easyocr模型子目录

# 创建目录(如果不存在)
os.makedirs(docling_subdir, exist_ok=True)
os.makedirs(easyocr_subdir, exist_ok=True)

# 下载docling模型(保存到专属子目录)
docling_model_dir = snapshot_download(
    model_id='ms-agent/docling-models',
    local_dir=docling_subdir
)
print(f'docling模型下载完成,路径: {docling_model_dir}')

# 下载easyocr模型(保存到专属子目录)
easyocr_model_dir = snapshot_download(
    model_id='Ceceliachenen/easyocr',
    local_dir=easyocr_subdir
)
print(f'easyocr模型下载完成,路径: {easyocr_model_dir}')
    

步骤5,用下载的模型来实现转md。

运行下述脚本:

python 复制代码
import os  # 导入os模块处理路径
from docling.datamodel.base_models import InputFormat, ImageRefMode  # 补充ImageRefMode导入
from docling.datamodel.pipeline_options import PdfPipelineOptions, EasyOcrOptions
from docling.document_converter import (
    PdfFormatOption, DocumentConverter, 
    ImageFormatOption, PowerpointFormatOption, 
    WordFormatOption, ExcelFormatOption, HTMLFormatOption
)

# -------------------------- 1. 配置OCR模型(EasyOCR)--------------------------
# 用os.path.join拼接路径,自动适配Linux/Windows
easyocr_model_storage_directory = os.path.join("docling_model", "easyocr-models")
easyocr_options = EasyOcrOptions()
easyocr_options.lang = ['ch_sim', 'en']  # 中文+英文识别
easyocr_options.model_storage_directory = easyocr_model_storage_directory

# -------------------------- 2. 配置PDF核心模型(docling)--------------------------
# 拼接docling模型路径,确保Linux下解析为 docling_model/docling-models
pdf_artifacts_path = os.path.join("docling_model", "docling-models")

# 验证路径是否存在(避免路径不存在导致的错误)
if not os.path.exists(pdf_artifacts_path):
    raise FileNotFoundError(f"docling模型路径不存在:{pdf_artifacts_path}\n请确认模型已下载到该路径")

# 初始化PDF管道配置
pipeline_options = PdfPipelineOptions(artifacts_path=pdf_artifacts_path)
pipeline_options.do_ocr = True  # 启用OCR(处理扫描件)
pipeline_options.do_table_structure = True  # 启用表格结构提取
pipeline_options.ocr_options = easyocr_options  # 关联OCR配置

# -------------------------- 3. 初始化文档转换器--------------------------
converter = DocumentConverter(
    format_options={
        InputFormat.PDF: PdfFormatOption(pipeline_options=pipeline_options),
        InputFormat.IMAGE: ImageFormatOption(pipeline_options=pipeline_options),
        InputFormat.PPTX: PowerpointFormatOption(pipeline_options=pipeline_options),
        InputFormat.DOCX: WordFormatOption(pipeline_options=pipeline_options),
        InputFormat.XLSX: ExcelFormatOption(pipeline_options=pipeline_options),
        InputFormat.HTML: HTMLFormatOption(pipeline_options=pipeline_options)
    }
)

# -------------------------- 4. 执行转换并保存--------------------------
source = "test.pdf"  # 输入PDF路径(确保该文件存在)
output = "01.md"     # 输出Markdown路径

# 验证输入PDF是否存在
if not os.path.exists(source):
    raise FileNotFoundError(f"输入PDF不存在:{source}")

# 执行转换
result = converter.convert(source)

# 保存Markdown(使用ImageRefMode.EMBEDDED嵌入图片)
with open(output, "w", encoding="utf-8") as f:
    f.write(result.document.export_to_markdown(image_mode=ImageRefMode.EMBEDDED))

print(f"docling已完成解析!Markdown文件保存至:{os.path.abspath(output)}")

报错:ImageRefMode 的实际导入路径与 docling 版本不匹配。

ImageRefMode 是一个枚举类型,用于控制图片在导出的 Markdown 文档中的呈现方式。它有三个选项:

PLACEHOLDER - 占位符模式:只在文档中保留图片的位置,不实际嵌入或引用图片;

EMBEDDED - 嵌入模式:将图片以 base64 编码的形式直接嵌入到 Markdown 文档中;

REFERENCED - 引用模式:将图片保存为外部 PNG 文件,并在 Markdown 中通过链接引用这些图片。

修改代码如下

from docling_core.types.doc import ImageRefMode

#增加图片处理配置

启用图片生成功能,使文档中的图片能够被提取和处理

pipeline_options.generate_picture_images = True

设置图片缩放比例为2.0,提高导出图片的质量

pipeline_options.images_scale = 2.0

python 复制代码
import os  # 导入os模块处理路径
from docling.datamodel.base_models import InputFormat  # 补充ImageRefMode导入
from docling.datamodel.pipeline_options import PdfPipelineOptions, EasyOcrOptions
from docling.document_converter import (
    PdfFormatOption, DocumentConverter, 
    ImageFormatOption, PowerpointFormatOption, 
    WordFormatOption, ExcelFormatOption, HTMLFormatOption
)
# 导入ImageRefMode枚举类,用于控制图片在Markdown中的呈现方式
from docling_core.types.doc import ImageRefMode
# -------------------------- 1. 配置OCR模型(EasyOCR)--------------------------
# 用os.path.join拼接路径,自动适配Linux/Windows
easyocr_model_storage_directory = os.path.join("docling_model", "easyocr-models")
easyocr_options = EasyOcrOptions()
easyocr_options.lang = ['ch_sim', 'en']  # 中文+英文识别
easyocr_options.model_storage_directory = easyocr_model_storage_directory

# -------------------------- 2. 配置PDF核心模型(docling)--------------------------
# 拼接docling模型路径,确保Linux下解析为 docling_model/docling-models
pdf_artifacts_path = os.path.join("docling_model", "docling-models")

# 验证路径是否存在(避免路径不存在导致的错误)
if not os.path.exists(pdf_artifacts_path):
    raise FileNotFoundError(f"docling模型路径不存在:{pdf_artifacts_path}\n请确认模型已下载到该路径")

# 初始化PDF管道配置
pipeline_options = PdfPipelineOptions(artifacts_path=pdf_artifacts_path)
pipeline_options.do_ocr = True  # 启用OCR(处理扫描件)
pipeline_options.do_table_structure = True  # 启用表格结构提取
pipeline_options.ocr_options = easyocr_options  # 关联OCR配置
#增加图片处理配置
# 启用图片生成功能,使文档中的图片能够被提取和处理
pipeline_options.generate_picture_images = True
# 设置图片缩放比例为2.0,提高导出图片的质量
pipeline_options.images_scale = 2.0
# -------------------------- 3. 初始化文档转换器--------------------------
converter = DocumentConverter(
    format_options={
        InputFormat.PDF: PdfFormatOption(pipeline_options=pipeline_options),
        InputFormat.IMAGE: ImageFormatOption(pipeline_options=pipeline_options),
        InputFormat.PPTX: PowerpointFormatOption(pipeline_options=pipeline_options),
        InputFormat.DOCX: WordFormatOption(pipeline_options=pipeline_options),
        InputFormat.XLSX: ExcelFormatOption(pipeline_options=pipeline_options),
        InputFormat.HTML: HTMLFormatOption(pipeline_options=pipeline_options)
    }
)

# -------------------------- 4. 执行转换并保存--------------------------
source = "test.pdf"  # 输入PDF路径(确保该文件存在)
output = "01.md"     # 输出Markdown路径

# 验证输入PDF是否存在
if not os.path.exists(source):
    raise FileNotFoundError(f"输入PDF不存在:{source}")

# 执行转换
result = converter.convert(source)

# 保存Markdown(使用ImageRefMode.EMBEDDED嵌入图片)
with open(output, "w", encoding="utf-8") as f:
    f.write(result.document.export_to_markdown(image_mode=ImageRefMode.EMBEDDED))

print(f"docling已完成解析!Markdown文件保存至:{os.path.abspath(output)}")

报错:easyocr 库未安装。

复制代码
pip install easyocr

报错:FileNotFoundError: Missing safe tensors file: docling_model/docling-models/model_artifacts/model.safetensors.

解决办法:

layout模型的权重需要放到model_artifacts下。

table模型的权重需要放到model_artifacts/accurate下。

到这里,docling已经可以成功将pdf转换成markdown。

效果优化

1.用gpu加速的参数设置。

python 复制代码
import os
import torch  # 用于验证GPU环境
from docling.datamodel.base_models import InputFormat
from docling.datamodel.pipeline_options import (
    PdfPipelineOptions, 
    EasyOcrOptions,
    AcceleratorOptions,  # 导入GPU加速器配置类
    AcceleratorDevice    # 导入设备类型(CUDA/CPU)
)
from docling.document_converter import (
    PdfFormatOption, DocumentConverter, 
    ImageFormatOption, PowerpointFormatOption, 
    WordFormatOption, ExcelFormatOption, HTMLFormatOption
)
from docling_core.types.doc import ImageRefMode


# 第一步:先验证GPU环境(避免配置后无效)
def check_gpu_env():
    if not torch.cuda.is_available():
        raise RuntimeError(
            "未检测到可用GPU环境!请先安装GPU版本的PyTorch,安装命令参考:\n"
            "pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118"
        )
    print(f"✅ 检测到GPU环境:{torch.cuda.get_device_name(0)}(CUDA版本:{torch.version.cuda})")

# 验证GPU环境(若失败直接报错)
check_gpu_env()


# -------------------------- 1. 配置OCR模型(EasyOCR,启用GPU)--------------------------
easyocr_model_storage_directory = os.path.join("docling_model", "easyocr-models")
easyocr_options = EasyOcrOptions()
easyocr_options.lang = ['ch_sim', 'en']  # 中英双语识别
easyocr_options.model_storage_directory = easyocr_model_storage_directory
easyocr_options.use_gpu = True  # 关键:启用EasyOCR的GPU加速
easyocr_options.force_full_page_ocr = True  # 整页OCR(提升识别完整性)


# -------------------------- 2. 配置PDF核心模型(docling,添加GPU加速)--------------------------
pdf_artifacts_path = os.path.join("docling_model", "docling-models", "model_artifacts")

# 验证模型路径存在
if not os.path.exists(pdf_artifacts_path):
    raise FileNotFoundError(f"docling模型路径不存在:{pdf_artifacts_path}\n请确认模型已下载到该路径")

# 初始化PDF管道配置(核心:添加AcceleratorOptions)
pipeline_options = PdfPipelineOptions(artifacts_path=pdf_artifacts_path)
pipeline_options.do_ocr = True  # 启用OCR(处理扫描件)
pipeline_options.do_table_structure = True  # 启用表格结构提取
pipeline_options.ocr_options = easyocr_options  # 关联OCR的GPU配置

# 关键:配置GPU加速器(指定使用CUDA)
pipeline_options.accelerator_options = AcceleratorOptions(
    device=AcceleratorDevice.CUDA,  # 使用NVIDIA GPU(核心配置)
    num_threads=4  # 并行线程数(建议设为CPU核心数的1/2,避免CPU瓶颈)
)

# 图片处理配置(不影响GPU加速,保持原功能)
pipeline_options.generate_picture_images = True
pipeline_options.images_scale = 2.0  # 图片缩放比例(1.0-3.0为宜,值越大越清晰但耗时更长)


# -------------------------- 3. 初始化文档转换器--------------------------
converter = DocumentConverter(
    format_options={
        InputFormat.PDF: PdfFormatOption(pipeline_options=pipeline_options),
        InputFormat.IMAGE: ImageFormatOption(pipeline_options=pipeline_options),
        InputFormat.PPTX: PowerpointFormatOption(pipeline_options=pipeline_options),
        InputFormat.DOCX: WordFormatOption(pipeline_options=pipeline_options),
        InputFormat.XLSX: ExcelFormatOption(pipeline_options=pipeline_options),
        InputFormat.HTML: HTMLFormatOption(pipeline_options=pipeline_options)
    }
)


# -------------------------- 4. 执行转换(带GPU加速)并保存--------------------------
source = "test.pdf"  # 输入PDF路径
output = "01.md"     # 输出Markdown路径

# 验证输入PDF存在
if not os.path.exists(source):
    raise FileNotFoundError(f"输入PDF不存在:{source}")

# 执行转换(记录GPU加速耗时)
import time
start_time = time.time()
print(f"🔄 开始转换PDF(GPU加速):{source}")
try:
    result = converter.convert(source)
    conversion_time = time.time() - start_time
    print(f"✅ PDF转换完成,耗时:{conversion_time:.2f}秒(GPU加速)")
except Exception as e:
    raise RuntimeError(f"转换失败:{e}") from e

# 保存Markdown(嵌入图片)
with open(output, "w", encoding="utf-8") as f:
    f.write(result.document.export_to_markdown(image_mode=ImageRefMode.EMBEDDED))

print(f"📄 Markdown文件已保存至:{os.path.abspath(output)}")

2.将图片提取出来放到一个文件夹内,然后以本地路径嵌入markdown文档。

为了后续能够处理图片,这里我不采用Base64编

python 复制代码
import os
import time
import torch
from pathlib import Path

# Docling 相关导入
from docling.datamodel.base_models import InputFormat
from docling.datamodel.pipeline_options import (
    PdfPipelineOptions, EasyOcrOptions, AcceleratorOptions, AcceleratorDevice
)
from docling.document_converter import (
    DocumentConverter, PdfFormatOption,
    ImageFormatOption, PowerpointFormatOption,
    WordFormatOption, ExcelFormatOption, HTMLFormatOption
)
from docling_core.types.doc import ImageRefMode


# -------------------------- 1. GPU 环境验证 --------------------------
def check_gpu_env():
    """检查并验证GPU环境是否可用。"""
    if not torch.cuda.is_available():
        raise RuntimeError(
            "未检测到可用GPU环境!请安装GPU版PyTorch:\n"
            "pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118"
        )
    print(f"✅ 检测到GPU环境:{torch.cuda.get_device_name(0)}(CUDA版本:{torch.version.cuda})")

check_gpu_env()


# -------------------------- 2. OCR 和 PDF 管道配置 --------------------------
# 配置EasyOCR选项
easyocr_model_storage_directory = os.path.join("docling_model", "easyocr-models")
easyocr_options = EasyOcrOptions()
easyocr_options.lang = ['ch_sim', 'en']  # 支持中文简体和英文
easyocr_options.model_storage_directory = easyocr_model_storage_directory
easyocr_options.use_gpu = True
easyocr_options.force_full_page_ocr = True

# 配置Docling模型路径
pdf_artifacts_path = os.path.join("docling_model", "docling-models", "model_artifacts")
if not os.path.exists(pdf_artifacts_path):
    raise FileNotFoundError(
        f"Docling模型路径不存在:{pdf_artifacts_path}\n"
        f"请执行命令下载:docling-download-models --output-dir {pdf_artifacts_path}"
    )

# 配置PDF处理管道
pipeline_options = PdfPipelineOptions(
    artifacts_path=pdf_artifacts_path,
    images_scale=2.0,  # 提高图片导出质量
    generate_picture_images=True,
    do_ocr=True,
    do_table_structure=True,
    ocr_options=easyocr_options,
    accelerator_options=AcceleratorOptions(
        device=AcceleratorDevice.CUDA,
        num_threads=4
    ),
    # --- 关键配置:强制生成页面图片 ---
    # 这能确保即使PDF中的图片无法被单独提取,每一页也会被保存为一张图片
    generate_page_images=True,
    keep_images_raw=False,
)

# -------------------------- 3. 初始化转换器 --------------------------
converter = DocumentConverter(
    format_options={
        InputFormat.PDF: PdfFormatOption(pipeline_options=pipeline_options),
        InputFormat.IMAGE: ImageFormatOption(pipeline_options=pipeline_options),
        InputFormat.PPTX: PowerpointFormatOption(pipeline_options=pipeline_options),
        InputFormat.DOCX: WordFormatOption(pipeline_options=pipeline_options),
        InputFormat.XLSX: ExcelFormatOption(pipeline_options=pipeline_options),
        InputFormat.HTML: HTMLFormatOption(pipeline_options=pipeline_options)
    }
)

# -------------------------- 4. 定义输入/输出路径 --------------------------
source_pdf = "test.pdf"
output_md = "01.md"
# 定义图片保存的目录名
image_assets_dir_name = "figures"

# 检查输入文件是否存在
if not os.path.exists(source_pdf):
    raise FileNotFoundError(f"输入PDF不存在:{source_pdf}")

# -------------------------- 5. 执行转换 --------------------------
start_time = time.time()
print(f"🔄 开始转换PDF(GPU加速):{source_pdf}")
try:
    conv_res = converter.convert(source_pdf)
    print(f"✅ PDF转换完成,耗时:{time.time() - start_time:.2f}秒")
except Exception as e:
    raise RuntimeError(f"转换失败:{e}") from e

# -------------------------- 6. 保存为Markdown(最终修正版) --------------------------
print(f"🔄 开始保存Markdown和图片...")
try:
    # 将目录名转换为 Path 对象
    image_assets_path = Path(image_assets_dir_name)

    # 调用save_as_markdown方法
    conv_res.document.save_as_markdown(
        filename=output_md,
        image_mode=ImageRefMode.REFERENCED,
        artifacts_dir=image_assets_path  # 传递 Path 对象
    )
    print(f"✅ Markdown已生成:{os.path.abspath(output_md)}")

    # --- 修正:检查我们实际指定的图片目录 ---
    if image_assets_path.exists():
        print(f"🖼️  图片已保存至:{image_assets_path.resolve()}")
        # (可选) 列出保存的图片文件以供确认
        image_files = [f.name for f in image_assets_path.iterdir() if f.is_file()]
        if image_files:
            print(f"   包含的图片文件: {', '.join(image_files)}")
        else:
            print("   目录已创建,但为空。")
    else:
        # 如果这个目录真的不存在,那才是一个真正的问题
        print("⚠️  错误:指定的图片目录未生成!")

except Exception as e:
    raise RuntimeError(f"保存Markdown失败:{e}") from e

print("\n🎉 所有任务已完成!")

码嵌入图片,而是保存为本地绝对路径。

这里报了很久的错,原因在于,项目自定义需要的参数不清晰,因此需要查看源码。。。。一直忙其他工作,没时间看源码。看了一下就清楚多了:

找到:save_as_markdown函数的源码:/home/agent/anaconda3/envs/doclingenv/lib/python3.11/site-packages/docling_core/types/doc/document.py

python 复制代码
def save_as_markdown(
    self,
    filename: Union[str, Path],              # 1. Markdown 文件的路径
    artifacts_dir: Optional[Path] = None,     # 2. 图片存放的目录
    # ... 其他参数 ...
    image_mode: ImageRefMode = ImageRefMode.PLACEHOLDER, # 3. 图片引用模式
    # ...
):

最终成功运行代码:

python 复制代码
import os
import time
import torch
from pathlib import Path

# Docling 相关导入
from docling.datamodel.base_models import InputFormat
from docling.datamodel.pipeline_options import (
    PdfPipelineOptions, EasyOcrOptions, AcceleratorOptions, AcceleratorDevice
)
from docling.document_converter import (
    DocumentConverter, PdfFormatOption,
    ImageFormatOption, PowerpointFormatOption,
    WordFormatOption, ExcelFormatOption, HTMLFormatOption
)
from docling_core.types.doc import ImageRefMode


# -------------------------- 1. GPU 环境验证 --------------------------
def check_gpu_env():
    """检查并验证GPU环境是否可用。"""
    if not torch.cuda.is_available():
        raise RuntimeError(
            "未检测到可用GPU环境!请安装GPU版PyTorch:\n"
            "pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118"
        )
    print(f"✅ 检测到GPU环境:{torch.cuda.get_device_name(0)}(CUDA版本:{torch.version.cuda})")

check_gpu_env()


# -------------------------- 2. OCR 和 PDF 管道配置 --------------------------
# 配置EasyOCR选项
easyocr_model_storage_directory = os.path.join("docling_model", "easyocr-models")
easyocr_options = EasyOcrOptions()
easyocr_options.lang = ['ch_sim', 'en']  # 支持中文简体和英文
easyocr_options.model_storage_directory = easyocr_model_storage_directory
easyocr_options.use_gpu = True
easyocr_options.force_full_page_ocr = True

# 配置Docling模型路径
pdf_artifacts_path = os.path.join("docling_model", "docling-models", "model_artifacts")
if not os.path.exists(pdf_artifacts_path):
    raise FileNotFoundError(
        f"Docling模型路径不存在:{pdf_artifacts_path}\n"
        f"请执行命令下载:docling-download-models --output-dir {pdf_artifacts_path}"
    )

# 配置PDF处理管道
pipeline_options = PdfPipelineOptions(
    artifacts_path=pdf_artifacts_path,
    images_scale=2.0,  # 提高图片导出质量
    generate_picture_images=True,
    do_ocr=True,
    do_table_structure=True,
    ocr_options=easyocr_options,
    accelerator_options=AcceleratorOptions(
        device=AcceleratorDevice.CUDA,
        num_threads=4
    ),
    # --- 关键配置:强制生成页面图片 ---
    # 这能确保即使PDF中的图片无法被单独提取,每一页也会被保存为一张图片
    generate_page_images=True,
    keep_images_raw=False,
)

# -------------------------- 3. 初始化转换器 --------------------------
converter = DocumentConverter(
    format_options={
        InputFormat.PDF: PdfFormatOption(pipeline_options=pipeline_options),
        InputFormat.IMAGE: ImageFormatOption(pipeline_options=pipeline_options),
        InputFormat.PPTX: PowerpointFormatOption(pipeline_options=pipeline_options),
        InputFormat.DOCX: WordFormatOption(pipeline_options=pipeline_options),
        InputFormat.XLSX: ExcelFormatOption(pipeline_options=pipeline_options),
        InputFormat.HTML: HTMLFormatOption(pipeline_options=pipeline_options)
    }
)

# -------------------------- 4. 定义输入/输出路径 --------------------------
source_pdf = "test.pdf"
output_md = "01.md"
# 定义图片保存的目录名
image_assets_dir_name = "figures"

# 检查输入文件是否存在
if not os.path.exists(source_pdf):
    raise FileNotFoundError(f"输入PDF不存在:{source_pdf}")

# -------------------------- 5. 执行转换 --------------------------
start_time = time.time()
print(f"🔄 开始转换PDF(GPU加速):{source_pdf}")
try:
    conv_res = converter.convert(source_pdf)
    print(f"✅ PDF转换完成,耗时:{time.time() - start_time:.2f}秒")
except Exception as e:
    raise RuntimeError(f"转换失败:{e}") from e

# -------------------------- 6. 保存为Markdown(最终修正版) --------------------------
print(f"🔄 开始保存Markdown和图片...")
try:
    # 将目录名转换为 Path 对象
    image_assets_path = Path(image_assets_dir_name)

    # 调用save_as_markdown方法
    conv_res.document.save_as_markdown(
        filename=output_md,
        image_mode=ImageRefMode.REFERENCED,
        artifacts_dir=image_assets_path  # 传递 Path 对象
    )
    print(f"✅ Markdown已生成:{os.path.abspath(output_md)}")

    # --- 修正:检查我们实际指定的图片目录 ---
    if image_assets_path.exists():
        print(f"🖼️  图片已保存至:{image_assets_path.resolve()}")
        # (可选) 列出保存的图片文件以供确认
        image_files = [f.name for f in image_assets_path.iterdir() if f.is_file()]
        if image_files:
            print(f"   包含的图片文件: {', '.join(image_files)}")
        else:
            print("   目录已创建,但为空。")
    else:
        # 如果这个目录真的不存在,那才是一个真正的问题
        print("⚠️  错误:指定的图片目录未生成!")

except Exception as e:
    raise RuntimeError(f"保存Markdown失败:{e}") from e

print("\n🎉 所有任务已完成!")

优化图片名称后的最新代码:

python 复制代码
import os
import time
import torch
import re
import shutil
from pathlib import Path
from collections import defaultdict

# Docling 相关导入
from docling.datamodel.base_models import InputFormat
from docling.datamodel.pipeline_options import (
    PdfPipelineOptions, EasyOcrOptions, AcceleratorOptions, AcceleratorDevice
)
from docling.document_converter import (
    DocumentConverter, PdfFormatOption,
    ImageFormatOption, PowerpointFormatOption,
    WordFormatOption, ExcelFormatOption, HTMLFormatOption
)
from docling_core.types.doc import ImageRefMode, PictureItem


# -------------------------- 1. GPU 环境验证 --------------------------
def check_gpu_env():
    """检查并验证GPU环境是否可用。"""
    if not torch.cuda.is_available():
        raise RuntimeError(
            "未检测到可用GPU环境!请安装GPU版PyTorch:\n"
            "pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118"
        )
    print(f"✅ 检测到GPU环境:{torch.cuda.get_device_name(0)}(CUDA版本:{torch.version.cuda})")

check_gpu_env()


# -------------------------- 2. OCR 和 PDF 管道配置 --------------------------
# 配置EasyOCR选项
easyocr_model_storage_directory = os.path.join("docling_model", "easyocr-models")
easyocr_options = EasyOcrOptions()
easyocr_options.lang = ['ch_sim', 'en']  # 支持中文简体和英文
easyocr_options.model_storage_directory = easyocr_model_storage_directory
easyocr_options.use_gpu = True
easyocr_options.force_full_page_ocr = True

# 配置Docling模型路径
pdf_artifacts_path = os.path.join("docling_model", "docling-models", "model_artifacts")
if not os.path.exists(pdf_artifacts_path):
    raise FileNotFoundError(
        f"Docling模型路径不存在:{pdf_artifacts_path}\n"
        f"请执行命令下载:docling-download-models --output-dir {pdf_artifacts_path}"
    )

# 配置PDF处理管道
pipeline_options = PdfPipelineOptions(
    artifacts_path=pdf_artifacts_path,
    images_scale=2.0,  # 提高图片导出质量
    generate_picture_images=True,
    do_ocr=True,
    do_table_structure=True,
    ocr_options=easyocr_options,
    accelerator_options=AcceleratorOptions(
        device=AcceleratorDevice.CUDA,
        num_threads=4
    ),
    # --- 关键配置:强制生成页面图片 ---
    # 这能确保即使PDF中的图片无法被单独提取,每一页也会被保存为一张图片
    generate_page_images=True,
    keep_images_raw=False,
)

# -------------------------- 3. 初始化转换器 --------------------------
converter = DocumentConverter(
    format_options={
        InputFormat.PDF: PdfFormatOption(pipeline_options=pipeline_options),
        InputFormat.IMAGE: ImageFormatOption(pipeline_options=pipeline_options),
        InputFormat.PPTX: PowerpointFormatOption(pipeline_options=pipeline_options),
        InputFormat.DOCX: WordFormatOption(pipeline_options=pipeline_options),
        InputFormat.XLSX: ExcelFormatOption(pipeline_options=pipeline_options),
        InputFormat.HTML: HTMLFormatOption(pipeline_options=pipeline_options)
    }
)

# -------------------------- 4. 定义输入/输出路径 --------------------------
source_pdf = "test.pdf"
output_md = "01.md"
# 定义图片保存的目录名
image_assets_dir_name = "figures"

# 检查输入文件是否存在
if not os.path.exists(source_pdf):
    raise FileNotFoundError(f"输入PDF不存在:{source_pdf}")

# -------------------------- 5. 执行转换 --------------------------
start_time = time.time()
print(f"🔄 开始转换PDF(GPU加速):{source_pdf}")
try:
    conv_res = converter.convert(source_pdf)
    print(f"✅ PDF转换完成,耗时:{time.time() - start_time:.2f}秒")
except Exception as e:
    raise RuntimeError(f"转换失败:{e}") from e

# -------------------------- 6. 保存为Markdown(初步保存) --------------------------
print(f"🔄 初步保存Markdown和图片...")
try:
    image_assets_path = Path(image_assets_dir_name)
    conv_res.document.save_as_markdown(
        filename=output_md,
        image_mode=ImageRefMode.REFERENCED,
        artifacts_dir=image_assets_path
    )
    print(f"✅ Markdown已初步生成:{os.path.abspath(output_md)}")
except Exception as e:
    raise RuntimeError(f"保存Markdown失败:{e}") from e


# -------------------------- 7. 新增:按页码和序号重命名图片 (修正版) --------------------------
def rename_images_by_page_and_order(md_path: Path, images_dir: Path, doc_result):
    """
    按照 '页码_序号' 的规则重命名图片,并更新Markdown文件。
    """
    if not images_dir.exists():
        print("⚠️  图片目录不存在,跳过重命名。")
        return

    print("🔄 开始按 '页码_序号' 重命名图片...")
    
    # 1. 从文档结构中获取所有图片的页码信息
    pictures_by_page = defaultdict(list)
    for element, level in doc_result.document.iterate_items():
        if isinstance(element, PictureItem) and element.prov:
            page_no = element.prov[0].page_no
            pictures_by_page[page_no].append(element)

    # 2. 获取磁盘上的图片文件并排序
    image_files = sorted([p for p in images_dir.iterdir() if p.is_file()], key=lambda x: x.name)
    
    if not image_files:
        print("   - 图片目录为空,无需重命名。")
        return

    # 3. 创建一个映射:旧文件名 -> 新文件名
    rename_map = {}
    picture_index = 0

    # 按页码顺序处理
    for page_no in sorted(pictures_by_page.keys()):
        page_pictures = pictures_by_page[page_no]
        for i, _ in enumerate(page_pictures):
            if picture_index >= len(image_files):
                print(f"   - 警告:文档中的图片数量多于文件数量,停止重命名。")
                break
            
            old_file = image_files[picture_index]
            old_filename = old_file.name
            
            # 生成新文件名,例如: page_03_01.png
            new_filename = f"page_{page_no:02d}_{i + 1:02d}{old_file.suffix}"
            new_file_path = images_dir / new_filename
            
            # --- 修正:只有在需要重命名时才操作 ---
            if old_file != new_file_path:
                shutil.move(old_file, new_file_path)
                rename_map[old_filename] = new_filename
                print(f"   - '{old_filename}' -> '{new_filename}'")
            
            picture_index += 1

    # --- 修正:只有在 rename_map 不为空时才更新 Markdown ---
    if rename_map:
        print("   - 更新Markdown文件中的图片链接...")
        with open(md_path, 'r', encoding='utf-8') as f:
            md_content = f.read()

        for old_name, new_name in rename_map.items():
            md_content = re.sub(rf'(\]\({re.escape(image_assets_dir_name)}/){re.escape(old_name)}(\))', rf'\1{new_name}\2', md_content)

        with open(md_path, 'w', encoding='utf-8') as f:
            f.write(md_content)
    else:
        print("   - 没有图片需要重命名,跳过Markdown文件更新。")
        
    print("✅ 图片重命名和链接更新完成。")


# -------------------------- 8. 调用重命名函数 --------------------------
try:
    rename_images_by_page_and_order(
        md_path=Path(output_md), 
        images_dir=image_assets_path, 
        doc_result=conv_res
    )
except Exception as e:
    print(f"⚠️  重命名过程中发生错误,但原始文件已生成: {e}")

print("\n🎉 所有任务已完成!")

3.尝试处理页眉页脚

检测和排除页眉/页脚是 Docling 处理的关键功能之一,这些元素(默认情况下)从 markdown 和 html 导出中排除,既然解析PDF没有过滤,那么最有可能的一种情况就是布局模型没有识别出页眉和页脚。

4.可以使用docling发布的不同的layout模型。

https://www.modelscope.cn/organization/ds4sd

5.想调用其他的大模型api可以参考下述链接:

🚀支持视觉大模型的开源PDF解析+OCR工具!Docling本地配置从入门到精通保姆级教程!支持LM Studio+InternVL3-9B与Gemini2.5 Pro轻松识别解析模糊PDF扫描文件 - AI超元域的博客

相关推荐
患得患失94920 小时前
【Turborepo】【Next】 Turborepo + Next.js 前后端精简搭建笔记(带官网)
开发语言·javascript·笔记
阿部多瑞 ABU20 小时前
技术报告:高仿真虚构内容对主流大模型的现实感幻觉测试
人工智能·经验分享·笔记·学习·ai写作
songyuc21 小时前
Eureka: Human-Level Reward Design via Coding Large Language Models 译读笔记
笔记·语言模型·eureka
能不能别报错1 天前
K8s学习笔记(十八) HPA控制器
笔记·学习·kubernetes
XiangrongZ1 天前
江协科技STM32课程笔记(四)—定时器TIM(输入捕获)
笔记·科技·stm32
koo3641 天前
李宏毅机器学习笔记24
人工智能·笔记·机器学习
老虎06271 天前
黑马点评学习笔记02(Mabatis—plus)
笔记·学习
摇滚侠1 天前
Spring Boot 3零基础教程,Spring Boot 日志级别,笔记19
java·spring boot·笔记
星空的资源小屋1 天前
RoboIntern,一款自动化办公小助手
运维·人工智能·pdf·自动化·电脑·excel