Python調(diào)用olmOCR大模型實(shí)現(xiàn)提取復(fù)雜PDF文件內(nèi)容
本篇筆記所對(duì)應(yīng)的視頻:www.bilibili.com/video/BV1gPXXYiETE/ allenai/olmocr是由Allen人工智能研究所(AI2)開發(fā)的一個(gè)開源工具包,旨在高效地將PDF和其他文檔轉(zhuǎn)換為結(jié)構(gòu)化的純文本,同時(shí)保持自然閱讀順序。以下是該項(xiàng)目的主要特點(diǎn)和功能:
核心技術(shù)
- 使用名為olmOCR-7B-0225-preview的視覺語言模型(VLM),這是基于Qwen2-VL-7B-Instruct訓(xùn)練而成的。
- 該模型經(jīng)過約25萬頁多樣化PDF內(nèi)容(包括掃描和基于文本的)的訓(xùn)練,這些內(nèi)容使用GPT-4o標(biāo)注并作為olmOCR-mix-0225數(shù)據(jù)集發(fā)布。
主要功能
- 高效批量處理:使用SGLang優(yōu)化推理管道,能以極低的成本處理大量文檔。
- 文檔錨定:提取每頁中顯著元素(如文本塊和圖像)的坐標(biāo),并將其與從PDF二進(jìn)制文件中提取的原始文本一起注入。
- 支持本地和集群使用:可在單機(jī)GPU上運(yùn)行,也支持使用AWS S3進(jìn)行多節(jié)點(diǎn)并行處理。
性能和優(yōu)勢(shì)
- 成本效益高:轉(zhuǎn)換100萬頁P(yáng)DF僅需190美元,約為使用GPT-4o API成本的1/32。
- 準(zhǔn)確性高:在人工評(píng)估中,olmOCR在各種PDF提取技術(shù)的ELO評(píng)級(jí)中排名最高。
- 提升下游任務(wù):使用olmOCR提取的文本訓(xùn)練語言模型,在多個(gè)AI基準(zhǔn)任務(wù)中平均提高了1.3個(gè)百分點(diǎn)的準(zhǔn)確率。
使用方法
olmOCR提供了Python API和命令行工具,可以輕松地將PDF轉(zhuǎn)換為結(jié)構(gòu)化文本。它還包括評(píng)估工具包、語言過濾、SEO垃圾郵件移除等功能。用戶可以通過GitHub獲取代碼,或使用在線演示來測試其功能。
總之,allenai/olmocr項(xiàng)目為大規(guī)模文檔轉(zhuǎn)換提供了一個(gè)高效、準(zhǔn)確且經(jīng)濟(jì)的解決方案,特別適合需要處理大量PDF文檔的研究和應(yīng)用場景。
安裝命令
# 安裝Miniconda(如果尚未安裝) wget <https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh> -O ~/miniconda.sh ; bash ~/miniconda.sh -b -p $HOME/miniconda ; eval "$($HOME/miniconda/bin/conda shell.bash hook)" ; echo 'export PATH="$HOME/miniconda/bin:$PATH"' >> ~/.bashrc ; source ~/.bashrc conda create -n ai python=3.11 -y && conda activate ai sudo apt-get update sudo apt-get install poppler-utils ttf-mscorefonts-installer msttcorefonts fonts-crosextra-caladea fonts-crosextra-carlito gsfonts lcdf-typetools conda create -n olmocr python=3.11 conda activate olmocr git clone <https://github.com/allenai/olmocr.git> cd olmocr pip install -e . pip install sgl-kernel==0.0.3.post1 --force-reinstall --no-deps pip install "sglang[all]==0.4.2" --find-links <https://flashinfer.ai/whl/cu124/torch2.4/flashinfer/> pip install gradio pandas python -m olmocr.pipeline ./localworkspace --pdfs tests/gnarly_pdfs/horribleocr.pdf cat localworkspace/results/output_*.jsonl
gradio UI代碼
import os
import json
import gradio as gr
import subprocess
import pandas as pd
from pathlib import Path
import shutil
import time
import re
# 創(chuàng)建工作目錄
WORKSPACE_DIR = "olmocr_workspace"
os.makedirs(WORKSPACE_DIR, exist_ok=True)
def modify_html_for_better_display(html_content):
"""修改HTML以便在Gradio中更好地顯示"""
if not html_content:
return html_content
# 增加容器寬度
html_content = html_content.replace('<div class="container">',
'<div class="container" style="max-width: 100%; width: 100%;">')
# 增加文本大小
html_content = html_content.replace('<style>',
'<style>\nbody {font-size: 16px;}\n.text-content {font-size: 16px; line-height: 1.5;}\n')
# 調(diào)整圖像和文本部分的大小比例
html_content = html_content.replace('<div class="row">',
'<div class="row" style="display: flex; flex-wrap: wrap;">')
html_content = html_content.replace('<div class="col-md-6">',
'<div class="col-md-6" style="flex: 0 0 50%; max-width: 50%; padding: 15px;">')
# 增加頁面之間的間距
html_content = html_content.replace('<div class="page">',
'<div class="page" style="margin-bottom: 30px; border-bottom: 1px solid #ccc; padding-bottom: 20px;">')
# 增加圖像大小
html_content = re.sub(r'<img([^>]*)style="([^"]*)"',
r'<img\1style="max-width: 100%; height: auto; \2"',
html_content)
# 添加縮放控制
zoom_controls = """
<div style="position: fixed; bottom: 20px; right: 20px; background: #fff; padding: 10px; border-radius: 5px; box-shadow: 0 0 10px rgba(0,0,0,0.2); z-index: 1000;">
<button onclick="document.body.style.zoom = parseFloat(document.body.style.zoom || 1) + 0.1;" style="margin-right: 5px;">放大</button>
<button onclick="document.body.style.zoom = parseFloat(document.body.style.zoom || 1) - 0.1;">縮小</button>
</div>
"""
html_content = html_content.replace('</body>', f'{zoom_controls}</body>')
return html_content
def process_pdf(pdf_file):
"""處理PDF文件并返回結(jié)果"""
if pdf_file is None:
return "請(qǐng)上傳PDF文件", "", None, None
# 創(chuàng)建一個(gè)唯一的工作目錄
timestamp = int(time.time())
work_dir = os.path.join(WORKSPACE_DIR, f"job_{timestamp}")
os.makedirs(work_dir, exist_ok=True)
# 復(fù)制PDF文件
pdf_path = os.path.join(work_dir, "input.pdf")
shutil.copy(pdf_file, pdf_path)
# 構(gòu)建命令并執(zhí)行
cmd = ["python", "-m", "olmocr.pipeline", work_dir, "--pdfs", pdf_path]
try:
# 執(zhí)行命令,等待完成
process = subprocess.run(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
check=True
)
# 命令輸出
log_text = process.stdout
# 檢查結(jié)果目錄
results_dir = os.path.join(work_dir, "results")
if not os.path.exists(results_dir):
return f"處理完成,但未生成結(jié)果目錄\n\n日志輸出:\n{log_text}", "", None, None
# 查找輸出文件
output_files = list(Path(results_dir).glob("output_*.jsonl"))
if not output_files:
return f"處理完成,但未找到輸出文件\n\n日志輸出:\n{log_text}", "", None, None
# 讀取JSONL文件
output_file = output_files[0]
with open(output_file, "r") as f:
content = f.read().strip()
if not content:
return f"輸出文件為空\n\n日志輸出:\n{log_text}", "", None, None
# 解析JSON
result = json.loads(content)
extracted_text = result.get("text", "未找到文本內(nèi)容")
# 生成HTML預(yù)覽
try:
preview_cmd = ["python", "-m", "olmocr.viewer.dolmaviewer", str(output_file)]
subprocess.run(preview_cmd, check=True)
except Exception as e:
log_text += f"\n生成HTML預(yù)覽失敗: {str(e)}"
# 查找HTML文件
html_files = list(Path("dolma_previews").glob("*.html"))
html_content = ""
if html_files:
try:
with open(html_files[0], "r", encoding="utf-8") as hf:
html_content = hf.read()
# 修改HTML以更好地顯示
html_content = modify_html_for_better_display(html_content)
except Exception as e:
log_text += f"\n讀取HTML預(yù)覽失敗: {str(e)}"
# 創(chuàng)建元數(shù)據(jù)表格
metadata = result.get("metadata", {})
meta_rows = []
for key, value in metadata.items():
meta_rows.append([key, value])
df = pd.DataFrame(meta_rows, columns=["屬性", "值"])
return log_text, extracted_text, html_content, df
except subprocess.CalledProcessError as e:
return f"命令執(zhí)行失敗: {e.stderr}", "", None, None
except Exception as e:
return f"處理過程中發(fā)生錯(cuò)誤: {str(e)}", "", None, None
# 創(chuàng)建Gradio界面
with gr.Blocks(title="olmOCR PDF提取工具") as app:
gr.Markdown("# olmOCR PDF文本提取工具")
with gr.Row():
with gr.Column(scale=1):
pdf_input = gr.File(label="上傳PDF文件", file_types=[".pdf"])
process_btn = gr.Button("處理PDF", variant="primary")
with gr.Column(scale=2):
tabs = gr.Tabs()
with tabs:
with gr.TabItem("提取文本"):
text_output = gr.Textbox(label="提取的文本", lines=20, interactive=True)
with gr.TabItem("HTML預(yù)覽", id="html_preview_tab"):
# 使用更大的HTML組件
html_output = gr.HTML(label="HTML預(yù)覽", elem_id="html_preview_container")
with gr.TabItem("元數(shù)據(jù)"):
meta_output = gr.DataFrame(label="文檔元數(shù)據(jù)")
with gr.TabItem("日志"):
log_output = gr.Textbox(label="處理日志", lines=15, interactive=False)
# 使用CSS自定義HTML預(yù)覽標(biāo)簽頁和內(nèi)容大小
gr.HTML("""
<style>
#html_preview_container {
height: 800px;
width: 100%;
overflow: auto;
border: 1px solid #ddd;
border-radius: 4px;
}
#html_preview_container iframe {
width: 100%;
height: 100%;
border: none;
}
</style>
""")
# 添加操作說明
gr.Markdown("""
## 使用說明
1. 上傳PDF文件
2. 點(diǎn)擊"處理PDF"按鈕
3. 等待處理完成
4. 查看提取的文本和HTML預(yù)覽
### 關(guān)于HTML預(yù)覽
- HTML預(yù)覽展示原始PDF頁面和提取的文本對(duì)照
- 可以清楚地看到OCR過程的精確度
- 如果預(yù)覽內(nèi)容太小,可以使用右下角的放大/縮小按鈕調(diào)整
## 注意
- 處理過程可能需要幾分鐘,請(qǐng)耐心等待
- 首次運(yùn)行會(huì)下載模型(約7GB)
""")
# 綁定按鈕事件 - 使用阻塞模式
process_btn.click(
fn=process_pdf,
inputs=pdf_input,
outputs=[log_output, text_output, html_output, meta_output],
api_name="process"
)
# 啟動(dòng)應(yīng)用
if __name__ == "__main__":
app.launch(share=True)
以上就是Python調(diào)用olmOCR大模型實(shí)現(xiàn)提取復(fù)雜PDF文件內(nèi)容的詳細(xì)內(nèi)容,更多關(guān)于Python olmOCR提取PDF內(nèi)容的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python如何使用Requests下載文件并且顯示進(jìn)度條
這篇文章主要為大家詳細(xì)介紹了如何使用?Requests?下載文件并且顯示進(jìn)度條,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-12-12
Python開發(fā)時(shí)報(bào)TypeError:?‘int‘?object?is?not?iterable錯(cuò)誤的解決方
Python寫循環(huán)程序的時(shí)候遇到TypeError:'int'object is not iterable,所以下面這篇文章主要給大家介紹了關(guān)于Python開發(fā)時(shí)報(bào)TypeError:'int'?object?is?not?iterable錯(cuò)誤的解決方式,需要的朋友可以參考下2022-06-06
Python控制自己的手機(jī)攝像頭拍照并自動(dòng)發(fā)送到郵箱案例講解
這篇文章主要介紹了Python控制自己的手機(jī)攝像頭拍照,并把照片自動(dòng)發(fā)送到郵箱,大概思路是通過opencv調(diào)用攝像頭拍照保存圖像本地用email庫構(gòu)造郵件內(nèi)容,保存的圖像以附件形式插入郵件內(nèi)容用smtplib庫發(fā)送郵件到指定郵箱,需要的朋友可以參考下2022-04-04
DataFrame.to_excel多次寫入不同Sheet的實(shí)例
今天小編就為大家分享一篇DataFrame.to_excel多次寫入不同Sheet的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-12-12
python3+django2開發(fā)一個(gè)簡單的人員管理系統(tǒng)過程詳解
這篇文章主要介紹了python3+django2開發(fā)一個(gè)簡單的人員管理系統(tǒng)過程詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-07-07
Python中yield的用法和實(shí)際應(yīng)用示例
在Python中,yield關(guān)鍵字主要用于生成器函數(shù)(generator functions)中,其目的是使函數(shù)能夠像迭代器一樣工作,即可以被遍歷,但不會(huì)一次性將所有結(jié)果都加載到內(nèi)存中,本文將詳細(xì)介紹yield的用法和一些實(shí)際應(yīng)用示例,感興趣的朋友一起看看吧2025-08-08
從基礎(chǔ)到高級(jí)詳解Python迭代器手動(dòng)訪問完全指南
在Python高級(jí)編程中,手動(dòng)控制迭代器是處理復(fù)雜數(shù)據(jù)流的關(guān)鍵技術(shù),本文將深入解析Python手動(dòng)迭代技術(shù)體系,并拓展大數(shù)據(jù)處理、流式計(jì)算、自定義數(shù)據(jù)結(jié)構(gòu)等工程級(jí)應(yīng)用場景2025-09-09

