PDF 知识卡片生成器
Overview
将一个 PDF 素材转化为一套可溯源的知识卡片系统:从原文中提炼方法、框架、概念与行动规则,每张卡片都带原文出处(页码 + 引用的原文片段),并内联展示定位页的真实文字。最终一键产出四种可用形态,覆盖"读—学—记—复用"全流程。
本技能刻意保持轻量:不强制重型审计门禁,但始终坚持逐条可溯源、引用不虚构这一硬约束(每张卡片的 quote 必须是对应来源原文的真实子串)。
When To Use
- 用户发来一个 PDF 并要求生成知识卡片 / 学习卡片 / 知识库 / 学习资料。
- 用户希望把教材、练习册、讲义、报告等拆成结构化、可记忆的卡片。
- 用户需要某份材料的"离线可看总览页 + 可复用数据 + 笔记 + 记忆卡片"。
不适用:用户只想要简单提取 PDF 文字(直接用 pdfminer 即可);或需要 learn-from-materials 的 complete systematic 全套审计门禁(那请用该技能)。
Workflow
Step 0 — 准备环境(换机器时先做一次)
python scripts/setup_env.py # 建隔离 venv 并装 pdfminer.six + pymupdf
之后所有脚本都用该 venv 的解释器运行(如 .venv/Scripts/python.exe)。不要往系统 Python 里装依赖。
Step 1 — 体检 PDF 文字层(先判断,再动手)
python scripts/render_pages.py "<PDF路径>" --check
输出 verdict 三选一:
| verdict | 含义 | 走哪条路 |
|---|---|---|
text_layer_ok |
文字层正常 | 直接进 Step 2 |
partially_weak |
少数页文字层偏薄 | 进 Step 2,并把那些页另外渲染核对 |
vector_outlined |
正文被转成矢量曲线,机器提不出字 | 走下面的「矢量曲线分支」 |
Step 2 — 提取 PDF 文字与来源映射
python scripts/extract_pdf.py "<PDF路径>" --out "<工作目录>"
- 脚本依赖
pdfminer.six;若报 ImportError,先在隔离 venv 安装固定版本并向用户说明后再跑(不要污染系统 Python):
bash python -m venv .venv && .venv/Scripts/python.exe -m pip install pdfminer.six==20260107 .venv/Scripts/python.exe scripts/extract_pdf.py "<PDF路径>" --out "<工作目录>" - 产出:
full_text.txt(带<!-- PDF 页 N -->标记)与source_map.json(每页一块,含pdf_page / start_char / end_char / content_sha256)。两者供 Step 4 做引用校验。 - 若提取出的每页字符数明显异常(平均 < 40 字),脚本会打印警告——不要拿残句建卡,请改走矢量曲线分支。
Step 2' — 矢量曲线分支(PDF 文字提不出来时)
当 verdict = vector_outlined(常见于微信/Word/网页"打印成 PDF"):
- 渲染成图:
bash python scripts/render_pages.py "<PDF路径>" --out "<工作目录>/pages"
得到每页 200 DPI 的 PNG 与page_manifest.json。 - 逐页视觉转录:用看图能力逐页读,把内容写成带页标记的转录母本(每页以
<!-- PDF 页 N -->开头,后接该页正文),存为<工作目录>/transcribed.txt。
- 转录要逐字,不要顺手改错别字;原文有错也照录。 - 放大复核可疑字(叠词、拟声词、专有搭配最易读错):
bash python scripts/render_pages.py "<PDF路径>" --out "<工作目录>/pages" --clip 4 700 880
裁出该区域放大后重新读一遍再定稿。 - 用转录本重建来源映射(产物与正常模式完全一致):
bash python scripts/extract_pdf.py "<PDF路径>" --out "<工作目录>" --transcript "<工作目录>/transcribed.txt" - 后续步骤不变——卡片引用的母本就是转录本,quote 仍然是它的逐字子串。
> 关键点:转录本先落盘再建卡。这样每条引用都能回溯到"第几页的哪一段",且机器可校验。
Step 3 — 通读并识别结构
读取 full_text.txt(矢量曲线分支则读 transcribed.txt),识别材料的层级结构:单元 / 章节 / 课文 / 小节。确定:
- 共有几个顶层单元(用于 units);
- 每篇/每节反复出现的"训练目标""提示""范本"等栏目标签(用于定位原文);
- 哪些内容适合提炼成方法卡 / 框架卡 / 概念卡 / 行动规则卡。
不要逐页罗列,按"写作/认知方法类型"归并(例如 27 篇课文可归为 8 张方法框架卡),控制卡片总量,保证页面可读。
Step 4 — 生成可溯源知识卡片 JSON
按 references/schema.md 的字段规范,写出一个知识库 JSON(建议命名为 <材料名>.knowledge.json)。要点:
- 每条
source存该定位的原文段落(text,用于内联展示),以及locator(如文件名 · 标题路径:第一单元 ¦ 自然与校园场景 · PDF第3–8页)。 - 每张
card的quote必须是其source_refs中某个source.text的真实子串——不允许改写、概括或编造。 card.quote取该段最核心的一句;source.text放完整段落,二者天然构成"精准引用 + 定位页原文"。- 如有题库需求,在
assessment写问答对(含basis指向来源)。 - 强烈建议用脚本建卡而不是手写 JSON:写一个构建脚本,按锚点行从原文母本里精确截取
source.text,再断言每条quote是其子串,断言通过才落盘。这样能从根本上杜绝"引用写错字"。
Step 5 — 渲染四种形态
运行渲染脚本,读入 Step 4 的 JSON,自动校验溯源并产出四种文件:
python scripts/render_cards.py "<知识库JSON>" --out "<输出目录>" --name "<材料名>"
产出(均在 --out 下):
- <材料名>.html — 离线交互总览页:单元导航 + 方法卡列表,每张卡内联「📖 定位页原文」折叠块与出处标记,含题库。
- <材料名>.knowledge.json — 可溯源 JSON 知识库(结构化,便于二次加工)。
- <材料名>.md — Markdown 笔记(纯文本,便于贴进 Obsidian / 笔记软件)。
- <材料名>.anki.txt — Anki 可导入卡片(问答,Tab 分隔;优先用 assessment,否则由卡片自动生成)。
脚本会强制校验:每张卡的 quote 必须为其来源 text 的子串,否则报错并列出问题卡片,要求修正后才生成。这保证了"引用不虚构"的硬约束。
Step 6 — 校验与交付
- 确认四种形态均已生成,HTML 能在浏览器离线打开。
- 建议再对 HTML 做一次内容抽检(关键引文是否出现、题库是否在位)。
- 用
present_files打开 HTML 总览页供用户预览。 - 告知用户四种文件的位置与用途。
溯源硬约束(不可妥协)
- quote 必须是真实子串:每张卡片引用的原文片段,必须逐字出现在对应
source.text中,且来源页码真实。 - 不虚构:没有原文支撑的结论、方法、数据一律不写;宁可少一张卡,不能编一条引用。
- 定位精确:
locator必须含具体标题路径与 PDF 页码区间,机器可核对。
Scripts
scripts/setup_env.py— 一键建隔离 venv 并装固定版本依赖(换电脑第一步)。scripts/extract_pdf.py <PDF> --out <dir> [--transcript <文件>]— 提取逐页文字 + 来源映射;--transcript用于矢量曲线 PDF。scripts/render_pages.py <PDF> --check | --out <dir> [--clip 页 y0 y1]— 文字层体检 + 页面渲染 + 局部放大复核。scripts/render_cards.py <JSON> --out <dir> --name <材料名>— 校验溯源并渲染四种形态。
References
references/schema.md— 知识库 JSON 完整字段规范与示例。references/workflow.md— 详细工作流、栏目识别技巧、矢量曲线处理与实战经验。README.md— 面向人的简介与安装/使用说明(可单独发给同事)。