图片PDF向量化处理的探索与实践

news/2025/2/15 11:26:53/文章来源:https://www.cnblogs.com/hongshao/p/18716681

在构建AI本地知识库时,我们不可避免地需要对PDF文件进行处理。PDF文件大致分为两种:扫描的图片文件和非图片文件。对于非图片类型的PDF,可以直接提取文本并进行向量化处理;但对于图片类型的PDF(如扫描件),处理起来就复杂得多。


问题背景

图片类型的PDF文件通常存在以下问题:

  • 扫描件可能不是一页一页扫描的,而是多页合并在一起。
  • 文字方向多样,可能包含横排、竖排甚至不同语言的文字。
  • 不同段落的文字容易被错误合并成一行,导致内容混乱。

幸运的是,借助现代AI技术,我们可以高效地解决这些问题。


处理流程

以下是图片PDF向量化处理的整体流程:

graph TDA[PDF输入] --> B[文本检测+方向分类+文本识别]B --> D[Ai整理合并]D --> E[小模型Ai校对]E --校对失败--> DE --校对成功--> F[Ai输出清理]F --> G[小模型校验]G --校验失败--> FG --校验成功--> H[输出整理完成的文档]H --> I[向量化]
  1. PDF输入
    将PDF文件作为输入源。

  2. 文本检测与方向分类
    使用OCR技术检测文字区域,并识别文字方向。提取文字内容,生成初步的文本数据。

  3. AI整理与合并
    使用大模型对提取的文本进行整理和合并,确保段落结构正确。

  4. 小模型校对
    使用小模型对整理后的文本进行校对。如果校对失败,则重新执行AI整理与合并步骤。

  5. AI输出清理
    对文本进行进一步清理,去除冗余信息。

  6. 小模型校验
    再次使用小模型对清理后的文本进行校验。如果校验失败,则重新执行清理步骤。

  7. 输出整理完成的文档
    将最终整理好的文档输出。

  8. 向量化
    将整理完成的文档转化为向量形式,用于后续的知识库构建。


技术选型

1. 文本检测与识别

经过多次测试,发现百度飞桨(PaddlePaddle)的PP-OCR模型效果最佳,能够很好地识别繁体中文和其他复杂字符。相比一些收费的OCR工具,PP-OCR的表现更加出色。

2. AI整理与合并

为了确保文本整理的准确性,我选择了通义千问的Qwen2.5-72B-Instruct模型。该模型具有强大的指令遵循能力,并且通过将temperature设置为0,可以严格遵循输入文档的结构,避免不必要的改动。

3. 校对与校验

在校对环节,我使用了DeepSeek-R1:7B模型。经过测试,即使是较小的DeepSeek-R1:1.5B模型也能满足需求,但为了保险起见,最终选择了7B版本。


示例代码

以下是关键步骤的部分代码示例:

文本检测与识别

from paddleocr import PaddleOCR# OCR核心配置
ocr = PaddleOCR(use_angle_cls=True,  # 自动旋转文本方向lang="ch",           # 支持繁体识别det_model_dir='ch_PP-OCRv4_det_infer',  # 文本检测模型rec_model_dir='ch_PP-OCRv4_rec_infer',  # 文本识别模型gpu_mem=4000        # 控制显存占用
)

AI整理与合并


