mcpField
L
local-paper-index

local-paper-index

github.com/allenai文档处理4262 次安装2 天前更新
代码仓库

关于 local-paper-index

用于将本地 PDF 或 Markdown 文档构建为可搜索 Asta 文档索引的技能,面向整理和检索文档集合的用户。它提供提取、分块、写入 YAML 索引及预热搜索缓存的脚本,并支持断点续跑与相对路径。

主要功能

  1. 01将 PDF 转换为 Markdown,可选择提取图片
  2. 02按约 2000 字符分块并写入 YAML 索引
  3. 03支持直接索引现有 Markdown 文件
  4. 04使用相对路径并保留已有索引文档
  5. 05提供可恢复的处理流程和缓存预热脚本

适用场景

  1. 01为本地论文 PDF 集合建立语义搜索索引
  2. 02将 Markdown 笔记整理为可检索文档集合
  3. 03中断后继续 PDF 提取与索引任务
  4. 04按集合标签或来源 PDF 搜索索引内容

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/allenai/asta-plugins --skill local-paper-index

安装后在 Claude Code 中输入/local-paper-index确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

assets/
chunk-and-index.py
extract-pdfs.sh
warm-cache.sh

详细介绍

本地 PDF 索引构建器

从一组本地 PDF 文件构建可搜索的 Asta 文档索引。每个 PDF 都会转换为 Markdown,拆分为约 2000 个字符的文本块,并作为文档写入 asta-documents YAML 索引,从而支持对整个文档集的全文语义搜索。

资源

此技能在 assets/ 目录中包含独立脚本:

脚本用途
assets/extract-pdfs.sh通过 asta pdf-extraction remote 将 PDF 转换为 Markdown
assets/chunk-and-index.py拆分 Markdown 文件并直接写入 YAML 索引
assets/warm-cache.sh执行初次搜索以构建搜索缓存

根据此技能文件的位置查找资源目录。这些脚本是独立的,可以复制到工作目录中,也可以直接在原位置运行。

流程

步骤 0:询问用户的路径和文档集名称

开始之前,向用户询问以下四项:

  1. PDF 目录 — PDF 文件位于何处?
  2. Markdown 输出目录 — 提取出的 Markdown 应保存到何处?
  3. 文档集名称 — 为文档集取一个简短标签(例如 my-papers、cs-reading-list)。
  4. 是否包含图片? — 是否提取并保存 PDF 中嵌入的图片,并与 Markdown 放在一起。图片对包含图表/示意图的论文很有用,但会占用更多存储空间。默认:否。

建议采用以下目录布局:PDF 和 Markdown 位于同一父目录下的相邻目录中,索引文件与它们放在一起。例如,如果 PDF 位于 /data/papers/pdfs/:

/data/papers/                          # DATASET_ROOT — parent of everything
├── pdfs/                              # PDF_DIR (user already has this)
├── markdown/                          # MARKDOWN_DIR (suggested: sibling of pdfs/)
│   ├── paper1.md                      # without --images: flat .md files
│   ├── paper2.md
│   ├── paper3/                        # with --images: per-PDF subdirectories
│   │   ├── paper3.md
│   │   └── img-0.jpeg
│   └── ...
└── index.yaml                         # INDEX_PATH (auto-created here)

此布局很重要,因为索引会存储 Markdown 文件的相对路径。将所有内容放在同一个根目录下可使索引便于移植,也便于使用 Git 管理。

建议时的关键规则:

  • Markdown 目录应与 PDF 目录相邻,而不是位于 .asta 内。
  • DATASET_ROOT 是同时包含 PDF_DIR 和 MARKDOWN_DIR 的父目录。
  • 索引位于 DATASET_ROOT/index.yaml。
  • 如果用户的 PDF 位于 /home/user/research/pdfs,建议使用 /home/user/research/markdown 和 /home/user/research/index.yaml。

用户确认(或提供自己的路径)后,设置以下变量:

