ragflow代码学习切片方式(1)docling_parser.py

1、类的创建

内容类型枚举

python 复制代码
class DoclingContentType(str, Enum):
    IMAGE = "image"
    TABLE = "table" 
    TEXT = "text"
    EQUATION = "equation"

逐行解释:

python 复制代码
class DoclingContentType(str, Enum):
  • 定义了一个名为 DoclingContentType 的类
  • (str, Enum) 表示这个类同时继承自 strEnum
  • 这意味着它既是枚举类型,又是字符串类型
python 复制代码
    IMAGE = "image"
  • 定义枚举常量 IMAGE,其值为字符串 "image"
  • 用于标识文档中的图像内容
python 复制代码
    TABLE = "table"
  • 定义枚举常量 TABLE,值为 "table"
  • 用于标识文档中的表格内容
python 复制代码
    TEXT = "text"
  • 定义枚举常量 TEXT,值为 "text"
  • 用于标识文档中的文本内容
python 复制代码
    EQUATION = "equation"
  • 定义枚举常量 EQUATION,值为 "equation"
  • 用于标识文档中的数学公式

作用:这个枚举定义了文档中可能包含的四种内容类型,便于在代码中统一管理和使用。

内容类型枚举 (DoclingContentType) 的实际使用

什么是枚举?

枚举就像是一个固定的选项菜单,只能选择其中定义好的值。

实际使用场景:

python 复制代码
# 场景1:文档解析器识别内容类型
def process_document_element(element):
    # 假设我们有一个文档元素,需要判断它是什么类型
    if element.contains_image():
        content_type = DoclingContentType.IMAGE
        print(f"发现 {content_type} 内容")  # 输出: 发现 image 内容
    elif element.contains_table():
        content_type = DoclingContentType.TABLE
        print(f"发现 {content_type} 内容")  # 输出: 发现 table 内容
    elif element.contains_math():
        content_type = DoclingContentType.EQUATION
    else:
        content_type = DoclingContentType.TEXT
    
    return content_type

# 使用
element_type = process_document_element(some_doc_element)
python 复制代码
# 场景2:根据不同内容类型进行不同处理
def handle_content(content_type: DoclingContentType, content_data):
    if content_type == DoclingContentType.TEXT:
        # 处理文本:提取文字,分析语义
        return process_text(content_data)
    
    elif content_type == DoclingContentType.TABLE:
        # 处理表格:提取行列数据
        return extract_table_data(content_data)
    
    elif content_type == DoclingContentType.IMAGE:
        # 处理图片:OCR识别或保存图片
        return process_image(content_data)
    
    elif content_type == DoclingContentType.EQUATION:
        # 处理公式:数学公式识别
        return parse_equation(content_data)

# 使用示例
text_result = handle_content(DoclingContentType.TEXT, "这是一段文字")
table_result = handle_content(DoclingContentType.TABLE, table_data)
python 复制代码
# 场景3:存储和序列化
document_elements = [
    {"type": DoclingContentType.TEXT, "content": "文章标题", "position": {...}},
    {"type": DoclingContentType.IMAGE, "content": image_data, "position": {...}},
    {"type": DoclingContentType.TABLE, "content": table_data, "position": {...}},
    {"type": DoclingContentType.EQUATION, "content": "E=mc²", "position": {...}}
]

# 遍历处理
for element in document_elements:
    if element["type"] == DoclingContentType.TABLE:
        print("这是一个表格,需要特殊处理")

边界框数据类

python 复制代码
@dataclass
class _BBox:
    page_no: int  
    x0: float
    y0: float
    x1: float
    y1: float

逐行解释:

python 复制代码
@dataclass
  • 这是一个装饰器,用于自动生成特殊方法
  • 它会自动创建 __init____repr__ 等方法
  • 让类定义更简洁,不需要手动写构造函数
python 复制代码
class _BBox:
  • 定义名为 _BBox 的类
  • 下划线前缀通常表示这是内部使用的类
python 复制代码
    page_no: int
  • 定义 page_no 字段,类型为整数 (int)
  • 表示边界框所在的页码
python 复制代码
    x0: float
    y0: float
  • 定义 x0y0 字段,类型为浮点数 (float)
  • 表示边界框左上角的坐标 (x0, y0)
python 复制代码
    x1: float
    y1: float
  • 定义 x1y1 字段,类型为浮点数 (float)
  • 表示边界框右下角的坐标 (x1, y1)

作用:这个数据类用于表示文档中某个元素(如图像、表格等)的位置信息,包含页码和边界框坐标。

边界框数据类 (_BBox) 的实际使用

什么是边界框?

边界框就是用一个矩形框出文档中某个元素的位置。

实际使用场景:

python 复制代码
# 场景1:在PDF页面中定位一个图片
# 假设我们在第2页发现一个图片,坐标从(50, 100)到(200, 300)
image_bbox = _BBox(
    page_no=2,      # 在第2页
    x0=50.0,        # 左上角x坐标
    y0=100.0,       # 左上角y坐标  
    x1=200.0,       # 右下角x坐标
    y1=300.0        # 右下角y坐标
)

print(f"图片在页面 {image_bbox.page_no}")
print(f"位置: ({image_bbox.x0}, {image_bbox.y0}) 到 ({image_bbox.x1}, {image_bbox.y1})")
print(f"宽度: {image_bbox.x1 - image_bbox.x0}")
print(f"高度: {image_bbox.y1 - image_bbox.y0}")
python 复制代码
# 场景2:文档中多个元素的定位
# 假设我们解析一个PDF,找到了各种元素的位置
document_bboxes = [
    _BBox(page_no=1, x0=100.0, y0=50.0, x1=400.0, y1=80.0),   # 标题文本
    _BBox(page_no=1, x0=50.0, y0=100.0, x1=200.0, y1=300.0),  # 图片
    _BBox(page_no=1, x0=250.0, y0=100.0, x1=450.0, y1=250.0), # 表格
    _BBox(page_no=2, x0=100.0, y0=150.0, x1=300.0, y1=180.0)  # 公式
]

# 找出第一页的所有元素
page1_elements = [bbox for bbox in document_bboxes if bbox.page_no == 1]
python 复制代码
# 场景3:结合内容类型和边界框
@dataclass
class DocumentElement:
    content_type: DoclingContentType
    bbox: _BBox
    content: any

# 创建一个文档元素
title_element = DocumentElement(
    content_type=DoclingContentType.TEXT,
    bbox=_BBox(page_no=1, x0=100.0, y0=50.0, x1=400.0, y1=80.0),
    content="RAGFlow 技术文档"
)