def merge_text_with_ai(blocks_metadata, page_size, model_name=MERGE_MODEL):"""智能版面分析及多语言文本合并"""system_prompt = """你是一个专业的OCR文本处理专家,擅长分析和重组OCR识别的文本块。
你的任务是将散乱的文本块重新组织成有序、连贯的文章。
只能输出重组后的纯文本内容,不要解释处理过程。"""user_prompt = """# OCR文本重组任务
【输入信息】
页面尺寸:{width}x{height}
文本块数据:
{blocks_metadata}【重组规则】
1. 文本分析- 识别段落关系:通过内容连贯性和位置关系- 重排段落:基于语义和排版位置2. 内容处理- 合并断行:修复被错误分割的句子- 保持段落完整性3. 质量要求- 保持语义连贯性- 避免重复内容- 维护完整段落结构- 保证内容完整不遗漏"""# 初始化merged变量merged = ""original_text = '\n'.join(block['text'] for block in blocks_metadata)for attempt in range(MAX_RETRIES):try:print("开始合并文本...")response = client_sf.chat.completions.create(model=model_name,messages=[{"role": "system", "content": system_prompt},{"role": "user", "content": user_prompt.format(width=page_size[0],height=page_size[1],blocks_metadata=blocks_metadata  # 修正变量名)}],temperature=0,timeout=MODEL_TIMEOUT)merged = response.choices[0].message.content.strip()# 后处理流程merged = re.sub(r'<think>.*?</think>', '', merged, flags=re.DOTALL)merged = re.sub(r'[※★◆▁▂▃▄▅▆▇█▏▎▍▌▋▊▉]+', '', merged)merged = re.sub(r'[,,]+', ',', merged)merged = re.sub(r'\n{3,}', '\n\n', merged)if validate_output(original_text, merged):print("校验通过,返回合并结果")return mergedprint(f"校验未通过,开始第{attempt+1}次重试...")except Exception as e:if 'timeout' in str(e).lower():logging.error(f"AI响应超时({MODEL_TIMEOUT}秒),尝试第{attempt+1}次重试...")else:logging.error(f"合并失败: {str(e)}")if attempt == MAX_RETRIES - 1:breaktime.sleep(RETRY_BASE_DELAY ** attempt)return original_text  # 如果所有尝试都失败,返回原始文本

小模型校对


def validate_output(original_text, processed_text):"""严格单结果校验"""system_prompt = """你是一个严格的文本质量检查员。
你的任务是对比原始文本和处理后的文本,检查是否存在内容缺失、非法删除或重复问题。
只需回答"是"或"否",不需要解释原因。"""user_prompt = """请对比原文和处理后文本,严格检查:
1. 内容缺失:处理后文本是否删除了原文中的句子
2. 非法删除:是否错误删除正文内容
3. 重复问题:是否产生了原文中不存在的重复内容▼原始文本▼
{original_sample}▼处理后文本▼
{processed_sample}如果存在任何一个问题,请回答[否]
如果全部符合要求,请回答[是]
仅允许输出[是]或[否]"""try:print("开始校验...")print("原始文本:",original_text.replace('\n', ' '))print("处理后文本:",processed_text.replace('\n', ' '))response = client_local.chat.completions.create(model=VALIDATE_MODEL,messages=[{"role": "system", "content": system_prompt},{"role": "user", "content": user_prompt.format(original_sample=original_text[:300].replace('\n', ' '),processed_sample=processed_text[:500].replace('\n', ' '))}],temperature=0,timeout=VALIDATE_TIMEOUT)# 严格清洗响应print("校验结果:",response.choices[0].message.content)clean_res = re.sub(r'<think>.*?</think>', '', response.choices[0].message.content, flags=re.DOTALL)clean_res = re.sub(r'[^是否]', '', clean_res)return '否' not in clean_resexcept Exception as e:logging.error(f"校验失败: {str(e)}")return False

原始图像

处理后效果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/884190.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android ADB 使用笔记

ADB(Android Debug Bridge)是用于与 Android 设备和模拟器交互的命令行工具。通过客户端、服务器和守护进程的协作,提供设备管理、应用安装与卸载、文件操作、系统设置控制等功能。常用命令包括连接设备、安装 APK、截图、录屏、模拟按键、获取设备信息等,是 Android 开发和…

别再误解了!AI 不是软件且不接受反驳!

是的,今天的 AI 是用软件编写的,但如今的实现实际上是一个计算图,它计算的是虚拟神经元网络的行为。软件仅仅是该网络的一个模拟。 让我解释一下。 就像我说的,神经网络 AI 实际上是一组相互连接的虚拟“神经元”。每个神经元或多或少地模拟了人类神经元的行为。这张图数学…

