用 AI 把课件 PDF 一键转成 Markdown
📘 项目背景
每次备课或者复习考试,常见的资料形式都是PDF 版课件:内容多、公式密集、还有各种选择题。
如果想把这些内容整理成可搜索、可编辑的 Markdown 笔记,传统方式通常是:
- 手动复制文字(遇到公式就崩溃)
- 自己用 LaTeX 写公式
- 选择题一个个重排格式
不仅枯燥,而且非常浪费时间。
于是,我基于多模态大模型(支持看图)做了一个“课件 PDF → Markdown 笔记”自动转换工具:
只需要选择输入/输出文件夹,就能把整批 PDF 课件自动转成结构化的 Markdown 文件,公式直接是 KaTeX 格式,选择题排版也自动搞定。
✨ 核心能力概览
| 功能 | 说明 |
|---|---|
| 📄 PDF 批量处理 | 支持选择一个文件夹,一次性处理多个 PDF 课件 |
| 🧠 AI OCR + 理解 | 用多模态大模型识别每一页内容,而不是简单图像 OCR |
| 🧮 KaTeX 数学公式 | 生成符合 Markdown + KaTeX 语法的数学公式 |
| 📝 选择题结构化 | 自动识别“题干 + 选项”,用 A./B./C./D. 规范输出 |
| ⚡ 并发加速 | 利用 asyncio + aiohttp 并发调用 API,加快大课件处理速度 |
| 🔁 稳健重试机制 | 针对限流、内容安全、图片过大等情况做了自动重试与降级提示 |
| 🖼 智能图片压缩 | 图片太大时自动压缩/缩放,以适配 API 限制 |
🏗 整体流程与架构
用一个简单的流程图来概括整个系统:
1 | ┌────────────┐ ┌────────────────────┐ ┌────────────────────┐ |
核心模块对应到代码大致可以分成三部分:
- PDF → 图片:
pdf_to_images - 单页图片 → Markdown 文本(AI 调用):
process_image - 整本 PDF 组织与输出:
process_pdf/process_files/main
下面重点讲 AI 相关的部分。
🤖 AI 应用详解:从图片到 Markdown 笔记
1. 多模态模型:从“看图”直接输出 Markdown + KaTeX
传统 OCR 工具只能把图片中的文字“抠出来”,但:
- 无法理解题目结构
- 公式识别不友好,很难直接用于 Markdown/KaTeX
- 选择题格式往往乱掉
在这个项目里,我直接把每一页课件渲染成图片,交给支持图像理解的多模态大模型处理。
在代码中,核心是一个精心设计的 system prompt,告诉模型我要的“输出格式”:
1 | system_prompt = """ |
在真正的实现里,我还加了一些具体例子,让模型模仿我想要的格式,例如:
- 如何写“第 35 题”的标题
- 选择题 A./B./C./D. 的排版样式
- 多行公式的写法
这样模型输出的结果基本可以直接贴到 Obsidian / Hexo / Markdown 编辑器里使用。
注意:实际代码中我有更多细节提示,这里做了部分简化,避免暴露完整提示工程。
2. 异步并发调用:整本课件同时跑
一本课件往往几十页,如果一页一页串行调用 AI 接口,会非常慢。
所以我使用了 asyncio + aiohttp + Semaphore 进行并发控制:
1 | CONCURRENCY = 20 # 同时最多处理 20 页 |
而 process_image 里核心逻辑是:
- 进入信号量,保证最多只有
CONCURRENCY个并发请求 - 把图片编码成 base64,按照兼容 OpenAI 的格式组织请求体
- 接收模型返回的 Markdown 文本
- 出错时根据错误类型做不同处理(重试、压缩、跳过等)
请求部分的结构大致如下(已去除具体地址与 Key):
1 | API_BASE_URL = "你的接口地址" # 实际代码中为私有配置 |
这里刻意没有给出真实
API_BASE_URL、API_KEY和完整参数,只展示结构,方便你替换成自己的服务。
3. 容错策略:图片太大、内容敏感、限流… 都有对策
在实际使用中,AI 接口最容易出现几类问题:
- 图片太大,超过模型限制
- 内容被误判为不安全(例如包含“政治”“敏感”等关键词)
- API 限流或网络不稳定
- 某些页结构特殊,模型多次失败
我在 process_image 中对这些情况做了分类处理:
3.1 文件过大:自动压缩再重试
当错误信息中出现“exceeded limit on max bytes”“data-uri item”等关键字时,判断为图片太大:
- 第一次遇到时,会调用
compress_image:- 先尝试降低 JPEG 质量
- 还不够再缩小分辨率
- 最后保底用一个较小尺寸 + 低质量版本
- 再用压缩后的图片重新调用 AI
- 如果多次压缩仍不满足大小限制,就在结果中写入一段提示文本,告诉你哪一页没能处理
压缩逻辑大致如下(去掉了一些打印细节):
1 | from PIL import Image |
3.2 内容安全/敏感词:跳过该页并写入说明
当错误信息里包含“data_inspection_failed”“inappropriate content”“政治”“敏感”“policy”等关键词时:
- 在命令行输出详细提示
- 在生成的 Markdown 中写入一段带 ⚠️ 提示的说明
- 并跳过该页内容的进一步重试
这样你在之后复盘时,可以清晰看到:
第 X 页可能包含敏感内容/质量过差,已跳过处理。
3.3 限流与网络问题:指数退避重试
对于限流、配额、网络超时这类错误:
- 统一采用最多 N 次重试 + 指数退避策略:
- 第 1 次失败后等 0 秒
- 第 2 次失败等 2 秒
- 第 3 次失败等 4 秒
- …
- 超过最大重试次数依然失败,则在该页输出
None,并在最终统计中归为“失败页面”。
📄 从 PDF 到 Markdown 文件:输出结构
每个 PDF 最终会对应一个同名的 .md 文件,例如:
概率论-期中复习.pdf→概率论-期中复习.md
文件内容按“每一页一个小节”组织:
1 | ## 第 1 页 |
脚本会统计:
- 成功处理了多少页
- 哪些页失败
- 失败页的编号列表
方便你后续人工检查少数问题页,而不是整本都自己重敲。
🧪 使用方式(简略版)
准备环境
安装依赖(示例):
1
pip install aiohttp pymupdf pillow
在代码中配置好自己的:
API_BASE_URLAPI_KEYMODEL_NAME
运行脚本
直接执行脚本:
1
python 课件PDF转Markdown.py
弹出 Tk 界面:
- 先选择包含 PDF 的输入文件夹
- 再选择输出 Markdown 的目标文件夹
查看结果
- 每个 PDF 会对应一个
.md文件 - 可直接导入 Obsidian / Hexo / 任意 Markdown 编辑器
- 每个 PDF 会对应一个
出于安全考虑,文中没有展示任何真实 Key 或完整配置,实际使用时请将敏感信息放到环境变量或独立配置文件中。
🔐 关于 API Key 与隐私安全
在实际项目中,有几点安全建议:
- 不要把 API Key 写死在代码仓库里
- 推荐使用环境变量:
os.getenv("AI_API_KEY") - 或使用
.env/ 独立配置文件(不提交到 Git)
- 推荐使用环境变量:
- 不要在博客/截图中展示完整请求地址和 Key
- 如果是批量处理学术课件:
- 请确认内容不涉及隐私/敏感数据
- 如有必要,可在本地或内网环境部署自托管模型
🎯 总结:让 AI 帮你做“搬运工”,自己做“思考者”
这个小工具本质上做了三件事:
- 把视觉问题(PDF 课件)转化为文本问题(Markdown 笔记)
- 把机械重复的整理工作交给 AI
- 把你的时间从格式处理中解放出来,留给真正的理解与思考
对于学生、老师、内容创作者来说,这是一种非常实用的 AI 应用形态:
不是炫酷的 Demo,而是每天都能用、用完就明显省时间的“小工具”。
如果你也有大量 PDF 课件、题库、讲义想要结构化,不妨试着把这个思路迁移到自己的场景里,让 AI 帮你打基础,你只负责在优质的 Markdown 笔记上“再加工”。