PDF（Canvaのスライド）からMarkdown（Marp）への変換スクリプト（生成AIを使ってスライドを作成する人向け）

### 概要

PDFファイルをMarp形式のMarkdownに変換するPythonスクリプトを作成しました。このスクリプトは、PDFからテキストを抽出し、適切なMarkdown形式に整形して保存します。

### モチベーション

生成AIを使ってスライドを作成する際の利便性を向上させるために、このスクリプトを開発しました。多くのスライドはCanvaを使って作成されており、過去のスライドの文言やチャート（図解や絵）を再利用して新しいスライドを作成したいと考えています。

### 課題

さまざまな生成AIを試しましたが、1ファイルが25MBを超えると読み込めなかったり、解析に時間がかかる割に認識率が低いという問題がありました。Canvaのスライドのレイアウトを再現することは難しく、手作業でひとつひとつ入力するのは避けたいと考え、このツールを作成しました。

### 解決策

このスクリプトを使うことで、PDFからテキストを抽出し、Marp形式のMarkdownに変換することができます。これにより、手作業での入力を減らし、効率的にスライドを作成することが可能です。

### 補足

本記事では、CanvaからMarkdownへの変換について説明していますが、逆にMarp CLIを使ってPDF出力し、そのPDFをCanvaで読み込ませることも可能です。

---

このような形でいかがでしょうか？他に修正や追加が必要な点があれば教えてくださいね。

### 最終的なコード

```python
import os
import re
import sys
import glob
from PyPDF2 import PdfReader

def extract_text_from_pdf(pdf_file):
    text = []
    with open(pdf_file, 'rb') as file:
        reader = PdfReader(file)
        for page in reader.pages:
            text.append(page.extract_text())
    return text

def clean_and_format_markdown(content):
    # 重複行の削除
    lines = content.split('\n')
    unique_lines = []
    for line in lines:
        if not unique_lines or line != unique_lines[-1]:
            unique_lines.append(line)
    content = '\n'.join(unique_lines)
    
    # 見出しの設定
    content = re.sub(r'^#\s', '## ', content, flags=re.MULTILINE)
    
    # レイアウトの改善
    content = re.sub(r'^▶', '- ', content, flags=re.MULTILINE)
    content = re.sub(r'^●', '### ', content, flags=re.MULTILINE)
    
    return content

def convert_pdf_to_marp(pdf_file):
    base_name = os.path.splitext(pdf_file)[0]
    md_file = f"{base_name}.md"

    try:
        # PDFからテキストを抽出
        extracted_text = extract_text_from_pdf(pdf_file)
        
        # Marpのフロントマター
        marp_content = "---\nmarp: true\ntheme: default\n---\n\n"
        
        # 各ページを処理
        for page_text in extracted_text:
            cleaned_text = clean_and_format_markdown(page_text)
            marp_content += cleaned_text + "\n\n---\n\n"  # ページ区切りを追加
        
        # 変更を保存
        with open(md_file, "w", encoding="utf-8") as file:
            file.write(marp_content)

        print(f"Converted {pdf_file} to {md_file}")
    except Exception as e:
        print(f"Unexpected error occurred while processing {pdf_file}: {e}")

def main():
    if len(sys.argv) > 1:
        pdf_files = sys.argv[1:]
    else:
        pdf_files = glob.glob("*.pdf")
    
    if not pdf_files:
        print("No PDF files found or specified.")
        return

    for file in pdf_files:
        if os.path.isfile(file) and file.lower().endswith('.pdf'):
            convert_pdf_to_marp(file)
        else:
            print(f"Skipping {file}: Not a valid PDF file.")

if __name__ == "__main__":
    main()
```

### 使用手順

1. 必要なライブラリのインストール:
   ```bash
   pip install PyPDF2
   ```

2. スクリプトを適当な名前（例：`pdf_to_marp.py`）で保存します。

3. コマンドラインで、スクリプトが保存されているディレクトリに移動します。

4. 以下のコマンドを実行して、PDFファイルをMarp形式のMarkdownに変換します:
   - 特定のPDFファイルを変換する場合:
     ```bash
     python pdf_to_marp.py path/to/your/file.pdf
     ```
   - カレントディレクトリ内のすべてのPDFファイルを変換する場合:
     ```bash
     python pdf_to_marp.py
     ```

5. 変換が完了すると、入力PDFファイルと同じ名前で`.md`拡張子のファイルが生成されます。

6. 生成されたMarkdownファイルをMarp対応のエディタ（例：VS Code with Marp extension）で開いて確認し、必要に応じて手動で調整します。

### Pandocを使った試行錯誤の過程

1. **最初のアプローチ**:
   当初、PDFからMarkdownへの変換にPandocを使用しようとしました。以下のようなコマンドを試みました:
   ```bash
   pandoc -f pdf -t markdown input.pdf -o output.md
   ```
   しかし、このアプローチは「Unknown input format pdf」というエラーで失敗しました。

2. **中間フォーマットの使用**:
   次に、PDFをテキストに変換してから、そのテキストをMarkdownに変換する2段階のプロセスを試みました:
   ```bash
   pdftotext input.pdf temp.txt
   pandoc -f plain -t markdown temp.txt -o output.md
   ```
   これは部分的に機能しましたが、PDFの構造が失われ、結果が理想的ではありませんでした。

3. **入力フォーマットの指定**:
   Pandocの入力フォーマットとして `plain` や `text` を指定しましたが、これらは直接サポートされていないことがわかりました。

4. **Markdownとして扱う**:
   最後に、入力を直接Markdownとして扱うことを試みました:
   ```bash
   pandoc -f markdown -t markdown input.txt -o output.md
   ```
   これは機能しましたが、PDFの構造やフォーマットを適切に保持できませんでした。

5. **結論**:
   これらの試行錯誤を経て、Pandocは本ケースでは最適なツールではないと判断しました。PDFの構造を保持し、Marp形式に適したMarkdownを生成するには、カスタムのPythonスクリプトを作成する方が効果的であることがわかりました。

この過程を経て、最終的に上記のPythonスクリプトを開発し、PDFからMarp形式のMarkdownへの直接変換を実現しました。このアプローチにより、PDFの構造をより適切に保持し、Marpに適したフォーマットを生成することができました。

### 生成AIの使用

* Perplexity(CLAUDE 3.5 SONNET)とMicrosoft Copilot（Microsoft 365等ライセンス支払いなし、無料）を使用して作成しました
* なお、開発・実行環境はMicrosoft Windows 11を搭載するPC上です