Home About Contact
Docling , PDF

Docling を使った pdf to markdown

pokemon pdf

このPDFDocling https://www.docling.ai/ を使って markdown に変換してみます。

Docling セットアップ

ここでは M1 Macbook Air を使っています。

Docling を使うには:

pip install docling

これだけで使えるのですが、 (この環境では) homebrew でインストールしている Python 3.13.2 ではうまく動きませんでした。 macOS (Sonoma 14.7.5) 標準の /usr/bin/python3 (Python 3.9.6) を使えば問題ない。 次のようにして venv 環境で Docling を試すとよい:

/usr/bin/python3 -m venv .venv
source .venv/bin/activate

pdf to markdown する

PDF から markdown に変換するには:

docling ./pokemon_doc.pdf

結果は ./pokemon_doc.md に保存されます。

直接ネット上のPDFを指して実行もできる:

docling https://blog.mindboardapps.com/posts/pdf-to-markdown-with-docling/images/pokemon_doc.pdf

オプションを指定しないと 画像部分が base64 文字列に変換され出力する markdown ファイルに埋め込まれます。 これはこれで便利なのですが、

とか

を使うこともできます。

docling ./pokemon_doc.pdf --image-export-mode placeholder

この場合は画像は次のようなプレースホルダー文字列で置き換えられた:

<!-- image -->
docling ./pokemon_doc.pdf --image-export-mode referenced

この場合は画像は次のようなプレースホルダー文字列で置き換えられた:

![Image](pokemon_doc_artifacts/image_000000_44d65f69e34ea6703726f2a98edc4d6555e701eb665d45d3f099919e26f42a2f.png)

なお表組部分は次のようにマークダウンのテーブル形式に変換される:

## 表1. 御三家ポケモン⼀覧

|   No. | 画像           | ⽇本語名   | 英語名      | タイプ     | 世 代   |   HP |
|-------|--------------|--------|----------|---------|-------|------|
|   001 | treecko.png  | キモリ    | Treecko  | くさ      | 第3    |   40 |
|   002 | torchic.png  | アチャモ   | Torchic  | ほのお     | 第3    |   45 |
|   003 | mudkip.png   | ミズゴロ ウ | Mudkip   | みず      | 第3    |   50 |
|   004 | turtwig.png  | ナエトル   | Turtwig  | くさ      | 第4    |   55 |
|   005 | chimchar.png | ヒコザル   | Chimchar | ほのお     | 第4    |   44 |
|   006 | piplup.png   | ポッチャ マ | Piplup   | みず      | 第4    |   53 |
|   007 | rowlet.png   | モクロー   | Rowlet   | くさ・ひこ う | 第7    |   68 |
|   008 | litten.png   | ニャビー   | Litten   | ほのお     | 第7    |   45 |
|   009 | popplio.png  | アシマリ   | Popplio  | みず      | 第7    |   50 |

画像や表組の処理をカスタマイズする

次のように直接 python コードを記述すれば、画像や表組の処理を自前のコードで差し替えることができる。

標準の画像処理 MarkdownPictureSerializer を継承して自前処理にした MyPictureSerializer :

class MyPictureSerializer(MarkdownPictureSerializer):
    def __init__(self, output_dir, doc_stem):
        super().__init__()
        self.output_dir = output_dir
        self.doc_stem = doc_stem
        self.counter = 0

    def serialize(self, *, item, doc_serializer, doc, **kwargs):
        self.counter += 1
        filename = f"{self.doc_stem}-picture-{self.counter}.png"
        item.get_image(doc).save(self.output_dir / filename, format="PNG")
        return SerializationResult(text=f"![Picture {self.counter}]({filename})")

標準の表組処理 MarkdownTableSerializer を継承して自前処理にした MyTableSerializer :

class MyTableSerializer(MarkdownTableSerializer):
    def __init__(self, output_dir, doc_stem):
        super().__init__()
        self.output_dir = output_dir
        self.doc_stem = doc_stem
        self.counter = 0

    def serialize(self, *, item, doc_serializer, doc, **kwargs):
        self.counter += 1
        img = item.get_image(doc)
        if img is None:
            return super().serialize(item=item, doc_serializer=doc_serializer, doc=doc, **kwargs)
        filename = f"{self.doc_stem}-table-{self.counter}.png"
        img.save(self.output_dir / filename, format="PNG")
        return SerializationResult(text=f"![Table {self.counter}]({filename})")

このカスタマイズでは、該当部分を画像ファイルとして書き出すと同時に画像をリンクする markdown 記述を出力している。

このコード:

img = item.get_image(doc)

で該当領域が画像として取り出せるので、これを API 経由で AIに渡して何かする...

などのカスタマイズが可能になる。

もちろん、 これらの自前シリアライザーを使ってPDF文書全体をマークダウン変換するため MarkdownDocSerializer をカスタマイズする必要あり:

def to_markdown(converter, input_path, output_dir, doc_stem):
    doc = converter.convert(str(input_path)).document
    serializer = MarkdownDocSerializer(
        doc=doc,
        picture_serializer=MyPictureSerializer(output_dir, doc_stem),
        table_serializer=MyTableSerializer(output_dir, doc_stem),
        params=MarkdownParams(image_placeholder="", image_mode=ImageRefMode.PLACEHOLDER),
    )
    return serializer.serialize().text

MarkdownDocSerializerpicture_serializer, table_serializer を自前のそれに差し替える。

画像や表組を実際に画像として出力する場合は PdfPipelineOptions で generate_picture_images とか generate_table_images を True に指定する必要がある・・・など、いろいろハマりどころはある。

    pipeline_options = PdfPipelineOptions(
        enable_remote_services=False,
        do_picture_description=False,
        generate_picture_images=True,
        images_scale=2.0,
        do_table_structure=True,
        generate_table_images=True,
    )

まとめ

Docling の入力は PDF 以外にも DOCX, PPTX なども使える。 ただし、DOCX や PPTX を入力した場合、PDF と異なる処理方法がたぶん使われる(詳細はドキュメントで確認のこと)。 PDF 入力の場合に関しては、 テキスト取り出し処理が行われる前にまずページ全体のレイアウトを AI が判定、 人間にとって自然な順でテキスト取り出しができる。 これが Docling を使う利点の一つ。 もう一つの利点は、ここで説明したように、ドキュメント中の 画像 / 表組 を認識して、それぞれそれ用の処理を使って変換されること。 そしてこの処理を自前のものに差し替えることができる。

なお、画像 / 表組 識別以外に 見出し / 段落 / リスト / コード / 数式 なども識別するようです。 Docling の Features を参照。
それぞれに シリアライザーがありカスタマイズ可能かどうかは調べていません。

本文テキストの取り出し処理は LLM OCR など AI を使っているわけではなく従来方式で PDF から普通にテキスト取り出ししているだけなのでハルシネーションの心配はない(と思う)。 また、 AI 処理を挟むといっても Docling にビルトインされている AI 処理範囲であれば M1 Macbook Air 8GB の非力なマシンでも普通に使える。 大量のドキュメントを頻繁に処理する場合などはまた話は別かもしれない。