欧拉角和四元数,3D 游戏开发中“旋转”难题的通俗讲解和应用实战

本文深入浅出地介绍了3D游戏开发中常用的旋转工具——欧拉角和四元数。通过生动的例子和代码演示,详细解释了它们的基本概念、应用场景以及如何解决万向锁、插值和计算效率等问题。无论你是初学者还是有经验的开发者,都能从中获得实用的知识和技巧……春节期间,老牛同学学习…

【Go-bug】go引入自建包名报错 package XXX is not in std

引入 这个问题从昨晚学到Package和Module这块的时候就开始折磨我,这里说道:Go语言也有 Public 和 Private 的概念,粒度是包。如果类型/接口/方法/函数/字段的首字母大写,则是 Public 的,对其他 package 可见,如果首字母小写,则是 Private 的,对其他 package 不可见。于…

[AI/前沿展望/综述] AI大模型的技术生态链全景图

序【特别说明】1、本文主要面向对象:开发者、对AI前沿技术感兴趣、基于AI创业的伙伴们 2、本文是对当前AI大模型的技术生态链的【综述】性文章。(文章有点长,预计阅读时长>10min)3、原作者:阿里云开发者(组织机构)(故,极小部分观点有含暗广的嫌疑。但瑕不掩瑜)关键词AI大模…

大语言模型的解码策略与关键优化总结

本文系统性地阐述了大型语言模型(Large Language Models, LLMs)中的解码策略技术原理及其实践应用。通过深入分析各类解码算法的工作机制、性能特征和优化方法,为研究者和工程师提供了全面的技术参考。主要涵盖贪婪解码、束搜索、采样技术等核心解码方法,以及温度参数、惩罚机…

mini-lsm通关笔记Week3Day3

项目地址:https://github.com/skyzh/mini-lsm 个人实现地址:https://gitee.com/cnyuyang/mini-lsm在本章中,您将:在上一章的基础上完成读路径,以支持快照读。 实现事务API,支持快照读。 引擎恢复过程中能正确恢复已提交时间戳。最后,您的引擎将能够为用户提供存储键(key…

软件测试流程——H模型

1、产品开需求澄清会议 2、开发和测试拿到需求 3、分析需求,编写测试计划 4、编写测试用例 5、评审测试用例 6、评审通过,将用例导入用例管理工具 7、搭建环境 8、开发提交项目代码包,达到准入条件 9、测试将项目代码包部署到环境中 10、开始冒烟测试 (冒烟测试通过,则进入…

请求被中止: 未能创建 SSL/TLS 安全通道_微信红包接口_iis_windows

开发微信红包接口过程中出现:请求被中止: 未能创建 SSL/TLS 安全通道。本地调试正常,但是服务器上不行。 通用方法:指定使用的协议tls(https://myssl.com,这里可以测试对应接口服务器支持的协议) 证书导入赋予权限,参考如下文章: 两种方式彻底解决请求被中止- 未能创建…

SpringBoot环境搭建

JDK 在Oracle官网下载JDK11需注册Oracle账户,较麻烦。 在https://jdk.java.net/archive/找到11 GA (build 11+28)下载Windows版本的压缩包解压后将jdk-11文件夹放到合适位置(多个版本可同时存在),IDE可自动检测到该JDK 如果存在问题可能需要进一步配置环境变量,先创建一个…

C语言静态查找表的查找算法(顺序查找、折半查找)

顺序查找的实现#include <stdio.h>#define SIZE 10 // 静态查找表的大小// 顺序查找函数 int sequentialSearch(int arr[], int size, int target) {for (int i = 0; i < size; i++) {if (arr[i] == target) {return i; // 查找成功,返回目标的索引}}return -1; /…

游戏陪玩接单平台源码,如何实现按钮悬浮功能

游戏陪玩接单平台源码,如何实现按钮悬浮功能实现可视区域底部悬浮编辑提交等功能的悬浮框: 并当滚动到某处时, 固定在该处<template><div><slot></slot><divv-show="show"style="height: 80px"></div></div>…