table_element = DocumentElement(
    content_type=DoclingContentType.TABLE,
    bbox=_BBox(page_no=1, x0=250.0, y0=100.0, x1=450.0, y1=250.0),
    content=[["姓名", "年龄"], ["张三", "25"], ["李四", "30"]]
)

# 使用
elements = [title_element, table_element]
for element in elements:
    print(f"类型: {element.content_type}")
    print(f"位置: 第{element.bbox.page_no}页")
    print(f"坐标: ({element.bbox.x0}, {element.bbox.y0})")

继承RAGFlowPdfParser

python 复制代码
class DoclingParser(RAGFlowPdfParser):
    def __init__(self):
        self.logger = logging.getLogger(self.__class__.__name__)
        self.page_images: list[Image.Image] = []
        self.page_from = 0
        self.page_to = 10_000

    def check_installation(self) -> bool:
        if DocumentConverter is None:
            self.logger.warning("[Docling] 'docling' is not importable, please: pip install docling")
            return False
        try:
            _ = DocumentConverter()
            return True
        except Exception as e:
            self.logger.error(f"[Docling] init DocumentConverter failed: {e}")
            return False

类定义和继承

python 复制代码
class DoclingParser(RAGFlowPdfParser):
  • 定义了一个名为 DoclingParser 的类
  • 继承自 RAGFlowPdfParser,意味着它拥有父类的所有功能,并可以扩展或重写

初始化方法 __init__

python 复制代码
def __init__(self):
  • 类的构造函数,在创建对象实例时自动调用
python 复制代码
    self.logger = logging.getLogger(self.__class__.__name__)
  • 创建一个日志记录器
  • self.__class__.__name__ 获取当前类的名称("DoclingParser")
  • 这样日志消息会显示来自 "DoclingParser" 类
python 复制代码
    self.page_images: list[Image.Image] = []
  • 初始化实例变量 page_images
  • 类型注解表明这是一个 Image.Image 对象的列表(来自PIL库)
  • 初始化为空列表,用于存储从PDF提取的页面图像
python 复制代码
    self.page_from = 0
    self.page_to = 10_000
  • 设置默认的页面范围
  • page_from = 0:从第0页开始(Python中通常从0开始计数)
  • page_to = 10_000:到第10,000页结束(使用下划线提高可读性)
  • 这为PDF处理设置了很大的默认页面范围

安装检查方法 check_installation

python 复制代码
def check_installation(self) -> bool:
  • 定义一个返回布尔值的方法,用于检查必要的依赖是否安装
