Python調(diào)用ollama本地大模型進(jìn)行批量識(shí)別PDF
現(xiàn)在市場(chǎng)上有很多PDF文件的識(shí)別,轉(zhuǎn)化,等等。有些業(yè)務(wù)可能需要總結(jié)摘要和關(guān)鍵詞等等一系列的操作。然而隨著AI的興起,本地大模型的部署,這些成為一種很方便的方法,接下來(lái)我將為各位介紹我所使用的方法。
本篇文章旨在自動(dòng)化處理 PDF 文檔,提取并清理文本數(shù)據(jù),然后使用一種大型模型生成摘要和關(guān)鍵詞。最后,處理結(jié)果會(huì)被整理并輸出到 Excel 文件中,便于后續(xù)分析和查看。
人工智能(AI)是一種模擬人類智能的科技,它已經(jīng)在現(xiàn)代科技中得到廣泛應(yīng)用,并且是未來(lái)發(fā)展的重點(diǎn)領(lǐng)域之一。人工智能應(yīng)用領(lǐng)域多樣,包括機(jī)器學(xué)習(xí)和數(shù)據(jù)分析、自然語(yǔ)言處理、機(jī)器視覺(jué)、自動(dòng)化和機(jī)器人等。未來(lái)發(fā)展趨勢(shì)包括深度學(xué)習(xí)和神經(jīng)網(wǎng)絡(luò)、增強(qiáng)學(xué)習(xí)、多模態(tài)融合和泛用人工智能。總體而言,人工智能的應(yīng)用將繼續(xù)擴(kuò)大,并在不同領(lǐng)域帶來(lái)更多的創(chuàng)新和進(jìn)步。(廢話~~~)
首先我們需要下載兩個(gè)庫(kù)PyPDF2以及ollama庫(kù)。(通過(guò)ollama部署好本地大模型:qwen2:14b或者其他大模型,這里部署步驟不再贅述,已經(jīng)有很成熟的步驟)方便調(diào)用~~終端輸入如下指令。
pip install PyPDF2 pip install ollama
PyPDF2是一個(gè)用于合并、分割、提取文本和元數(shù)據(jù)等PDF文件操作的Python庫(kù)。它建立在PDFMiner庫(kù)的基礎(chǔ)上,提供了更高級(jí)別的功能和易用性。ollama庫(kù)是一個(gè)用于機(jī)器學(xué)習(xí)和深度學(xué)習(xí)的Python庫(kù)。它提供了一系列功能強(qiáng)大的工具和函數(shù),用于數(shù)據(jù)處理、模型構(gòu)建、特征工程、模型選擇和評(píng)估等任務(wù)。兩者的結(jié)合則成為了如今的成果。話不多說(shuō),直接上代碼。
首先,在我們進(jìn)行批量處理PDF文件時(shí),先要了解如何處理單個(gè)PDF,然后再進(jìn)行實(shí)現(xiàn)批量PDF的處理實(shí)現(xiàn),如下是如何處理單個(gè)PDF,并設(shè)有異常處理,在處理PDF時(shí)存在部分亂碼,可能是包含有圖片格式的問(wèn)題,故此設(shè)置了清洗文本,只保留了可以打印的字符,在提交給大模型進(jìn)行回答時(shí)不受影響,個(gè)人沒(méi)有進(jìn)行未清洗測(cè)試。
def clean_text(text):
text = re.sub(r'[^\x20-\x7E]+', '', text) # 只保留可打印的 ASCII 字符
return re.sub(r'\s+', ' ', text).strip()
def process_pdf(pdf_path, output_path):
try:
with open(pdf_path, "rb") as file:
reader = PyPDF2.PdfReader(file)
with open(output_path, "w", encoding='utf-8') as output_file:
for page in reader.pages:
text = page.extract_text()
if text: # 檢查是否成功提取文本
clean_text_result = clean_text(text) # 清理文本
output_file.write(clean_text_result + "\n") # 寫入文件
else:
output_file.write("未提取到有效文本\n")
except FileNotFoundError:
print(f"文件未找到: {pdf_path}")
return False
except PyPDF2.errors.PdfReadError:
print(f"無(wú)法讀取PDF文件: {pdf_path}")
return False
except Exception as e:
print(f"處理PDF文件時(shí)發(fā)生錯(cuò)誤: {pdf_path}, 錯(cuò)誤信息: {e}")
return False
return True接下來(lái)是定義超時(shí)處理異常類,在后面進(jìn)行測(cè)試時(shí)發(fā)現(xiàn),部分PDF通過(guò)這里無(wú)法執(zhí)行,就會(huì)一直卡著,增加超時(shí)處理,更方便后續(xù)進(jìn)程的實(shí)現(xiàn)。
# 定義超時(shí)處理異常類
class TimeoutException(Exception):
pass
# 定義帶超時(shí)功能的線程類
class TimeoutThread(threading.Thread):
"""
允許超時(shí)處理的線程類。
"""
def __init__(self, target, args=(), kwargs={}):
threading.Thread.__init__(self)
self.target = target
self.args = args
self.kwargs = kwargs
self.result = None
self.exception = None
def run(self):
try:
self.result = self.target(*self.args, **self.kwargs)
except Exception as e:
self.exception = e
def join(self, timeout=None):
super(TimeoutThread, self).join(timeout)
if self.is_alive():
raise TimeoutException("處理超時(shí)")
if self.exception:
raise self.exception
return self.result這段是處理指定文件夾中的所有PDF文件,并讀取PDF識(shí)別后的txt文件中的文章信息,提交給本地大模型,我這里使用的qwen2.5:14b,總體上來(lái)說(shuō),qwen2.5還是好用的,并將結(jié)果保存到EXCEL中。至于替換信息是因?yàn)?,qwen2.5給到的返回信息也是需要清理的。
def process_folder(folder_path, output_folder, excel_path):
"""
處理指定文件夾中的所有PDF文件,并將結(jié)果保存到Excel文件中。
"""
if not os.path.exists(output_folder):
os.makedirs(output_folder)
pdf_files = glob.glob(os.path.join(folder_path, "*.pdf"))
results = []
total_files = len(pdf_files)
processed_files = 0
errors = []
unprocessed_files = []
for pdf_file in pdf_files:
base_name = os.path.basename(pdf_file).replace(".pdf", ".txt")
output_path = os.path.join(output_folder, base_name)
success = process_pdf(pdf_file, output_path)
if not success:
errors.append(pdf_file)
continue
with open(output_path, "r", encoding='utf-8') as file:
content = file.read()
try:
# 使用線程實(shí)現(xiàn)超時(shí)處理
def process_model():
title = base_name.split(".txt")[0]
res = ollama.chat(model='qwen2.5:14b', stream=False, messages=[{"role": "user", "content": f"{content}總結(jié)成摘要和關(guān)鍵詞"}], options={"temperature": 0})
summary = res['message']['content'].split('### 摘要\n\n')[1].split('\n\n### 關(guān)鍵詞')[0]
keywords = res['message']['content'].split('### 關(guān)鍵詞\n\n')[1].split('\n- ')[1:]
keywords = '、'.join(keywords)
results.append({"文件名": title, "摘要": summary, "關(guān)鍵詞": keywords})
print(res)
timeout_thread = TimeoutThread(target=process_model)
timeout_thread.start()
timeout_thread.join(timeout=30)
except TimeoutException:
print(f"處理大模型時(shí)超時(shí): {pdf_file}")
errors.append(pdf_file)
except Exception as e:
print(f"處理大模型時(shí)發(fā)生錯(cuò)誤: {pdf_file}, 錯(cuò)誤信息: {e}")
errors.append(pdf_file)
processed_files += 1
print(f"進(jìn)度: {processed_files}/{total_files} 文件已處理")
# 每次處理完一個(gè)文件后保存Excel文件
write_to_excel(results, excel_path)
# 記錄未處理的文件
unprocessed_files = pdf_files[processed_files:]
return results, errors, unprocessed_files返回的信息如圖所示,所以我們需要進(jìn)一步處理。