PDF_DIR="/data/papers/pdfs"                               # user-provided
MARKDOWN_DIR="/data/papers/markdown"                       # user-confirmed
DATASET_ROOT="/data/papers"                                # parent of both
INDEX_PATH="$DATASET_ROOT/index.yaml"                      # derived
COLLECTION="my-papers"                                     # user-chosen
IMAGES=false                                                # true if user wants images
步骤 1:查找 PDF 并展示估算结果
PDF_COUNT=$(find "$PDF_DIR" -name "*.pdf" -type f | wc -l)
TOTAL_SIZE=$(find "$PDF_DIR" -name "*.pdf" -type f -exec du -ch {} + | tail -1 | awk '{print $1}')
echo "Found $PDF_COUNT PDFs ($TOTAL_SIZE total)"

继续操作前,向用户展示以下估算结果:

指标估算
找到的 PDFN 个文件
磁盘上的总大小X MB
提取时间每份 10 页 PDF 约需 2-5 分钟(远程 API);对于超过 20 份的批次,使用 olmocr 会更快
拆分与索引每份 PDF 约需 1-2 秒
索引存储空间提取文本大小的约 2-3 倍(Markdown 文件 + 含文本块内容的 YAML)
缓存预热5-30 秒(索引完成后只需执行一次)
预计总时间主要取决于提取:约为 N_papers x 3 分钟

开始前请征求用户确认,尤其是文档集较大时(超过 20 份 PDF)。

步骤 2:将 PDF 提取为 Markdown
# Without images (flat layout: markdown/paper.md)
bash /path/to/assets/extract-pdfs.sh "$PDF_DIR" "$MARKDOWN_DIR"

# With images (per-PDF subdirectories: markdown/paper/paper.md + images)
bash /path/to/assets/extract-pdfs.sh --images "$PDF_DIR" "$MARKDOWN_DIR"

只有在用户于步骤 0 选择包含图片时,才传入 --images。使用 --images 时,每个 PDF 都会在 MARKDOWN_DIR 下拥有自己的子目录,以避免不同 PDF 的图片文件名冲突。步骤 3 中的拆分脚本会自动处理这两种目录布局。

此脚本会:

  • 跳过已存在 Markdown 文件的 PDF(可恢复运行)
  • 将大型 PDF(超过 50 页)按每 50 页为一段进行提取
  • 显示进度和数量

对于大型批次(超过 20 份 PDF),使用带有 --workers 的 asta pdf-extraction olmocr 会快得多。详情请参阅 pdf-extraction 技能。

步骤 3:分块并构建索引
uv run --with pyyaml python3 /path/to/assets/chunk-and-index.py "$COLLECTION" "$MARKDOWN_DIR" --index-path "$INDEX_PATH" --pdf-dir "$PDF_DIR"

