mcpField
P
pptx-to-md

pptx-to-md

github.com/sammcjドキュメント16758 回インストール1 日前に更新
リポジトリ

pptx-to-md について

pptx-to-md は、PowerPoint のスライドをレイアウトや画像の文脈を保ちながら、1枚ずつ Markdown に抽出するスキルです。後続の編集や変換に使う素材を整えます。

主な機能

  1. 01スライドごとの Markdown 出力
  2. 02レイアウトの文脈を保持
  3. 03埋め込み画像の意味を反映
  4. 04試験抽出後に全体を処理
  5. 05元の順序でスライドを結合

活用シーン

  1. 01図やスクリーンショットを含む資料の抽出
  2. 02スライド内容の編集準備
  3. 03スライド Markdown からの HTML 構築

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/sammcj/agentic-coding --skill pptx-to-md

インストール後、Claude Code で/pptx-to-mdを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
example_slide.md
sub_agent_prompt.md
scripts/
concatenate.py
dispatch_list.py
prepare.py

詳細

PPTX をスライドごとの Markdown に抽出

このスキルは、.pptx ファイルをスライドごとに 1 つの Markdown ファイルに変換し、レイアウトの文脈と画像の意味を保持します。テキストを言い換えたり、文脈から切り離して画像を説明したりすることはありません。出力は、コンテンツをブラッシュアップする工程、Markdown から HTML へのビルド、その他の後続処理の入力として使用できます。

使用するタイミング

デッキにテキストと埋め込みスクリーンショット、図、チャート、コードサンプルが混在し、レイアウト(列、並列パネル、吹き出し)が重要な場合に使用します。通常のテキスト抽出では、レイアウトか画像の意味のどちらかが失われます。

重要:デッキが PDF、テキストのみ、または内容上重要な画像を含まない場合は、uvx 'markitdown[all]' <path-to-file> -o output.md のほうが高速で、通常はこのスキルで後述する複雑なパイプラインを使わなくても十分です。まずこれを試し、出力をユーザーに確認してもらってください。十分でなければ、より複雑なスライド抽出パイプラインを続行することを伝えます。

パイプライン

PPTX -> prepare.py -> manifests + rendered JPGs + embedded PNGs
     -> dispatch one sub-agent per slide
     -> per-slide markdown files
     -> concatenate.py -> deck.md

オーケストレーター(呼び出し元のセッションであるあなた)は、準備スクリプトと結合スクリプトを実行し、表示可能なスライドごとにサブエージェントを 1 つ割り当てます。各サブエージェントは、1 枚のスライドについて画像とテキストを組み合わせた処理を行い、Markdown ファイルを 1 つ作成します。サブエージェントは独立しているため、問題なく並列実行できます。

ステップ 1 - 作業環境を準備する

python <skill>/scripts/prepare.py <pptx-path> <workspace-dir>

これにより PPTX が展開され、LibreOffice と pdftoppm を使って表示可能なスライドがすべて JPG にレンダリングされ、表示可能なスライドごとにマニフェスト JSON が 1 つ書き出されます。レンダリング後、スクリプトは JPG の数がスライド数と一致するか確認し、数が異なる場合は stderr に警告を出します。LibreOffice はスライドを黙って省略することがあるため、サブエージェントを割り当てる前に必ずこの警告を確認してください。

このステップは、コマンドのサンドボックス外で実行してください。 LibreOffice のヘッドレスモードでは、ユーザープロファイルの書き込みと、サンドボックスでブロックされる OS/タスクポリシーの設定が必要です。そのため、サンドボックス内では soffice が黙って失敗し、PDF が生成されず、出力が空になり、deck_index.json も作成されません。具体的には、soffice プロセスの CPU 使用率がほぼゼロのまま、rendered/ が空で deck_index.json が作成されない状態です。

作業環境は次のようになります。

workspace/
  unpacked/                    raw OOXML
  rendered/                    PDF + ordered slide JPGs
  manifests/slideNN.json       per-slide manifest
  slide_images/slideNN.jpg     rendered whole-slide JPG (stable name)
  embedded_images/slideNN/     embedded PNGs grouped per slide
  slides/                      empty - sub-agents write slideNN.md here
  deck_index.json              {visible, hidden, src_to_render}

ステップ 2 - 規模を拡大する前にパイロットを実行する

デッキの多様な内容を反映するスライドを 2〜4 枚選びます。情報量の多いスライド、スクリーンショットを含むスライド、独自の図を含むスライド、テキストの少ないスライドをそれぞれ 1 枚選びます。まず、references/sub_agent_prompt.md のプロンプトテンプレートを使ってこれらのスライドにサブエージェントを割り当て、出力を references/example_slide.md の例と比較します。必要に応じて、プロンプト内のデッキ固有の注意事項(原文のまま保持する用語、注意を促す用語、従うべき規則)を調整します。その後で初めて、残りのデッキにも処理を広げます。