最后我們將總結(jié)出來(lái)的關(guān)鍵詞,文章摘要,以及對(duì)應(yīng)的PDF標(biāo)題寫入EXCEL中。
def write_to_excel(results, excel_path):
df = pd.DataFrame(results)
df.to_excel(excel_path, index=False)
最后加上我們的主函數(shù),完整代碼如下:
import PyPDF2
import re
import ollama
import os
import glob
import pandas as pd
import threading
import time
# 定義函數(shù)來(lái)去除特殊空格和非法字符
def clean_text(text):
# 移除特定的非法字符
text = re.sub(r'[^\x20-\x7E]+', '', text) # 只保留可打印的 ASCII 字符
# 替換多個(gè)空格
return re.sub(r'\s+', ' ', text).strip()
# 定義函數(shù)來(lái)處理單個(gè)PDF文件
def process_pdf(pdf_path, output_path):
"""
處理單個(gè)PDF文件,提取文本并輸出到指定路徑。
"""
try:
with open(pdf_path, "rb") as file:
reader = PyPDF2.PdfReader(file)
with open(output_path, "w", encoding='utf-8') as output_file:
for page in reader.pages:
text = page.extract_text()
if text: # 檢查是否成功提取文本
clean_text_result = clean_text(text) # 清理文本
output_file.write(clean_text_result + "\n") # 寫入文件
else:
output_file.write("未提取到有效文本\n")
except FileNotFoundError:
print(f"文件未找到: {pdf_path}")
return False
except PyPDF2.errors.PdfReadError:
print(f"無(wú)法讀取PDF文件: {pdf_path}")
return False
except Exception as e:
print(f"處理PDF文件時(shí)發(fā)生錯(cuò)誤: {pdf_path}, 錯(cuò)誤信息: {e}")
return False
return True
# 定義超時(shí)處理異常類
class TimeoutException(Exception):
pass
# 定義帶超時(shí)功能的線程類
class TimeoutThread(threading.Thread):
"""
允許超時(shí)處理的線程類。
"""
def __init__(self, target, args=(), kwargs={}):
threading.Thread.__init__(self)
self.target = target
self.args = args
self.kwargs = kwargs
self.result = None
self.exception = None
def run(self):
try:
self.result = self.target(*self.args, **self.kwargs)
except Exception as e:
self.exception = e
def join(self, timeout=None):
super(TimeoutThread, self).join(timeout)
if self.is_alive():
raise TimeoutException("處理超時(shí)")
if self.exception:
raise self.exception
return self.result
# 定義函數(shù)來(lái)處理文件夾中的所有PDF文件
def process_folder(folder_path, output_folder, excel_path):
"""
處理指定文件夾中的所有PDF文件,并將結(jié)果保存到Excel文件中。
"""
if not os.path.exists(output_folder):
os.makedirs(output_folder)
pdf_files = glob.glob(os.path.join(folder_path, "*.pdf"))
results = []
total_files = len(pdf_files)
processed_files = 0
errors = []
unprocessed_files = []
for pdf_file in pdf_files:
base_name = os.path.basename(pdf_file).replace(".pdf", ".txt")
output_path = os.path.join(output_folder, base_name)
success = process_pdf(pdf_file, output_path)
if not success:
errors.append(pdf_file)
continue
with open(output_path, "r", encoding='utf-8') as file:
content = file.read()
try:
# 使用線程實(shí)現(xiàn)超時(shí)處理
def process_model():
title = base_name.split(".txt")[0]
res = ollama.chat(model='qwen2.5:14b', stream=False, messages=[{"role": "user", "content": f"{content}總結(jié)成摘要和關(guān)鍵詞"}], options={"temperature": 0})
summary = res['message']['content'].split('### 摘要\n\n')[1].split('\n\n### 關(guān)鍵詞')[0]
keywords = res['message']['content'].split('### 關(guān)鍵詞\n\n')[1].split('\n- ')[1:]
keywords = '、'.join(keywords)
results.append({"文件名": title, "摘要": summary, "關(guān)鍵詞": keywords})
print(res)
timeout_thread = TimeoutThread(target=process_model)
timeout_thread.start()
timeout_thread.join(timeout=30)
except TimeoutException:
print(f"處理大模型時(shí)超時(shí): {pdf_file}")
errors.append(pdf_file)
except Exception as e:
print(f"處理大模型時(shí)發(fā)生錯(cuò)誤: {pdf_file}, 錯(cuò)誤信息: {e}")
errors.append(pdf_file)
processed_files += 1
print(f"進(jìn)度: {processed_files}/{total_files} 文件已處理")
# 每次處理完一個(gè)文件后保存Excel文件
write_to_excel(results, excel_path)
# 記錄未處理的文件
unprocessed_files = pdf_files[processed_files:]
return results, errors, unprocessed_files
# 定義函數(shù)來(lái)將結(jié)果寫入Excel文件
def write_to_excel(results, excel_path):
"""
將處理結(jié)果寫入指定的Excel文件。
"""
df = pd.DataFrame(results)
df.to_excel(excel_path, index=False)
# 主程序
if __name__ == "__main__":
a = input("PDF文件夾路徑:")
b = input("TXT文件輸出路徑:")
c = input("EXCEl文件輸出路徑:")
folder_path = fr"{a}" # 文件夾路徑
output_folder = fr"" # TXT文件輸出路徑
excel_path = fr"{c}\results.xlsx" # Excel文件輸出路徑
results, errors, unprocessed_files = process_folder(folder_path, output_folder, excel_path)
print(f"所有PDF文件已處理完畢,結(jié)果已保存到 {excel_path}")
if errors:
print("以下PDF文件處理失敗:")
for error in errors:
print(error)
if unprocessed_files:
print("以下PDF文件未處理:")
for unprocessed in unprocessed_files:
print(unprocessed)附輸出結(jié)果以及EXCEL表。


