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約 2,000 文字単位に分割して YAML インデックスを作成
  3. 03既存の Markdown ファイルを直接インデックス化
  4. 04相対パスを使い、既存のインデックス文書を保持
  5. 05再開可能な処理とキャッシュ事前生成スクリプト

活用シーン

  1. 01ローカルの論文 PDF 集合にセマンティック検索インデックスを作成
  2. 02Markdown メモを検索可能な文書コレクションに整理
  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.shasta pdf-extraction remote を使って PDF を Markdown に変換します
assets/chunk-and-index.pyMarkdown ファイルをチャンクに分割し、YAML インデックスに直接書き込みます
assets/warm-cache.sh検索キャッシュを構築するため、最初の検索を実行します

このスキルファイルを基準にアセットディレクトリを探してください。スクリプトは自己完結型で、作業ディレクトリにコピーしても、そのまま実行してもかまいません。

手順

ステップ 0:ユーザーにパスとコレクション名を確認します

開始前に、ユーザーに次の 4 点を尋ねます。

  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 ファイルへの相対パスが保存されるため、この構成が重要です。すべてを 1 つのルートディレクトリの下に置くと、インデックスを移植しやすく、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
抽出時間PDF 10 ページあたり約 2~5 分(リモート API)。20 件を超えるバッチでは olmocr の方が高速です
チャンク分割+インデックス作成PDF 1 件あたり約 1~2 秒
インデックスのストレージ容量抽出したテキストの約 2~3 倍(Markdown ファイル+チャンクテキストを含む YAML)
キャッシュのウォームアップ5~30 秒(インデックス作成後に 1 回実行)
合計所要時間の見積もり抽出が大部分を占めます。概算で N_papers × 3 分です

特に大規模なコレクション(PDF が 20 件を超える場合)は、開始前にユーザーに確認します。

ステップ 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 ページ単位で抽出します。
  • 進捗と件数を報告します。

**大規模なバッチ(PDF が 20 件を超える場合)**では、--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。また、--pdf-dir が指定され、一致する PDF が見つかった場合に限り、source_pdf(元の PDF を指す相対パスまたは file:// ポインター)
    • チャンクごとのメタデータ: 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 を指し、2 つ目のタグは 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 あたり備考
抽出(リモート)10 ページあたり 2~5 分API に依存。1 回の呼び出しにつき最大 50 ページ
抽出(olmocr)1 ページあたり 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 ディレクトリはインデックスファイルと同じディレクトリ内にある必要があります。

コメント