--index-path 参数为必填项。该脚本会:

  • 根据索引文件所在目录计算路径,并在 url 字段中存储相对路径,使索引可在不同机器间移植。被索引的文档就是 Markdown 文件:其 url 指向 .md 文件。
  • 读取每个 Markdown 文件,在段落或句子边界处分割成约 2000 字符的块
  • 一次性将所有文档写入索引 YAML
  • 保留索引中已有的文档(追加而非覆盖)
  • 跳过此集合中已建立索引的 Markdown 文件(通过 url 判断是否可恢复;可安全地重复运行)
  • 遍历 --pdf-dir,根据基本名称(每个 PDF 的子目录名称或扁平文件名去掉扩展名后的部分)查找每个 .md 对应的上游 PDF——它会查找磁盘上实际存在的 PDF,而非假设文件名。没有匹配 PDF 的 .md 会在没有 source_pdf 的情况下建立索引,并发出警告。
  • 每个文档包含:
    • 共享元数据(位于 extra 中): collection,以及 source_pdf(指向上游 PDF 的相对路径或 file:// 路径),仅当提供了 --pdf-dir 且找到了匹配的 PDF 时才包含
    • 每个块的元数据: chunk_index、total_chunks、chunk_chars、chunk_offset、file_chars(位于 extra 中)
    • 标签: <collection-name>,以及 PDF 转换的 Markdown 对应的 pdf-index,或原始 Markdown 对应的 md-index

选项:

  • --chunk-size 2000 — 调整分块大小(默认 2000 字符)
  • --pdf-dir "$PDF_DIR" — 上游源 PDF 所在目录。索引自行编写的 Markdown 时请省略此参数(参见下文的索引原始 Markdown)。
步骤 4:预热搜索缓存
bash /path/to/assets/warm-cache.sh "$DATASET_ROOT"

此参数为必填项:

  • $DATASET_ROOT — 包含 index.yaml 的根目录

此步骤为必需步骤。 建立索引后,首次搜索会构建内部 BM25 和嵌入索引。如果不预热,用户的首次实际搜索会意外地变慢。

步骤 5:报告结果
asta documents --root "$DATASET_ROOT" list --tags="$COLLECTION"
asta documents --root "$DATASET_ROOT" show

告知用户:

  • 已处理的 PDF 数量和创建的块数
  • 数据集根目录:DATASET_ROOT 路径
  • 索引位置:INDEX_PATH
  • 用于筛选的集合标签:所选集合名称
  • 搜索方法:asta documents --root "$DATASET_ROOT" search --summary="query" --tags="COLLECTION"

搜索索引

构建完成后,可搜索所有已建立索引的 PDF:

# Semantic search within the collection
asta documents --root "$DATASET_ROOT" search --summary="neural network architecture" --tags="my-papers"

# With relevance scores
asta documents --root "$DATASET_ROOT" search --summary="attention mechanism" --tags="my-papers" --show-scores

# Filter by source PDF
asta documents --root "$DATASET_ROOT" search --extra=".source_pdf contains some-paper"

# List all documents in the collection
asta documents --root "$DATASET_ROOT" list --tags="my-papers"

索引原始 Markdown(无 PDF)

如果语料库已经是 Markdown(自行编写的 .md 文档、导出的笔记、调查记录、wiki),则无需提取内容——跳过步骤 1–2,直接将分块器指向 Markdown 目录。只需省略 --pdf-dir:

COLLECTION="my-notes"
MARKDOWN_DIR="/data/notes"            # a tree of .md files (rglob, nested OK)
INDEX_PATH="/data/notes/index.yaml"

uv run --with pyyaml python3 /path/to/assets/chunk-and-index.py \
  "$COLLECTION" "$MARKDOWN_DIR" --index-path "$INDEX_PATH"

bash /path/to/assets/warm-cache.sh "$(dirname "$INDEX_PATH")"
asta documents --root "$(dirname "$INDEX_PATH")" search \
  --summary="your query" --tags="$COLLECTION" --show-scores

Markdown 就是源文件:每个文档的 url 都指向 .md 文件,次级标签为 md-index,且不存在 extra.source_pdf(因为没有上游 PDF)。分块、相对路径 URL 和断点续做行为与 PDF 流程完全相同——两者唯一的区别是是否存在 extra.source_pdf。

存储空间估算

集合大小预计索引大小预计 Markdown 大小
10 个 PDF(约 10 页/个)2-5 MB1-3 MB
50 个 PDF(约 10 页/个)10-25 MB5-15 MB
100 个 PDF(约 10 页/个)20-50 MB10-30 MB

总存储空间约为提取文本的 2-3 倍(Markdown 文件 + summary 字段中包含块文本的索引 YAML)。

时间估算

阶段每个 PDF备注
提取(远程)2-5 分钟/10 页受 API 限制;每次调用最多 50 页
提取(olmocr)10-20 秒/页,并行处理更适合超过 20 个 PDF 的情况
分块与建立索引1-2 秒一次性写入 YAML,速度快
预热缓存总计 5-30 秒建立索引后执行一次

重要说明

  • 预热缓存。 首次运行 asta documents search --summary=... 会构建搜索索引。索引完成后,务必运行缓存预热脚本。
  • 分块大小的权衡。 2000 个字符可以兼顾搜索精度和上下文。分块越小,命中越精确,上下文越少;分块越大,上下文越多,但相关性会降低。
  • 可恢复运行。 提取和索引都会跳过已处理的文件。中断后可安全地重新运行。
  • 索引仅追加。 分块脚本会保留索引中的现有文档。若要从头重建,请先删除 index.yaml。
  • 需要 PyYAML。 分块脚本需要 pyyaml。如果尚未安装,请运行 pip install pyyaml 或 uv pip install pyyaml 进行安装。
  • 相对路径。 索引中存储的是相对路径(例如 markdown/paper.md),以便数据集可移植。这要求 Markdown 目录位于与索引文件相同的目录下。

评论

支持 Markdown