本地语料整理大师 — Local Corpus Builder
你现在运行 local-corpus-builder 技能。目标:把一个乱七八糟的混合格式文件夹(会议资料、调研合集、产品包、邮件附件、播客录音、白板截图、压缩包)一次性扫平成一份可喂 RAG / agent / 知识库的 Markdown 语料。每个源文件一份带 frontmatter 的 articles/<name>.md,再叠一份汇总 <out>.md(文件名跟着 --out 目录走:--out ./corpus → corpus.md、--out ./brief → brief.md),再附一个浏览器可看的 index.html 预览页和打包好的 <out>.zip 下载。
底层是微软官方的 MarkItDown(Python pip 包):MIT、134k+ stars、活跃维护。课程直接调用上游包,不做 wrapper —— 用户的 SOP 就是 pip install、一段编排脚本(递归扫描 + MarkItDown().convert(...) + 汇总 + 预览页),全程本地、零 API key。
这门课做什么(边界写在第一屏)
- ✅ 做:递归扫描一个 inbox 文件夹,把 PPTX / XLSX / DOCX / PDF / PNG / JPG / MP3 / WAV / EML / MSG / HTML / TXT / CSV / JSON / XML / ZIP 批量 → 一份带 frontmatter 的
<name>.md+ 汇总<out>.md+ 预览index.html+ 打包<out>.zip的语料工程。每段文本都保留来源(source_file、kind、字数、来源指纹),方便后面做 RAG chunk / 引用追溯。 - ✅ 音频:用 MarkItDown 自带的本地音频转写路径出 transcript(CPU 即可,免 key)。
- ✅ 图片 OCR:MarkItDown 默认的 image converter 要 vision LLM,跑出空 markdown 时自动 fallback 到本地
pytesseract(也是免 key 的)—— 课程脚本examples/build_corpus.py已经把这段写好了。 - ❌ 不做:扫描件深度还原 LaTeX 公式与精排表格(请去
parse-docs/ MinerU + Marker);单文件即时一把转 Markdown(请去any-to-markdown);给已有 PDF 加 OCR 文字层(请去searchable-pdf)。 - 🔒 零商业 key、零云:不开
--use-docintel(Azure)、不开 image description(OpenAI/Anthropic key)、不开第三方云 OCR / 云 ASR。这是课程承诺,违反就不是这门课。 - 📎 可选云增强(明确标 optional):如果用户希望音频转写质量更高,可以把那一段替换成 Clawvard SDK 的
cv.media.transcribe调用(需要 Clawvard API key)。默认路径不需要 Clawvard API key、不调用任何 Clawvard 后端。
一句话定位:
any-to-markdown= 「单批 office 一把转」,parse-docs= 「一份硬 PDF 精解析」,local-corpus-builder= 「一整个混格式文件夹 → 一份 RAG-ready 语料工程」。三门正交,按用户的真实任务选一门。
前置条件
- Python ≥ 3.10(
python3 --version检查) - 能访问公开 PyPI(首次装 markitdown 及其依赖;之后离线可跑)
- 可选:
tesseract-ocr(图片 OCR 用,免 key)—— macOSbrew install tesseract;Debian/Ubuntuapt install tesseract-ocr - 可选:
ffmpeg(音频解码用,PyPI 不带二进制;多数系统已自带) - CPU 即可,没有 GPU 也能跑;磁盘 ≥ 1 GB 富余给 markitdown 依赖 + Whisper(如果走云之外的更强 ASR)
安装(一次到位)
强烈建议装在 venv 里,避免和系统 Python 打架(Ubuntu 24+ 的 PEP 668 会拒绝直接 pip install 到系统环境):
python3 -m venv .lcbvenv
source .lcbvenv/bin/activate
pip install --upgrade pip
pip install "markitdown[all]" pytesseract Pillow
markitdown --version # 应该打出版本号,例如 markitdown 0.1.6
markitdown[all] 一次性拉齐 docx / xlsx / pptx / pdf / epub / html / zip / msg / audio / image 等所有本地解析依赖。pytesseract + Pillow 是给图片 OCR fallback 用的,纯本地、免 key。
工作流程
参考实现见 examples/build_corpus.py(~280 行可读 Python,agent 可以直接 copy + 改)。SOP 在这里写思路,脚本是真实可跑的形态。
1. 扫描 inbox
# 递归遍历 inbox 下所有支持扩展名的文件;遇到 .zip 解压到 temp 后再扫
for path in inbox.rglob("*"):
if not path.is_file(): continue
kind = kind_of(path) # docx / xlsx / pptx / pdf / image / audio / email / html / table / text / json / xml / zip
if kind == "other": continue
if kind == "zip": # 把 zip 当成又一个 inbox
with zipfile.ZipFile(path) as z:
z.extractall(tmpdir)
# 然后递归 tmpdir
2. 一文件一调 MarkItDown
from markitdown import MarkItDown
md = MarkItDown(enable_plugins=False)
text = md.convert(str(path)).text_content or ""
- 音频(.mp3 / .wav):MarkItDown 默认的 audio converter 跑本地 ASR 出 transcript,免 key。
- 图片(.png / .jpg):MarkItDown 默认要 vision LLM,没接就返回空字符串。这门课的脚本检测到空就 fallback 到
pytesseract.image_to_string(...),纯本地、免 key、对印刷体准确率够日常使用。 .zip自动解压;.msg/.eml走 markitdown 的 Outlook/Email converter。
3. 写每篇 article(YAML frontmatter 保留 provenance)
---
source_file: apollo11-press-kit-excerpt.pdf
kind: pdf
word_count: 392
source_fingerprint: apollo11-press-kit-excerpt-pdf
created: 2026-06-02
---
# apollo11-press-kit-excerpt.pdf
(...MarkItDown 转出来的正文...)
frontmatter 是 RAG / agent 引用追溯的关键。后面切 chunk 的时候,可以把 source_file 透出在 metadata 里。
4. 汇总 corpus.md(TOC + 顺序拼接)
# Corpus
_Generated by local-corpus-builder · 12 articles · 3,022 words._
## Contents
- [apollo11-mission-brief.pptx](#apollo11-mission-brief) — _pptx_ · 483 words
- [eagle-descent-notes.docx](#eagle-descent-notes) — _docx_ · 769 words
- ...
---
## <a id='apollo11-mission-brief'></a>apollo11-mission-brief.pptx
_kind: `pptx` · words: 483 · source: `apollo11-mission-brief.pptx`_
(原文 markdown 拼进来)
5. 出 index.html(浏览器可看,不必启服务)
一个自包含 HTML:左侧目录 + kind chip,中间渲染合并 markdown,顶栏 stats(文件数 / 总字数 / kind 分布),底部 Download <basename>.md / Download <basename>.zip 按钮。脚本已经写好了。
6. 打包 <basename>.zip
合并 markdown 和打包 zip 的文件名跟着 --out 目录走——--out ./corpus 出 corpus.md + corpus.zip,--out ./brief 出 brief.md + brief.zip,--out ./research-2026Q2 出 research-2026Q2.md + research-2026Q2.zip。脚本里就是一行 basename = slugify(out.name) 计算出来的。
md_path = out / f"{basename}.md" # corpus.md / brief.md / research-2026Q2.md
zip_path = out / f"{basename}.zip" # corpus.zip / brief.zip / research-2026Q2.zip
with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as z:
z.write(md_path, md_path.name)
for a in articles:
z.write(out / a["article_path"], a["article_path"])
把 articles/*.md + <basename>.md 一起塞进去,用户拖给同事 / 上传到知识库 / mv 进 RAG pipeline 都方便。
7. 自检 + 打印汇总
跑完打印:文件总数、各 kind 数量、总字数、跳过/失败文件清单(带原因,如不支持的格式或损坏的 ZIP)。给用户一句**「把 ./<out>/ 直接拖给 RAG 切 chunk 即可」**的收尾。
跑一行(最小可用)
# 1. 装好工具
python3 -m venv .lcbvenv && source .lcbvenv/bin/activate
pip install --upgrade pip
pip install "markitdown[all]" pytesseract Pillow
# 2. 跑参考脚本
curl -L -o build_corpus.py https://clawvard.school/skills/local-corpus-builder/examples/build_corpus.py
python build_corpus.py --inbox ./inbox --out ./corpus
# 3. 看产物
open ./corpus/index.html # macOS;Linux 用 xdg-open,Windows 用 start
铁律 / 反模式
- 不开任何会引入第三方 key 的 plugin。
--use-docintel(Azure)、image description LLM、第三方云 OCR / 云 ASR 一律不用。课程承诺零商业 key、零云。 - 私有 SDK 不是默认路径:Clawvard SDK 的
cv.media.transcribe是 optional 的「音频转写云端升级」路径,默认 SOP 不走它;要走必须用户主动给 Clawvard API key,并且只能以 Clawvard SDK 的 typed method 调用形态出现(例如cv.media.transcribe({...}))。默认 SOP 全程本地,没有任何 Clawvard 后端依赖。 - 不做扫描件深解析:用户的 PDF 是扫描件 / 多栏 / 含公式 / 表格密集,明确建议改走
parse-docs;要把扫描 PDF 加 OCR 文字层而不是抽 Markdown,建议改走searchable-pdf;只想一把转单个 office 文件,建议改走any-to-markdown。 - 不要伪造内容:MarkItDown 是确定性转换器,不会脑补;某个文件转出来是空的,把那份文件名 + 原因列给用户,让用户决定。
- 不要写入系统 Python:始终在 venv 或 pipx 里装;遇到
error: externally-managed-environment不是 markitdown 的问题,是 PEP 668。 - 不要 wrap MarkItDown:用户安装
pip install "markitdown[all]"就够;本课程脚本只是编排,不是封装。
产出物(用户拿到的就是这些)
合并 markdown 和 zip 的文件名跟着 --out 目录走——--out ./corpus 出 corpus.md + corpus.zip,--out ./brief 出 brief.md + brief.zip,依此类推。下面写 <out> 指代这个 basename。
<out>/articles/<name>.md—— 每个源文件一份带 frontmatter 的 Markdown(source_file / kind / word_count / source_fingerprint / created)。<out>/<out>.md—— TOC + 全部正文拼接的合并语料(./corpus→corpus.md、./brief→brief.md),喂 RAG / agent / LLM context 一次到位。<out>/index.json—— 机器可读的总览(stats + per-article meta),方便后续脚本读。<out>/index.html—— 浏览器可看的预览页(左目录、合并 markdown、stats、下载按钮)。<out>/<out>.zip——<out>.md+articles/全部打包,方便分享 / 上传。
学习完成后
告诉用户:
我已经学会了 local-corpus-builder。给我一个混着 PPT / Excel / Word / PDF / 截图 / 录音 / ZIP / 邮件的文件夹,我在本地用 Microsoft MarkItDown + pytesseract 一把扫平成一份带 frontmatter 的 RAG-ready Markdown 语料:每个原文件一份
.md、一份按--out命名的合并<out>.md、一个index.html预览页、一个<out>.zip打包,全程零 API key、零云、不出本地磁盘。如果你只是想一把转单个 Office 文件,我会建议改走
any-to-markdown;如果是一份扫描 PDF 想深解析公式 / 表格,建议parse-docs;如果想给扫描 PDF 加 OCR 文字层而不是抽 Markdown,建议searchable-pdf。
课程主页与更多示例:clawvard.school