python 复制代码
    if DocumentConverter is None:
        self.logger.warning("[Docling] 'docling' is not importable, please: pip install docling")
        return False
  • 检查 DocumentConverter 类是否可用(是否为 None
  • 如果不可用,记录警告日志并返回 False
  • 提示用户需要执行 pip install docling
python 复制代码
    try:
        _ = DocumentConverter()
        return True
    except Exception as e:
        self.logger.error(f"[Docling] init DocumentConverter failed: {e}")
        return False
  • 尝试创建 DocumentConverter 的实例来测试其功能
  • _ = DocumentConverter():创建实例但不保存(使用 _ 表示不关心变量名)
  • 如果成功,返回 True 表示安装正确
  • 如果出现异常,记录错误日志并返回 False

实际使用场景

python 复制代码
# 创建解析器实例
parser = DoclingParser()

# 检查安装
if parser.check_installation():
    print("Docling 已正确安装,可以开始解析PDF")
else:
    print("需要安装 Docling: pip install docling")

# 访问实例变量
print(f"默认页面范围: {parser.page_from} 到 {parser.page_to}")
print(f"页面图像列表: {parser.page_images}")  # 初始为空列表

2、函数方法

(1)images

方法定义

python 复制代码
def __images__(self, fnm, zoomin: int = 1, page_from=0, page_to=600, callback=None):
  • def __images__(self, fnm, ...): 定义了一个名为__images__的实例方法
  • self: 指向当前对象实例的引用
  • fnm: 文件名或文件内容,可以是字符串路径或字节数据
  • zoomin: int = 1: 缩放因子,默认值为1(原大小)
  • page_from=0: 起始页码,默认从第0页开始
  • page_to=600: 结束页码,默认到第600页
  • callback=None: 回调函数,用于进度通知等,默认为空

页码设置

python 复制代码
self.page_from = page_from
self.page_to = page_to
  • 将传入的起始页码和结束页码保存到实例变量中,供其他方法使用

PDF文件处理

python 复制代码
try:
    opener = pdfplumber.open(fnm) if isinstance(fnm, (str, PathLike)) else pdfplumber.open(BytesIO(fnm))
  • try: 开始异常处理块
  • 检查fnm的类型:
    • 如果是字符串或路径对象(str, PathLike),直接使用pdfplumber.open(fnm)打开文件
    • 否则,假定是字节数据,用BytesIO(fnm)包装后再用pdfplumber打开
  • BytesIO用于在内存中处理二进制数据,避免写入临时文件

处理PDF页面

python 复制代码
with opener as pdf:
    pages = pdf.pages[page_from:page_to]
    self.page_images = [p.to_image(resolution=72 * zoomin, antialias=True).original for p in pages]
  • with opener as pdf: 使用上下文管理器确保PDF文件正确关闭
  • pages = pdf.pages[page_from:page_to] 切片获取指定页码范围内的页面
  • 列表推导式遍历每个页面:
    • p.to_image() 将PDF页面转换为图像
    • resolution=72 * zoomin 设置分辨率(72是标准DPI,乘以缩放因子)
    • antialias=True 开启抗锯齿,使图像更平滑
    • .original 获取原始图像数据
    • 结果保存到self.page_images列表中

异常处理

python 复制代码
except Exception as e:
    self.page_images = []
    self.logger.exception(e)
  • 如果处理过程中出现任何异常:
    • self.page_images设为空列表
    • 使用logger记录异常详细信息

这个方法的主要功能:将PDF文件的指定页面范围转换为图像,并保存到内存中供后续处理使用。

(2)_make_line_tag

方法定义

python 复制代码
def _make_line_tag(self, bbox: _BBox) -> str:
  • _make_line_tag:下划线开头表示这是内部方法
  • bbox: _BBox:参数类型注解,接受一个 _BBox 对象
  • -> str:返回值类型注解,返回字符串

边界框检查

python 复制代码
    if bbox is None:
        return ""
  • 检查传入的边界框是否为 None
  • 如果是 None,直接返回空字符串,避免后续操作出错

提取坐标值

python 复制代码
    x0, x1, top, bott = bbox.x0, bbox.x1, bbox.y0, bbox.y1
  • 从边界框对象中提取四个坐标值:
    • x0:左边界 x 坐标
    • x1:右边界 x 坐标
    • top:上边界 y 坐标(原 y0
    • bott:下边界 y 坐标(原 y1

坐标系统转换

python 复制代码
    if hasattr(self, "page_images") and self.page_images and len(self.page_images) >= bbox.page_no:
        _, page_height = self.page_images[bbox.page_no-1].size
        top, bott = page_height - top, page_height - bott

这是最关键的部分,进行坐标系统的转换:

python 复制代码
    if hasattr(self, "page_images") and self.page_images and len(self.page_images) >= bbox.page_no:
  • 检查三个条件:
    1. self 是否有 page_images 属性
    2. page_images 列表不为空
    3. page_images 的长度足够(页码从1开始,但列表索引从0开始)
python 复制代码
        _, page_height = self.page_images[bbox.page_no-1].size
  • 获取指定页面的图像尺寸
  • bbox.page_no-1:页码转索引(页码从1开始,列表索引从0开始)
  • image.size 返回 (width, height),这里用 _ 忽略宽度,只取高度
python 复制代码
        top, bott = page_height - top, page_height - bott
  • 坐标系统转换:将 y 坐标从"从上到下"转换为"从下到上"
  • 这是因为 PDF 的坐标原点在左下角,而图像处理通常在左上角

生成格式化字符串

python 复制代码
    return "@@{}\t{:.1f}\t{:.1f}\t{:.1f}\t{:.1f}##".format(
        bbox.page_no, x0, x1, top, bott
    )
  • 使用固定格式生成位置标签字符串
  • 格式:@@页码\tx0\tx1\ty0\ty1##
  • {:.1f}:浮点数格式,保留1位小数

实际使用示例

python 复制代码
# 假设有一个边界框
bbox = _BBox(page_no=1, x0=100.5, y0=200.3, x1=300.7, y1=400.9)

# 假设页面高度为 800
self.page_images = [Image.new('RGB', (600, 800))]  # 创建一个 600x800 的测试图像

# 调用方法
result = self._make_line_tag(bbox)
print(result)  # 输出: @@1	100.5	300.7	599.7	399.1##

坐标转换的详细过程:

  • 原始坐标:(x0=100.5, y0=200.3, x1=300.7, y1=400.9)
  • 页面高度:800
  • 转换后:
    • top = 800 - 200.3 = 599.7
    • bott = 800 - 400.9 = 399.1
  • 最终坐标:(100.5, 300.7, 599.7, 399.1)

这个标签的用途

这种格式化的位置标签可能用于:

  1. 文本定位:标记文本在页面中的具体位置
  2. 后续处理:其他组件可以解析这个标签来定位元素
  3. 数据导出:便于存储和传输位置信息
  4. 可视化:用于高亮显示或交互操作

这个方法的核心作用就是标准化位置信息的表示格式,并处理不同坐标系统之间的转换。

(3)extract_positions

方法定义

python 复制代码
@staticmethod
def extract_positions(txt: str) -> list[tuple[list[int], float, float, float, float]]:
  • @staticmethod:静态方法装饰器,表示这个方法不依赖于类实例
  • txt: str:输入参数,包含位置标签的文本
  • 返回值类型:一个列表,每个元素是元组,包含:
    • list[int]:页码列表
    • 4个 float:left, right, top, bottom 坐标

初始化结果列表

python 复制代码
    poss = []
  • 初始化一个空列表,用于存储解析后的位置信息

正则表达式匹配

python 复制代码
    for tag in re.findall(r"@@[0-9-]+\t[0-9.\t]+##", txt):
  • 使用正则表达式在文本中查找所有符合格式的位置标签
  • 正则表达式 r"@@[0-9-]+\t[0-9.\t]+##" 解析:
    • @@:匹配开头
    • [0-9-]+:匹配数字和横线(用于页码范围)
    • \t:匹配制表符
    • [0-9.\t]+:匹配数字、小数点和制表符(用于坐标)
    • ##:匹配结尾

标签解析

python 复制代码
        pn, left, right, top, bottom = tag.strip("#").strip("@").split("\t")
  • tag.strip("#"):去掉结尾的 ##
  • .strip("@"):去掉开头的 @@
  • .split("\t"):按制表符分割成5个部分

类型转换

python 复制代码
        left, right, top, bottom = float(left), float(right), float(top), float(bottom)
  • 将坐标字符串转换为浮点数

页码处理

python 复制代码
        poss.append(([int(p) - 1 for p in pn.split("-")], left, right, top, bottom))
  • pn.split("-"):将页码字符串按横线分割(处理页码范围)
  • [int(p) - 1 for p in pn.split("-")]:将页码转换为整数并减1(从1-based转为0-based)
  • 将解析结果添加到列表中

完整的处理流程

步骤1:原始文档解析

首先有一个函数将PDF/文档转换为包含位置信息的结构化文本:

python 复制代码
def parse_document_to_annotated_text(self, pdf_path):
    """将PDF文档解析为包含位置标签的文本"""
    annotated_text = ""
    
    # 使用docling解析文档
    converter = DocumentConverter()
    result = converter.convert(pdf_path)
    
    # 遍历文档中的每个元素(文本、表格、图片等)
    for element in result.elements:
        # 获取元素的位置信息
        bbox = _BBox(
            page_no=element.page_number,
            x0=element.bbox.x0, y0=element.bbox.y0,
            x1=element.bbox.x1, y1=element.bbox.y1
        )
        
        # 生成位置标签
        position_tag = self._make_line_tag(bbox)
        
        # 将元素内容与位置标签结合
        if element.type == DoclingContentType.TEXT:
            annotated_text += f"{position_tag}{element.text}"
        elif element.type == DoclingContentType.TABLE:
            # 表格可能转换为Markdown或HTML
            table_content = self._table_to_markdown(element.content)
            annotated_text += f"{position_tag}{table_content}"
        elif element.type == DoclingContentType.IMAGE:
            annotated_text += f"{position_tag}[图像: {element.alt_text}]"
    
    return annotated_text

步骤2:实际生成的文本示例

经过上述处理,实际的文本可能是这样的:

python 复制代码
text = """
@@1\t100.5\t200.5\t300.5\t400.5##RAGFlow 技术文档
@@1\t50.0\t550.0\t450.0\t500.0##本文介绍RAGFlow的核心概念和使用方法。
@@1\t60.0\t540.0\t520.0\t600.0##第一章 概述
@@2\t100.0\t500.0\t100.0\t300.0##RAGFlow是一个基于检索增强生成的文档处理系统。
@@2\t50.0\t550.0\t320.0\t400.0##| 组件 | 功能 |
|------|------|
| 解析器 | 提取文档内容 |
| 检索器 | 查找相关信息 |
@@3\t80.0\t520.0\t150.0\t350.0##[图像: 系统架构图]
@@3\t100.0\t500.0\t400.0\t450.0##第二章 安装部署
"""

步骤3:后续处理流程

然后使用 extract_positions 来提取这些位置信息:

python 复制代码
class DoclingParser(RAGFlowPdfParser):
    def process_document(self, pdf_path):
        # 1. 解析文档生成带位置标签的文本
        annotated_text = self.parse_document_to_annotated_text(pdf_path)
        
        # 2. 提取所有位置信息
        positions = self.extract_positions(annotated_text)
        
        # 3. 同时获取纯文本内容(去掉位置标签)
        clean_text = self.remove_position_tags(annotated_text)
        
        return {
            'text': clean_text,      # 纯文本内容
            'positions': positions,   # 位置信息
            'annotated_text': annotated_text  # 带标签的原始文本
        }
    
    @staticmethod
    def remove_position_tags(text: str) -> str:
        """移除位置标签,返回纯文本"""
        return re.sub(r"@@[0-9-]+\t[0-9.\t]+##", "", text)

步骤4:实际使用场景

python 复制代码
# 完整的使用流程
parser = DoclingParser()

# 处理PDF文档
result = parser.process_document("ragflow_docs.pdf")

print("纯文本内容:")
print(result['text'])

print("\n位置信息:")
for pages, left, right, top, bottom in result['positions']:
    print(f"页码: {pages}, 位置: ({left}, {top}) -> ({right}, {bottom})")

print("\n带标签的原始文本:")
print(result['annotated_text'])

设计目的

这种设计的价值在于:

  1. 位置保持:在提取文本内容的同时保留精确的位置信息
  2. 可逆处理:可以通过位置信息重新定位到原文
  3. 多模态处理:统一处理文本、表格、图像等不同类型的内容
  4. 后续分析:便于实现点击定位、高亮显示、布局分析等功能

(4)crop

方法定义和初始化

python 复制代码
def crop(self, text: str, ZM: int = 1, need_position: bool = False):
    imgs = []
  • text: 包含位置标签的文本
  • ZM: 缩放因子(可能未使用)
  • need_position: 是否返回位置信息
  • imgs: 存储裁剪出的图像片段

提取位置信息

python 复制代码
    poss = self.extract_positions(text)
    if not poss:
        return (None, None) if need_position else None
  • 从文本中提取所有位置标签
  • 如果没有位置信息,直接返回

扩展位置范围

python 复制代码
    GAP = 6
    pos = poss[0]
    poss.insert(0, ([pos[0][0]], pos[1], pos[2], max(0, pos[3] - 120), max(pos[3] - GAP, 0)))
  • 在位置列表开头添加一个扩展区域:
    • 使用第一个位置的页码
    • 向上扩展120像素(显示更多上文)
    • 确保不超出页面边界
python 复制代码
    pos = poss[-1]
    poss.append(([pos[0][-1]], pos[1], pos[2], min(self.page_images[pos[0][-1]].size[1], pos[4] + GAP), min(self.page_images[pos[0][-1]].size[1], pos[4] + 120)))
  • 在位置列表末尾添加一个扩展区域:
    • 使用最后一个位置的页码
    • 向下扩展120像素(显示更多下文)
    • 确保不超出页面边界

核心裁剪逻辑

python 复制代码
    positions = []
    for ii, (pns, left, right, top, bottom) in enumerate(poss):
        if bottom <= top:
            bottom = top + 4
  • 遍历所有位置信息
  • 如果底部坐标小于等于顶部,设置最小高度4像素
python 复制代码
        img0 = self.page_images[pns[0]]
        x0, y0, x1, y1 = int(left), int(top), int(right), int(min(bottom, img0.size[1]))
        
        crop0 = img0.crop((x0, y0, x1, y1))
        imgs.append(crop0)
  • 获取第一个页面的图像
  • 计算裁剪区域坐标
  • 执行裁剪并保存图像
python 复制代码
        if 0 < ii < len(poss)-1:
            positions.append((pns[0] + self.page_from, x0, x1, y0, y1))
  • 记录原始位置信息(排除首尾的扩展区域)

处理跨页内容

python 复制代码
        remain_bottom = bottom - img0.size[1]
        for pn in pns[1:]:
            if remain_bottom <= 0:
                break
            page = self.page_images[pn]
            x0, y0, x1, y1 = int(left), 0, int(right), int(min(remain_bottom, page.size[1]))
            cimgp = page.crop((x0, y0, x1, y1))
            imgs.append(cimgp)
            if 0 < ii < len(poss) - 1:
                positions.append((pn + self.page_from, x0, x1, y0, y1))
            remain_bottom -= page.size[1]
  • 处理跨越多页的内容
  • 计算剩余需要裁剪的高度
  • 在后续页面上继续裁剪

图像合成

python 复制代码
    if not imgs:
        return (None, None) if need_position else None

    height = sum(i.size[1] + GAP for i in imgs)
    width = max(i.size[0] for i in imgs)
    pic = Image.new("RGB", (width, int(height)), (245, 245, 245))
  • 创建新的空白画布
  • 计算总高度(所有图像高度 + 间隔)
  • 宽度取最宽图像的宽度
  • 背景色为浅灰色 (245, 245, 245)
python 复制代码
    h = 0
    for ii, img in enumerate(imgs):
        if ii == 0 or ii + 1 == len(imgs):
            img = img.convert("RGBA")
            overlay = Image.new("RGBA", img.size, (0, 0, 0, 0))
            overlay.putalpha(128)
            img = Image.alpha_composite(img, overlay).convert("RGB")
        pic.paste(img, (0, int(h)))
        h += img.size[1] + GAP
  • 将裁剪的图像拼接到画布上
  • 对首尾的扩展区域添加半透明遮罩(变暗效果)
  • 更新垂直位置

返回值

python 复制代码
    return (pic, positions) if need_position else pic
  • 根据参数返回图像和位置信息,或只返回图像

实际使用示例

python 复制代码
# 假设有一段带位置标签的文本
text_with_positions = "@@1\t100\t300\t200\t250##重要内容@@1\t100\t300\t260\t280##"

# 调用crop方法
result_image, positions = parser.crop(text_with_positions, need_position=True)

# 结果:
# - result_image: 合成的长图像,包含目标区域及其上下文
# - positions: 原始目标区域的位置信息

方法功能总结

这个方法的主要作用是:

  1. 上下文提取:不仅裁剪目标区域,还包含上下文区域
  2. 跨页处理:支持跨越多页的内容
  3. 视觉区分:用遮罩区分原始内容和扩展内容
  4. 位置追踪:保持原始位置信息的准确性

常用于生成包含上下文引用的图像片段,便于展示和理解文档中的特定内容。

(5)_iter_doc_items

这是一个非常重要的迭代器方法,它负责从Docling解析结果中提取结构化的文档内容。

方法定义

python 复制代码
def _iter_doc_items(self, doc) -> Iterable[tuple[str, Any, Optional[_BBox]]]:
  • 返回一个迭代器,每个元素是三元组:(内容类型, 内容, 位置信息)
  • doc 是Docling库解析文档后返回的对象

第一部分:提取文本内容

python 复制代码
        for t in getattr(doc, "texts", []):
  • 遍历文档中的所有文本元素
  • getattr(doc, "texts", []) 安全地获取 texts 属性,如果没有则返回空列表
python 复制代码
            parent = getattr(t, "parent", "")
            ref = getattr(parent, "cref", "")
            label = getattr(t, "label", "")
  • 获取文本元素的层级信息:
    • parent: 父元素
    • ref: 父元素的引用路径
    • label: 文本元素的类型标签
python 复制代码
            if (label in ("section_header","text",) and ref in ("#/body",)) or label in ("list_item",):
  • 过滤条件 :只处理特定类型的文本
    • 主体部分(#/body)的标题和正文
    • 或者列表项
python 复制代码
                text = getattr(t, "text", "") or ""
  • 获取文本内容,确保不是None

提取位置信息(边界框)

python 复制代码
                bbox = None
                if getattr(t, "prov", None):
                    pn = getattr(t.prov[0], "page_no", None)
                    bb = getattr(t.prov[0], "bbox", None)
                    bb = [getattr(bb, "l", None), getattr(bb, "t", None), getattr(bb, "r", None), getattr(bb, "b", None)]
                    if pn and bb and len(bb) == 4:
                        bbox = _BBox(page_no=int(pn), x0=bb[0], y0=bb[1], x1=bb[2], y1=bb[3])
  • prov 属性包含位置证明信息
  • 提取:页码(page_no)和边界框坐标(l, t, r, b)
  • 如果信息完整,创建 _BBox 对象
python 复制代码
                yield (DoclingContentType.TEXT.value, text, bbox)
  • 生成文本内容项:("text", "文本内容", 位置对象)

第二部分:提取公式内容

python 复制代码
        for item in getattr(doc, "texts", []):
            if getattr(item, "label", "") in ("FORMULA",):
  • 再次遍历文本元素,寻找公式类型
  • label 为 "FORMULA" 表示数学公式
python 复制代码
                text = getattr(item, "text", "") or ""
                bbox = None
                if getattr(item, "prov", None):
                    pn = getattr(item.prov, "page_no", None)
                    bb = getattr(item.prov, "bbox", None)
                    bb = [getattr(bb, "l", None), getattr(bb, "t", None), getattr(bb, "r", None), getattr(bb, "b", None)]
                    if pn and bb and len(bb) == 4:
                        bbox = _BBox(int(pn), bb[0], bb[1], bb[2], bb[3])
                yield (DoclingContentType.EQUATION.value, text, bbox)
  • 提取公式内容和位置信息
  • 生成公式内容项:("equation", "公式内容", 位置对象)

实际使用示例

python 复制代码
# 假设doc是Docling解析后的文档对象
parser = DoclingParser()

for content_type, content, bbox in parser._iter_doc_items(doc):
    if content_type == "text":
        print(f"文本: {content}")
        if bbox:
            print(f"  位置: 第{bbox.page_no}页 ({bbox.x0}, {bbox.y0})")
    elif content_type == "equation":
        print(f"公式: {content}")

处理的数据结构示例

假设Docling解析后的数据结构如下:

python 复制代码
doc = {
    "texts": [
        {
            "label": "section_header",
            "text": "第一章 引言",
            "parent": {"cref": "#/body"},
            "prov": [{
                "page_no": 1,
                "bbox": {"l": 100.0, "t": 50.0, "r": 300.0, "b": 80.0}
            }]
        },
        {
            "label": "FORMULA", 
            "text": "E = mc^2",
            "prov": {
                "page_no": 2,
                "bbox": {"l": 150.0, "t": 200.0, "r": 250.0, "b": 220.0}
            }
        }
    ]
}

方法的作用总结

这个方法的核心作用是:

  1. 内容提取:从复杂的Docling解析结果中提取有用的文本和公式
  2. 内容分类:区分普通文本、标题、列表项、公式等
  3. 位置关联:将内容与其在文档中的精确位置关联起来
  4. 数据标准化:统一输出格式,便于后续处理

(6)_transfer_to_sections

这是一个非常重要的方法,它负责将Docling解析的结果转换为统一的章节格式。

方法定义和目的

python 复制代码
def _transfer_to_sections(self, doc) -> list[tuple[str, str]]:
    """
    和 MinerUParser 保持一致:返回 [(section_text, line_tag), ...]
    """
  • 方法目标:与 MinerUParser 保持输出格式一致
  • 返回值:(章节文本, 位置标签) 的元组列表
  • 这是标准化输出的关键步骤

初始化结果列表

python 复制代码
    sections: list[tuple[str, str]] = []
  • 初始化空列表,用于存储转换后的章节数据

遍历文档项

python 复制代码
    for typ, payload, bbox in self._iter_doc_items(doc):
  • 使用前面分析的 _iter_doc_items 方法遍历文档内容
  • 获取:(内容类型, 内容, 位置信息) 三元组

处理文本内容

python 复制代码
        if typ == DoclingContentType.TEXT.value:
            section = payload.strip()
            if not section:
                continue
  • 如果是文本类型 ("text")
  • 去除首尾空白字符
  • 如果去除后为空字符串,跳过该项

处理公式内容

python 复制代码
        elif typ == DoclingContentType.EQUATION.value:
            section = payload.strip()
  • 如果是公式类型 ("equation")
  • 同样去除空白字符,但允许空公式(可能包含特殊符号)

跳过其他类型

python 复制代码
        else:
            continue
  • 跳过图片、表格等其他类型的内容
  • 只保留文本和公式

生成位置标签

python 复制代码
        tag = self._make_line_tag(bbox) if isinstance(bbox, _BBox) else ""
  • 如果有有效的边界框对象,生成位置标签
  • 如果没有位置信息,使用空字符串

添加到结果列表

python 复制代码
        sections.append((section, tag))
  • (文本内容, 位置标签) 添加到结果列表

返回结果

python 复制代码
    return sections

实际转换示例

假设 _iter_doc_items 返回:

python 复制代码
[
    ("text", "第一章 引言", _BBox(page_no=1, x0=100, y0=50, x1=300, y1=80)),
    ("text", "这是正文内容", _BBox(page_no=1, x0=50, y0=100, x1=550, y1=120)),
    ("equation", "E = mc^2", _BBox(page_no=2, x0=150, y0=200, x1=250, y1=220)),
    ("image", "[图片数据]", None)  # 这个会被跳过
]

经过 _transfer_to_sections 处理后:

python 复制代码
[
    ("第一章 引言", "@@1\t100.0\t300.0\t...##"),
    ("这是正文内容", "@@1\t50.0\t550.0\t...##"), 
    ("E = mc^2", "@@2\t150.0\t250.0\t...##")
]

设计意图和重要性

1. 标准化输出

python 复制代码
# 不同的解析器都返回相同格式
miner_parser = MinerUParser()
docling_parser = DoclingParser()

# 统一接口,便于后续处理
miner_sections = miner_parser.parse(pdf_path)      # 返回 [(text, tag), ...]
docling_sections = docling_parser._transfer_to_sections(doc)  # 返回 [(text, tag), ...]

2. 数据过滤和清理

  • 过滤掉空文本
  • 跳过不需要的内容类型(图片、表格等)
  • 统一处理文本格式

3. 位置信息保留

python 复制代码
# 后续可以轻松还原位置信息
for section_text, position_tag in sections:
    if position_tag:
        positions = self.extract_positions(position_tag)
        # 可以进行精确定位或图像裁剪

4. 支持多种使用场景

场景1:纯文本处理

python 复制代码
sections = self._transfer_to_sections(doc)
pure_text = "\n".join([text for text, tag in sections])

场景2:带位置的文本检索

python 复制代码
sections = self._transfer_to_sections(doc)
for text, tag in sections:
    if "关键词" in text:
        # 找到相关内容,可以通过tag精确定位
        cropped_image = self.crop(tag + text)

场景3:多解析器统一处理

python 复制代码
def parse_pdf_unified(pdf_path):
    # 尝试多种解析器,但输出格式统一
    parsers = [MinerUParser(), DoclingParser()]
    
    for parser in parsers:
        try:
            if hasattr(parser, '_transfer_to_sections'):
                sections = parser._transfer_to_sections(doc)
            else:
                sections = parser.parse(pdf_path)
            return sections
        except Exception as e:
            continue

这个方法的核心价值在于创建了一个统一的接口,让不同的PDF解析器能够以相同的格式输出结果,极大地简化了后续的处理流程。

(7)cropout_docling_table

这是一个专门用于裁剪文档中表格图像的方法!

方法定义

python 复制代码
def cropout_docling_table(self, page_no: int, bbox: tuple[float, float, float, float], zoomin: int = 1):
  • 专门用于裁剪表格的方法
  • page_no: 表格所在的页码(从1开始)
  • bbox: 表格的边界框坐标 (left, top, right, bottom)
  • zoomin: 缩放因子(可能未使用)

检查图像数据

python 复制代码
    if not getattr(self, "page_images", None):
        return None, ""
  • 检查 self.page_images 是否存在且不为空
  • 如果没有图像数据,返回空结果

计算页面索引

python 复制代码
    idx = (page_no - 1) - getattr(self, "page_from", 0)
    if idx < 0 or idx >= len(self.page_images):
        return None, ""
  • page_no - 1: 将页码转换为0-based索引
  • - self.page_from: 考虑页面范围的偏移量
  • 检查索引是否在有效范围内

获取页面图像和尺寸

python 复制代码
    page_img = self.page_images[idx]
    W, H = page_img.size
    left, top, right, bott = bbox
  • 获取指定页面的图像
  • 获取图像的宽度和高度
  • 解构边界框坐标

坐标系统转换

python 复制代码
    x0 = float(left)
    y0 = float(H - top)  # 关键:y坐标转换
    x1 = float(right)
    y1 = float(H - bott) # 关键:y坐标转换
  • 关键步骤:将y坐标从"从上到下"转换为"从下到上"
  • PDF坐标系统:原点在左下角,y向上增加
  • 图像坐标系统:原点在左上角,y向下增加
  • H - topH - bott 完成坐标转换

边界检查和安全处理

python 复制代码
    x0, y0 = max(0.0, min(x0, W - 1)), max(0.0, min(y0, H - 1))
    x1, y1 = max(x0 + 1.0, min(x1, W)), max(y0 + 1.0, min(y1, H))
  • 确保坐标不超出图像边界
  • max(0.0, min(x0, W - 1)): 限制在 [0, 宽度-1] 范围内
  • max(x0 + 1.0, ...): 确保宽度至少为1像素

执行裁剪操作

python 复制代码
    try:
        crop = page_img.crop((int(x0), int(y0), int(x1), int(y1))).convert("RGB")
    except Exception:
        return None, ""
  • 使用PIL的 crop 方法裁剪图像
  • .convert("RGB"): 确保输出为RGB格式
  • 异常处理:如果裁剪失败返回空结果

返回结果

python 复制代码
    pos = (page_no-1 if page_no>0 else 0, x0, x1, y0, y1)
    return crop, [pos]
  • 返回裁剪的图像和位置信息
  • 位置信息使用0-based页码

实际使用示例

python 复制代码
# 假设在文档处理过程中发现表格
parser = DoclingParser()
parser.__images__("document.pdf")  # 先加载图像

# 表格位置信息(来自Docling解析)
table_page_no = 2
table_bbox = (100.5, 200.3, 400.7, 500.9)  # (left, top, right, bottom)

# 裁剪表格图像
table_image, positions = parser.cropout_docling_table(table_page_no, table_bbox)

if table_image:
    table_image.save("extracted_table.png")
    print(f"表格裁剪成功,位置: {positions[0]}")

坐标转换的详细过程

假设:

  • 页面高度 H = 800
  • 表格边界框: (100, 200, 400, 500)

转换过程:

复制代码
原始PDF坐标:
  top = 200 (距离页面顶部的距离)
  bottom = 500 (距离页面顶部的距离)

转换后图像坐标:
  y0 = 800 - 200 = 600 (距离图像顶部的距离)  
  y1 = 800 - 500 = 300 (距离图像顶部的距离)

最终裁剪区域: (100, 300, 400, 600)

与之前crop方法的区别

特性 crop 方法 cropout_docling_table 方法
输入 带位置标签的文本 直接的页码和边界框
输出 合成的长图像 单个表格图像
用途 文本段落的可视化 表格提取和展示
坐标处理 _make_line_tag中处理 在方法内部处理

这个方法专门为表格提取设计,是Docling文档处理流程中的重要组成部分!

(8)_transfer_to_tables

这是一个专门用于提取文档中表格和图片的方法!

方法定义

python 复制代码
def _transfer_to_tables(self, doc):
  • 专门处理文档中的表格和图片
  • 返回统一格式的数据,便于后续处理

第一部分:提取表格

python 复制代码
    tables = []
    for tab in getattr(doc, "tables", []):
  • 初始化结果列表
  • 遍历文档中的所有表格,安全地获取 tables 属性

提取表格位置信息

python 复制代码
        img = None
        positions = ""
        if getattr(tab, "prov", None):
            pn = getattr(tab.prov[0], "page_no", None)
            bb = getattr(tab.prov[0], "bbox", None)
            if pn is not None and bb is not None:
                left = getattr(bb, "l", None)
                top = getattr(bb, "t", None)
                right = getattr(bb, "r", None)
                bott = getattr(bb, "b", None)
                if None not in (left, top, right, bott):
                    img, positions = self.cropout_docling_table(int(pn), (float(left), float(top), float(right), float(bott)))
  • 提取表格的位置证明信息(prov
  • 获取页码和边界框坐标
  • 如果所有坐标都有效,调用 cropout_docling_table 裁剪表格图像

提取表格HTML内容

python 复制代码
        html = ""
        try:
            html = tab.export_to_html(doc=doc)
        except Exception:
            pass
  • 尝试将表格导出为HTML格式
  • 异常处理:如果导出失败,保持空字符串

保存表格数据

python 复制代码
        tables.append(((img, html), positions if positions else ""))
  • 将表格数据保存为:((图像, HTML内容), 位置信息)

第二部分:提取图片

python 复制代码
    for pic in getattr(doc, "pictures", []):
  • 遍历文档中的所有图片

提取图片位置信息

python 复制代码
        img = None
        positions = ""
        if getattr(pic, "prov", None):
            pn = getattr(pic.prov[0], "page_no", None)
            bb = getattr(pic.prov[0], "bbox", None)
            if pn is not None and bb is not None:
                left = getattr(bb, "l", None)
                top = getattr(bb, "t", None)
                right = getattr(bb, "r", None)
                bott = getattr(bb, "b", None)
                if None not in (left, top, right, bott):
                    img, positions = self.cropout_docling_table(int(pn), (float(left), float(top), float(right), float(bott)))
  • 与表格类似的逻辑,提取图片位置并裁剪图像

提取图片标题

python 复制代码
        captions = ""
        try:
            captions = pic.caption_text(doc=doc)
        except Exception:
            pass
  • 尝试提取图片的标题文本
  • 异常处理:如果提取失败,保持空字符串

保存图片数据

python 复制代码
        tables.append(((img, [captions]), positions if positions else ""))
  • 将图片数据保存为:((图像, [标题列表]), 位置信息)

返回结果

python 复制代码
    return tables

实际处理结果示例

假设文档包含:

  • 1个表格(第2页)
  • 2张图片(第3页)

处理后的 tables 列表:

python 复制代码
[
    # 表格数据
    (
        (表格图像对象, "<table><tr><td>数据</td></tr></table>"), 
        [(1, 100.0, 400.0, 300.0, 600.0)]  # 位置信息
    ),
    # 第一张图片数据
    (
        (图片1图像对象, ["图1: 系统架构"]),  # 图像和标题
        [(2, 50.0, 300.0, 200.0, 400.0)]   # 位置信息
    ),
    # 第二张图片数据  
    (
        (图片2图像对象, ["图2: 性能对比"]),
        [(2, 350.0, 600.0, 200.0, 400.0)]
    )
]

设计意图分析

1. 统一输出格式

python 复制代码
# 统一的返回格式,便于后续处理
for (img, content), positions in tables:
    if isinstance(content, str): 
        # 处理表格(HTML内容)
        process_table(content, img)
    elif isinstance(content, list):
        # 处理图片(标题列表)
        process_image(content[0], img)

2. 多模态数据提取

  • 表格:图像 + HTML结构化数据
  • 图片:图像 + 文本标题
  • 两者都包含精确的位置信息

3. 容错处理

  • 大量使用 getattr(..., None) 避免属性不存在时报错
  • try-except 块处理可能失败的操作

4. 与前面方法的关系

复制代码
完整文档处理流程:

doc (原始Docling对象)
    ↓
_transfer_to_sections()  # 提取文本和公式 → 用于文本处理
_transfer_to_tables()    # 提取表格和图片 → 用于视觉元素处理
    ↓
统一的数据格式 → 便于RAG系统索引和使用

实际应用场景

python 复制代码
def process_document_completely(self, pdf_path):
    """完整的文档处理流程"""
    converter = DocumentConverter()
    doc = converter.convert(pdf_path)
    
    # 加载页面图像
    self.__images__(pdf_path)
    
    # 提取所有类型的内容
    sections = self._transfer_to_sections(doc)  # 文本内容
    tables_and_images = self._transfer_to_tables(doc)  # 表格和图片
    
    return {
        'text_content': sections,
        'visual_content': tables_and_images,
        'complete_coverage': True  # 确保覆盖所有内容类型
    }

这个方法确保了文档中的所有视觉元素(表格、图片)都能被正确提取并标准化,为后续的文档理解和检索提供完整的数据支持!

(9)parse_pdf

这是整个Docling解析器的核心入口方法!它整合了我们前面分析的所有组件,完成了从PDF到结构化数据的完整转换流程。

方法定义和参数

python 复制代码
def parse_pdf(
        self,
        filepath: str | PathLike[str],
        binary: BytesIO | bytes | None = None,
        callback: Optional[Callable] = None,
        *,
        output_dir: Optional[str] = None, 
        lang: Optional[str] = None,        
        method: str = "auto",             
        delete_output: bool = True,       
    ):
  • filepath: PDF文件路径
  • binary: 可选的二进制数据(内存中的PDF)
  • callback: 进度回调函数
  • output_dir: 临时输出目录
  • lang: 语言设置
  • method: 解析方法
  • delete_output: 是否删除临时文件

1. 安装检查

python 复制代码
        if not self.check_installation():
            raise RuntimeError("Docling not available, please install `docling`")
  • 检查Docling依赖是否安装
  • 如果没有安装,抛出明确错误

2. 处理二进制输入

python 复制代码
        if binary is not None:
            tmpdir = Path(output_dir) if output_dir else Path.cwd() / ".docling_tmp"
            tmpdir.mkdir(parents=True, exist_ok=True)
            name = Path(filepath).name or "input.pdf"
            tmp_pdf = tmpdir / name
            with open(tmp_pdf, "wb") as f:
                if isinstance(binary, (bytes, bytearray)):
                    f.write(binary)
                else:
                    f.write(binary.getbuffer())
            src_path = tmp_pdf
  • 如果提供的是二进制数据,先写入临时文件
  • 创建临时目录,确保父目录存在
  • 将二进制数据写入临时PDF文件

3. 处理文件路径输入

python 复制代码
        else:
            src_path = Path(filepath)
            if not src_path.exists():
                raise FileNotFoundError(f"PDF not found: {src_path}")
  • 如果是文件路径,检查文件是否存在

4. 进度回调

python 复制代码
        if callback:
            callback(0.1, f"[Docling] Converting: {src_path}")
  • 通知调用方解析开始(10%进度)

5. 加载页面图像

python 复制代码
        try:
            self.__images__(str(src_path), zoomin=1)
        except Exception as e:
            self.logger.warning(f"[Docling] render pages failed: {e}")
  • 调用前面分析的 __images__ 方法加载PDF页面图像
  • 为后续的 cropout_docling_table 准备图像数据
  • 异常处理:即使图像加载失败,也继续文本解析

6. 使用Docling解析文档

python 复制代码
        conv = DocumentConverter()  
        conv_res = conv.convert(str(src_path))
        doc = conv_res.document
        if callback:
            callback(0.7, f"[Docling] Parsed doc: {getattr(doc, 'num_pages', 'n/a')} pages")
  • 创建Docling转换器
  • 解析PDF文档,得到复杂的结果对象
  • 进度回调(70%进度)

7. 提取结构化数据

python 复制代码
        sections = self._transfer_to_sections(doc)
        tables = self._transfer_to_tables(doc)

        if callback:
            callback(0.95, f"[Docling] Sections: {len(sections)}, Tables: {len(tables)}")
  • 关键步骤:使用前面分析的两个方法提取数据
  • _transfer_to_sections: 提取文本和公式
  • _transfer_to_tables: 提取表格和图片
  • 进度回调(95%进度)

8. 清理临时文件

python 复制代码
        if binary is not None and delete_output:
            try:
                Path(src_path).unlink(missing_ok=True)
            except Exception:
                pass
  • 如果是二进制输入且设置了删除标志,清理临时文件

9. 完成并返回结果

python 复制代码
        if callback:
            callback(1.0, "[Docling] Done.")
        return sections, tables
  • 最终进度回调(100%)
  • 返回提取的所有数据

完整的数据流

复制代码
输入 (PDF文件/二进制数据)
    ↓
临时文件处理 (如果需要)
    ↓
self.__images__() → 加载页面图像
    ↓  
DocumentConverter().convert() → 原始doc对象
    ↓
_transfer_to_sections() → 文本数据
_transfer_to_tables()   → 视觉数据
    ↓
输出 (sections, tables)

实际使用示例

python 复制代码
# 使用文件路径
parser = DoclingParser()
sections, tables = parser.parse_pdf("document.pdf")

# 使用二进制数据
with open("document.pdf", "rb") as f:
    binary_data = f.read()
sections, tables = parser.parse_pdf("document.pdf", binary=binary_data)

# 带进度回调
def progress_callback(progress, message):
    print(f"{progress*100:.0f}%: {message}")

sections, tables = parser.parse_pdf("document.pdf", callback=progress_callback)

返回的数据结构

python 复制代码
# sections: 来自 _transfer_to_sections
[
    ("章节标题", "@@1\t100\t200\t300\t400##"),
    ("正文内容", "@@1\t50\t550\t100\t120##"),
    ("数学公式", "@@2\t150\t250\t200\t220##")
]

# tables: 来自 _transfer_to_tables  
[
    ((表格图像, "<table>...</table>"), "位置信息"),
    ((图片图像, ["图片标题"]), "位置信息")
]

设计价值

这个 parse_pdf 方法的价值在于:

  1. 统一入口: 封装了所有复杂的处理逻辑
  2. 灵活输入: 支持文件路径和二进制数据
  3. 进度反馈: 通过callback提供实时进度
  4. 资源管理: 自动处理临时文件清理
  5. 错误恢复: 即使部分步骤失败也能继续
  6. 完整提取: 返回文档的所有重要内容

这就是整个Docling解析器的"大脑",它将我们前面分析的所有零散组件整合成了一个完整、健壮的PDF解析流程!

总结:

各函数的职责总结

函数 主要职责 依赖
parse_pdf 总协调,流程控制 所有其他函数
check_installation 环境检查
__images__ 加载页面图像
_iter_doc_items 提取原始文档项 doc对象
_transfer_to_sections 标准化文本数据 _iter_doc_items, _make_line_tag
_transfer_to_tables 标准化视觉数据 cropout_docling_table
_make_line_tag 位置信息编码 _BBox, 坐标转换
extract_positions 位置信息解码 正则表达式
cropout_docling_table 裁剪具体区域 self.page_images
crop 裁剪文本区域 self.page_images, extract_positions

对于文本内容:

复制代码
doc (结构数据)
    ↓
_iter_doc_items() → 提取文本和位置
    ↓
_make_line_tag() → 生成标准化标签
    ↓
sections = [("文本", "@@页码\t坐标##")]

对于表格/图片:

复制代码
doc (结构数据)          self.page_images (图像数据)
    ↓                            ↓
_transfer_to_tables() → cropout_docling_table()
    ↓                            ↓
((图像, 内容), 位置) ←─────────── 裁剪结果
相关推荐
大千AI助手2 小时前
多叉树:核心概念、算法实现与全领域应用
人工智能·算法·决策树·机器学习··多叉树·大千ai助手
醒过来摸鱼2 小时前
9.12 sinc插值
python·线性代数·算法·numpy
努力的光头强2 小时前
《智能体设计模式》从零基础入门到精通,看这一篇就够了!
大数据·人工智能·深度学习·microsoft·机器学习·设计模式·ai
小兔崽子去哪了2 小时前
Numpy、Panads
python·numpy·pandas
2501_941149112 小时前
人工智能驱动下的边缘物联网革新,打造未来全球智能互联新格局
人工智能·物联网
dagouaofei2 小时前
开题报告自动做PPT
python·powerpoint
没头脑的男大2 小时前
Unet+Transformer脑肿瘤分割检测
人工智能·深度学习·transformer
Elias不吃糖2 小时前
整合了c++里面常用的STL及其常用API
开发语言·c++·学习·stl