實(shí)測(cè)56,成功45,失敗9,總體來(lái)說(shuō)70-80的成功率,但也大大降低的工作量。
以上就是Python調(diào)用ollama本地大模型進(jìn)行批量識(shí)別PDF的詳細(xì)內(nèi)容,更多關(guān)于Python ollama識(shí)別PDF的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
在Django中進(jìn)行用戶注冊(cè)和郵箱驗(yàn)證的方法
這篇文章主要介紹了在Django中進(jìn)行用戶注冊(cè)和郵箱驗(yàn)證的方法的相關(guān)資料,需要的朋友可以參考下2016-05-05
Python編程實(shí)現(xiàn)數(shù)學(xué)運(yùn)算求一元二次方程的實(shí)根算法示例
這篇文章主要介紹了Python編程實(shí)現(xiàn)數(shù)學(xué)運(yùn)算求一元二次方程的實(shí)根算法,涉及Python數(shù)學(xué)運(yùn)算求解方程的相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-04-04
PyChar學(xué)習(xí)教程之自定義文件與代碼模板詳解
pycharm默認(rèn)的【新建】文件,格式很不友好,那么就需要改一下文件模板。下面這篇文章主要給大家介紹了關(guān)于PyChar學(xué)習(xí)教程之自定義文件與代碼模板的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友們下面跟著小編來(lái)一起看看吧。2017-07-07
python內(nèi)置函數(shù)anext的具體使用
本文主要介紹了python內(nèi)置函數(shù)anext的具體使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01
通過(guò)python爬蟲mechanize庫(kù)爬取本機(jī)ip地址的方法
python中的mechanize算是一個(gè)比較古老的庫(kù)了,在python2的時(shí)代中,使用的多一些,在python3以后就很少使用了,現(xiàn)在已經(jīng)是2202年了,可能很多人都沒(méi)聽說(shuō)過(guò)mechanize,這不要緊,我們先來(lái)簡(jiǎn)單的講解一下,如何使用mechanize,感興趣的朋友一起看看吧2022-08-08
Django ORM多對(duì)多查詢方法(自定義第三張表&ManyToManyField)
今天小編就為大家分享一篇Django ORM多對(duì)多查詢方法(自定義第三張表&ManyToManyField),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-08-08