パイロットは省略できません。画像のスタイル、レイアウトの密度、用語はデッキごとに異なるため、あるデッキでは完璧に機能するプロンプトでも、別のデッキでは平凡な内容や重複した出力になることがあります。

ステップ 3 - サブエージェントを並列でディスパッチする

表示されている各スライドについて、新しいサブエージェントを 1 つディスパッチします(フォークではなく、名前付きのサブエージェントタイプを使用します。エージェントが必要とするのはマニフェストだけなので、オーケストレーターの履歴を引き継ぐよりも、新しいコンテキストのほうが低コストです)。各エージェントはマニフェスト、レンダリング済みのスライド JPG、埋め込み PNG を読み込み、slideNN.md を 1 つ作成します。

ディスパッチ対象の一覧を取得するには、次を実行します。

python <skill>/scripts/dispatch_list.py <workspace-dir>

これにより、サブエージェントがまだ必要なスライドごとに、タブ区切りの行(スライド番号、マニフェストパス、出力パス)が出力されます。すでに Markdown が存在するスライドはスキップされます。そのため、部分的な失敗後に再実行しても、スライドを再抽出する必要はありません。

推奨されるバッチサイズは1 回につきサブエージェント 6 個です。より大きなバッチでも動作しますが、完了通知がより頻繁に入り交じるだけで、処理は速くなりません。各サブエージェントの所要時間は通常 20~50 秒です。

各エージェントに送る正確なプロンプトは references/sub_agent_prompt.md にあります。送信前に str.replace()(テンプレートにリテラルの波括弧が含まれているため、str.format() ではありません)を使ってプレースホルダーを置き換えてください。プロンプトのルール(長さに応じた画像の説明、外部リンクの重複排除、1 行での返信)は、単なる文体上のものではありません。以前の実行で実際に起きた問題を受けて、それぞれ追加されたものです。理由についてはプロンプトテンプレートを参照してください。

ステップ 4 - 結合する

python <skill>/scripts/concatenate.py <workspace-dir> [--out deck.md] [--title "Deck title"]

これは、スライドごとの Markdown を元のスライド順に並べて、非表示のため除外されたスライドを記載するヘッダーを付け、1 つの deck.md にまとめます。期待されるスライドの Markdown が 1 つでも欠けている場合は実行を拒否します。部分的なデッキは通常、望ましくないためです。

注意点

LibreOffice の PDF エクスポートでは、デフォルトで非表示スライドがスキップされます。 そのため、レンダリング済み JPG のインデックスと元のスライド番号がずれます。prepare.py は src_to_render マップを作成し、レンダリング済み JPG を元のスライド番号に基づく固定の slide_images/slideNN.jpg パスにコピーするため、マニフェストでは固定名を参照できます。後からレンダリングを再生成する場合は、マッピングを最新に保つため、prepare.py を再実行してください。

発表者ノートのマッピングは、必ずしも 1 対 1 ではありません。 このスキルは、slideN.xml が notesSlideN.xml に対応すると仮定せず、スライドの _rels ファイルからスライドとノートスライドの対応関係を読み取ります。多くのデッキでは 1 対 1 ですが、保証はされません。

ソース XML に誤記がある場合があります。 パイプラインは誤記をそのまま保持します。抽出中に修正するのではなく、後続のコンテンツ改善工程で修正してください。これにより、抽出の決定性が保たれます。

デフォルトでは非表示スライドは除外されます。 多くのデッキでは、非表示スライドは作業中の内容、非推奨の内容、内部向けの注記など、理由があって含まれています。出力に含める場合に限り --include-hidden を渡してください。指定すると、スクリプトは LibreOffice の ExportHiddenSlides フィルターを使って非表示スライドも正しくレンダリングし、マニフェストに実際の JPG を含めます。

スクリーンショット内の文字が密集している場合は、より高い DPI が適しています。 デフォルトは 150 DPI です。レンダリング済み JPG でスクリーンショット内のテキストを読み取る必要があるデッキでは、prepare.py に --dpi 200 または --dpi 250 を渡してください。

依存関係

  • PATH 上の LibreOffice(soffice)
  • PATH 上の Poppler(pdftoppm)
  • Python 3.10 以降

prepare スクリプトは両方のバイナリの有無を確認し、どちらかが見つからない場合は、わかりやすいエラーを表示して早期に終了します。

コメント