寫了個腳本將pdf轉markdown

看到有人需要將掃描pdf文檔轉markdown,想起之前寫的一個小工具。
這個腳本是為了將pdf轉成markdown,只需要申請一個智譜的api key,并填到config里,使用的模型是4v flash,免費的,所以可以放心使用。
效果如下圖:
在這里插入圖片描述

腳本里的提示詞可以根據個人需要進行修改。以下是原始代碼:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-"""
PDF轉Markdown自動化系統
功能:監控input/目錄下的PDF文件,轉換為Markdown格式
作者:您的專屬程序員
日期:2025-04-03
版本:2.0.0
"""import base64
import logging
import time
import json
import os
import fitz  # PyMuPDF
from pathlib import Path
from typing import Optional, Dict, Any, List, Generator
from zhipuai import ZhipuAI
from zhipuai.core._errors import ZhipuAIError# 配置日志系統
logging.basicConfig(level=logging.INFO,format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',handlers=[logging.FileHandler('pdf2md.log'),logging.StreamHandler()]
)
logger = logging.getLogger(__name__)class GLM4VTester:"""GLM-4V 模型測試工具類"""def __init__(self, api_key: str, model_name: str = "glm-4v-flash"):self.client = ZhipuAI(api_key=api_key)self.model_name = model_nameself.total_tokens = 0self.total_requests = 0self.total_time = 0.0def analyze_image(self, image_path: str, prompt: str = "你是一個OCR助手,請把圖中內容按原有格式輸出出來,如果有公式則輸出為LaTeX") -> Dict[str, Any]:"""分析圖片內容:param image_path: 圖片路徑:param prompt: 提示詞:return: API響應結果"""start_time = time.time()# 讀取圖片并轉為base64with open(image_path, "rb") as image_file:base64_image = base64.b64encode(image_file.read()).decode('utf-8')# 調用APIresponse = self.client.chat.completions.create(model=self.model_name,messages=[{"role": "user", "content": [{"type": "text", "text": prompt},{"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{base64_image}"}}]}])# 更新統計信息elapsed_time = time.time() - start_timeself.total_requests += 1self.total_time += elapsed_timeif hasattr(response, 'usage') and response.usage:self.total_tokens += response.usage.total_tokenslogger.info(f"API請求完成,耗時: {elapsed_time:.2f}秒")return {"response": response, "time": elapsed_time}def generate_markdown_report(self, image_path: str, result: Dict[str, Any], output_path: str) -> str:"""生成Markdown格式的分析報告:param image_path: 原始圖片路徑:param result: API響應結果:param output_path: 輸出文件路徑:return: 生成的Markdown內容"""response = result["response"]elapsed_time = result["time"]# 提取文本內容content = response.choices[0].message.content# 生成Markdownmarkdown = f"""# 圖像分析報告## 原始圖像
![原始圖像]({os.path.abspath(image_path)})## 分析結果
{content}## 統計信息
- 處理時間: {elapsed_time:.2f}秒
- 總請求數: {self.total_requests}
- 總Token數: {self.total_tokens}
- 平均響應時間: {self.total_time/self.total_requests:.2f}秒
"""# 保存到文件with open(output_path, 'w', encoding='utf-8') as f:f.write(markdown)return markdownclass ProcessingConfig:"""PDF處理配置類"""def __init__(self, config_dict: Dict[str, Any]):self.api_key = config_dict.get("api_key", "")self.input_dir = config_dict.get("input_dir", "input")self.output_dir = config_dict.get("output_dir", "output")self.model = config_dict.get("model", "glm-4v-flash")self.dpi = config_dict.get("dpi", 600)self.api_interval = config_dict.get("api_interval", 3.0)self.max_retries = config_dict.get("max_retries", 3)self.retry_backoff = config_dict.get("retry_backoff", 0.5)self.prompt = config_dict.get("prompt", "你是一個OCR助手,請把圖中內容按原有格式輸出出來,不要翻譯,如果有公式則輸出為LaTeX,圖片忽略不管")class PDFProcessor:"""PDF處理核心類"""def __init__(self, config: ProcessingConfig, ocr_engine: GLM4VTester):"""初始化PDF處理器:param config: 處理配置:param ocr_engine: OCR引擎實例"""self.config = configself.ocr_engine = ocr_engineself.temp_dir = "temp_images"os.makedirs(self.temp_dir, exist_ok=True)def _convert_page_to_image(self, page, page_num: int) -> str:"""將PDF頁面轉換為圖片:param page: PyMuPDF頁面對象:param page_num: 頁碼:return: 圖片文件路徑"""pix = page.get_pixmap(dpi=self.config.dpi)img_path = os.path.join(self.temp_dir, f"page_{page_num}.png")pix.save(img_path)return img_pathdef _safe_api_call(self, image_path: str) -> str:"""安全的API調用方法,包含重試機制:param image_path: 圖片路徑:return: OCR結果文本"""retries = 0while retries <= self.config.max_retries:try:time.sleep(self.config.api_interval + (retries * self.config.retry_backoff))result = self.ocr_engine.analyze_image(image_path, self.config.prompt)return result["response"].choices[0].message.contentexcept ZhipuAIError as e:logger.warning(f"API調用失敗(重試 {retries}/{self.config.max_retries}): {e}")retries += 1raise Exception(f"API調用失敗,超過最大重試次數 {self.config.max_retries}")def _format_page(self, content: str, page_num: int) -> str:"""格式化單頁內容為Markdown:param content: OCR原始內容:param page_num: 頁碼:return: 格式化后的Markdown"""return f"## 第 {page_num} 頁\n\n{content}\n\n---\n"def process_pdf(self, pdf_path: str) -> Generator[str, None, None]:"""處理單個PDF文件:param pdf_path: PDF文件路徑:return: 生成Markdown內容"""logger.info(f"開始處理PDF文件: {pdf_path}")with fitz.open(pdf_path) as doc:for page_num, page in enumerate(doc, start=1):try:# 轉換為圖片img_path = self._convert_page_to_image(page, page_num)# OCR識別content = self._safe_api_call(img_path)# 格式化輸出yield self._format_page(content, page_num)# 清理臨時圖片os.remove(img_path)except Exception as e:logger.error(f"處理第{page_num}頁時出錯: {e}")yield f"## 第 {page_num} 頁\n\n[處理錯誤: {str(e)}]\n\n"logger.info(f"完成PDF處理: {pdf_path}")def process_single_image(config: ProcessingConfig, image_path: str, output_path: str):"""處理單張圖片模式"""try:tester = GLM4VTester(api_key=config.api_key, model_name=config.model)logger.info(f"開始分析文件: {image_path}")result = tester.analyze_image(image_path, config.prompt)markdown = tester.generate_markdown_report(image_path, result, output_path)print(f"\n分析完成! 結果已保存到: {output_path}\n")return Trueexcept Exception as e:logger.error(f"文件處理失敗: {e}")return Falsedef process_pdf_file(config: ProcessingConfig, pdf_path: str, output_path: str):"""處理PDF文件模式"""try:tester = GLM4VTester(api_key=config.api_key, model_name=config.model)processor = PDFProcessor(config, tester)with open(output_path, 'w', encoding='utf-8') as f:for page_content in processor.process_pdf(pdf_path):f.write(page_content)logger.info(f"PDF轉換完成! 結果已保存到: {output_path}")return Trueexcept Exception as e:logger.error(f"PDF處理失敗: {e}")return Falsedef batch_process_pdfs(config: ProcessingConfig):"""批量處理input/目錄下的PDF文件"""tester = GLM4VTester(api_key=config.api_key, model_name=config.model)processor = PDFProcessor(config, tester)input_dir = config.input_diroutput_dir = config.output_diros.makedirs(input_dir, exist_ok=True)os.makedirs(output_dir, exist_ok=True)processed_files = set()if os.path.exists("processed.log"):with open("processed.log", "r") as f:processed_files = set(f.read().splitlines())while True:try:for filename in os.listdir(input_dir):if filename.lower().endswith('.pdf') and filename not in processed_files:pdf_path = os.path.join(input_dir, filename)output_path = os.path.join(output_dir, f"{os.path.splitext(filename)[0]}.md")logger.info(f"開始處理: {filename}")with open(output_path, 'w', encoding='utf-8') as f:for page_content in processor.process_pdf(pdf_path):f.write(page_content)# 記錄已處理文件with open("processed.log", "a") as f:f.write(f"{filename}\n")processed_files.add(filename)logger.info(f"處理完成: {filename} -> {output_path}")time.sleep(10)  # 每10秒檢查一次新文件except KeyboardInterrupt:logger.info("收到中斷信號,停止處理")breakexcept Exception as e:logger.error(f"批量處理出錯: {e}")time.sleep(30)  # 出錯后等待30秒再重試def load_config():"""加載配置文件"""config_path = "config.json"default_config = {"api_key": "","input_dir": "input","output_dir": "output","model": "glm-4v-flash","dpi": 600,"api_interval": 3.0,"max_retries": 3,"retry_backoff": 0.5,"prompt": "你是一個OCR助手,請把圖中內容按原有格式輸出出來,如果有公式則輸出為LaTeX,圖片請用《》描述"}try:with open(config_path, 'r') as f:config = json.load(f)# 合并配置,優先使用配置文件中的值return {**default_config, **config}except FileNotFoundError:logger.warning(f"配置文件 {config_path} 未找到,使用默認配置")# 創建默認配置文件with open(config_path, 'w') as f:json.dump(default_config, f, indent=2)return default_configexcept json.JSONDecodeError as e:logger.error(f"配置文件格式錯誤: {e}")return default_configdef main():"""主函數"""config_dict = load_config()config = ProcessingConfig(config_dict)# 檢查API密鑰是否設置if not config.api_key:logger.error("API密鑰未設置,請在config.json中設置api_key")exit(1)# 確保目錄存在os.makedirs(config.input_dir, exist_ok=True)os.makedirs(config.output_dir, exist_ok=True)# 直接啟動批處理模式logger.info(f"啟動批處理模式,監控目錄: {config.input_dir}")batch_process_pdfs(config)if __name__ == '__main__':main()

自己修改一下config里面的智譜api key:

{"api_key": "智譜的api_key","input_dir": "input","output_dir": "output", "model": "glm-4v-flash","dpi": 600,"api_interval": 3.0,"max_retries": 3,"retry_backoff": 0.5
}

缺點是由于是ocr,所以無法提取圖片,有需要圖片的用minerU或者marker,我試了marker,效果還可以的。

🔥運維干貨分享

  • 軟考高級系統架構設計師備考學習資料
  • 軟考中級數據庫系統工程師學習資料
  • 軟考高級網絡規劃設計師備考學習資料
  • Kubernetes CKA認證學習資料分享
  • AI大模型學習資料合集
  • 免費文檔翻譯工具(支持word、pdf、ppt、excel)
  • PuTTY中文版安裝包
  • MobaXterm中文版安裝包
  • pinginfoview網絡診斷工具中文版
  • Xshell、Xsftp、Xmanager中文版安裝包
  • Typora簡單易用的Markdown編輯器
  • Window進程監控工具,能自動重啟進程和卡死檢測
  • Spring 源碼學習資料分享
  • 畢業設計高質量畢業答辯 PPT 模板分享
  • IT行業工程師面試簡歷模板分享

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/79814.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/79814.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/79814.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

CSS--圖片鏈接水平居中展示的方法

原文網址&#xff1a;CSS--圖片鏈接居中展示的方法-CSDN博客 簡介 本文介紹CSS圖片鏈接水平居中展示的方法。 圖片鏈接 問題復現 源碼 <html xml:lang"cn" lang"cn"><head><meta http-equiv"Content-Type" content"te…

工具分享:通過滑塊拉取CAN報文信號數值自動發送報文

0. 概述 CAN報文發送工具使用wxpython進行開發,配套Excel模板可以通過修改Excel自定義界面展示的信號名稱和信號的屬性;同時,工具支持導入現場采集的報文數據自動按照配套Excel模板定義的報文發送周期進行模擬發送。 由于是我好幾年前開發的作品,一些開發細節也記得不是很…

【Python】os模塊

os 模塊是 Python 標準庫中用于與操作系統交互的核心模塊&#xff0c;提供了許多操作文件和目 錄的函數。 1. 基本介紹 os 模塊提供了以下主要功能&#xff1a; 文件和目錄操作路徑操作進程管理環境變量訪問 import os2. 常用功能分類 2.1 文件和目錄操作 函數/方法描述o…

ai agent(智能體)開發 python3基礎11: java 調用python waitfor卡死,導致深入理解操作系統進程模型和IPC機制

java 調用python waitfor 卡死 導致瀏覽器無法自動關閉&#xff0c;java &#xff0c;python雙發無限等待 根源在于還是沒有理解 進程之間標準輸入輸出到底是什么含義 系統進程與跨語言調用的核心機制 在跨語言調用&#xff08;如Java調用Python&#xff09;時&#xff0c;理…

Kubernetes(k8s)學習筆記(九)--搭建多租戶系統

K8s 多租戶管理 多租戶是指在同一集群中隔離多個用戶或團隊&#xff0c;以避免他們之間的資源沖突和誤操作。在K8s中&#xff0c;多租戶管理的核心目標是在保證安全性的同時&#xff0c;提高資源利用率和運營效率。 在K8s中&#xff0c;該操作可以通過命名空間&#xff08;Nam…

同質化的旅游內核

湘西鳳凰古城、北京非常有文藝氛圍的方家胡同都在被改造翻新為現代的其他城市范式式的樣式。 什么意思呢&#xff1f;很多古城的老房子&#xff0c;從外面看&#xff0c;很古老、很漂亮&#xff0c;但是進去以后&#xff0c;完全不是那么回事&#xff0c;整座房子已經被完全掏…

鴻蒙開發——3.ArkTS聲明式開發:構建第一個ArkTS應用

鴻蒙開發——3.ArkTS聲明式開發:構建第一個ArkTS應用 一、創建ArkTS工程二、ArkTS工程目錄結構&#xff08;Stage模型&#xff09;三、構建第一個頁面四、構建第二個頁面五、實現頁面之間的跳轉六、模擬器運行 一、創建ArkTS工程 1、若首次打開DevEco Studio&#xff0c;請點擊…

C語言初階:數組

目錄 0.數組要講的知識點 1.一維數組的創建和初始化 1.1 數組的創建&#xff1a; 1.2數組實例&#xff1a; 1.3 數組的初識化&#xff1a; 例子&#xff1a; 2.一維數組的使用 例子&#xff1a; 總結&#xff1a; 3.一維數組在內存中的存儲 4.二維數組的創建和初始化 4.…

UE5 Daz頭發轉Blender曲線再導出ABC成為Groom

先安裝Daz to Blender Import插件 【神器】 --DAZ一鍵導入blender插件的詳細安裝和使用&#xff0c;自帶骨骼綁定和控制器&#xff0c;多姿勢動畫&#xff0c;Importer橋接插件_嗶哩嗶哩_bilibili 然后安裝DAZHairConverter插件 一分鐘將DAZ頭發轉化成Blender粒子毛發_嗶哩嗶…

淺聊find_package命令的搜索模式(Search Modes)

背景 find_package應該算是我們使用最多的cmake命令了。但是它是如何找到上游庫的.cmake文件的&#xff1f; 根據官方文檔&#xff0c;整理下find_package涉及到的搜索模式。 搜索模式 find_package涉及到的搜索模式有兩種&#xff1a;模塊模式(Module mode)和配置模式(Conf…

什么是先驗?(CVPR25)Detail-Preserving Latent Diffusion for Stable Shadow Removal論文閱讀

文章目錄 先驗&#xff08;Prior&#xff09;是什么&#xff1f;1. 先驗的數學定義2. 先驗在深度生成模型中的角色3. 為什么需要先驗&#xff1f;4. 先驗的常見類型5. 如何選擇或構造先驗&#xff1f;6. 小結 先驗&#xff08;Prior&#xff09;是什么&#xff1f; 在概率統計…

【視覺基礎模型-SAM系列-2】SAM2: Segment Anything in Images and Videos

論文鏈接&#xff1a;SAM 2: Segment Anything in Images and Videos 代碼鏈接&#xff1a;https://github.com/facebookresearch/sam2?tabreadme-ov-file 作者&#xff1a;Nikhila Ravi, Valentin Gabeur, Yuan-Ting Hu, Ronghang Hu, Chaitanya Ryali, Tengyu Ma, Haitham…

OpenShift AI - 模型注冊管理

《OpenShift / RHEL / DevSecOps 匯總目錄》 說明&#xff1a;本文已經在 OpenShift 4.18 OpenShift AI 2.19 的環境中驗證 文章目錄 啟用模型注冊管理功能安裝管理數據庫啟用模型注冊功能 注冊模型部署模型歸檔模型歸檔模型和模型版本恢復歸檔模型 模型注冊表訪問權限管理參考…

【背包dp----01背包】例題三------(標準的01背包+變種01背包1【恰好裝滿背包體積 產生的 最大價值】)

【模板】01背包 題目鏈接 題目描述 : 輸入描述: 輸出描述: 示例1 輸入 3 5 2 10 4 5 1 4輸出 14 9說明 裝第一個和第三個物品時總價值最大&#xff0c;但是裝第二個和第三個物品可以使得背包恰好裝滿且總價值最大。 示例2 輸入 3 8 12 6 11 8 6 8輸出 8 0說明 裝第三個物…

Node.js 的 child_process 模塊詳解

Node.js 的 child_process 模塊提供了創建子進程的能力,使 Node.js 應用能夠執行系統命令、運行其他程序或腳本。這個模塊非常強大,可以幫助我們實現很多復雜的功能。 1. exec - 執行 shell 命令 exec 方法用于執行 shell 命令,并緩沖任何產生的輸出。 特點 創建 shell 來…

進程與線程詳細介紹

目錄 一 進程概念 二 進程的組成 2.1 PCB 2.2 數據段 2.3 程序段 三 進程的五大特點 四 進程的創建與銷毀 五 線程概念 六 線程特征 七 進程與線程的區別與聯系 區別 聯系 一 進程概念 進程是程序的一次執行過程&#xff0c;是操作系統進行資源分配和調度的基本單位…

如何在服務器后臺運行Python腳本,并配置虛擬環境與GPU支持

使用Conda虛擬環境在服務器后臺運行Python腳本&#xff0c;并檢查GPU分配 在服務器開發環境中&#xff0c;我們需要確保Python腳本運行在指定的Conda虛擬環境中&#xff0c;并且確認是否正確分配了GPU資源。本文將通過一個完整的start.sh腳本&#xff0c;完成以下功能&#xff…

前端取經路——工程化渡劫:八戒的構建之道

大家好,我是老十三,一名前端開發工程師。前端工程化就像八戒的釘耙,看似簡單卻能降妖除魔。在本文中,我將帶你探索前端工程化的九大難題,從模塊化組織到CI/CD流程,從代碼規范到自動化測試,揭示這些工具背后的核心原理。無論你是初學者還是資深工程師,這些構建之道都能幫…

Ubuntu 安裝 Keepalived

Keepalived 是什么 Keepalived 是一個用于實現高可用性&#xff08;High Availability, HA&#xff09;的服務&#xff0c;是一款基于 VRRP 協議的高可用軟件&#xff0c;常用于主備切換和虛擬IP漂移&#xff0c;在服務故障時自動實現故障轉移。 Keepalived 的核心功能 功能說…

DHCP理解

文章目錄 DHCP理解DHCP的核心作用DHCP默認端口DHCP的工作原理&#xff08;4個步驟&#xff09;圖示說明&#xff08;含中繼代理&#xff09;DHCP Discover&#xff08;客戶端發現階段&#xff09;DHCP Offer&#xff08;服務器提供階段&#xff09;DHCP Request&#xff08;客戶…