見出し画像

画像からテーブル構造の抽出を GPT4V と Instructor を使って実現する

GPT-4V を使って画像から表を抽出し、Instructor を使って表を整形するサンプルコード。Instructor 自体の docs を参照して試してます。

# ライブラリのインストール
!pip install instructor -Uqq

Instructorライブラリを使って、GPT4Vから返り値として得たいフォーマットを指定します。

from io import StringIO
from typing import Annotated, Any
from pydantic import BaseModel, BeforeValidator, PlainSerializer, InstanceOf, WithJsonSchema
import pandas as pd

def md_to_df(data: Any) -> Any:
    "markdownをDataFrameに変換する"
    if isinstance(data, str):
        return (
            pd.read_csv(
                StringIO(data),  # Process data
                sep="|",
                index_col=1,
            )
            .dropna(axis=1, how="all")
            .iloc[1:]
            .map(lambda x: x.strip())
        )
    return data


MarkdownDataFrame = Annotated[
    InstanceOf[pd.DataFrame],  # pandas DataFrame のインスタンスであることを指定
    BeforeValidator(md_to_df),  # 検証前に md_to_df 関数を呼び出す
    PlainSerializer(lambda df: df.to_markdown()),  # DataFrame をマークダウンにシリアライズする方法を定義
    WithJsonSchema(
        {
            "type": "string",  # JSON スキーマタイプを文字列として指定
            "description": "The markdown representation of the table, each one should be tidy, do not try to join tables that should be seperate",
        }
    ),
]

class Table(BaseModel):
    caption: str
    dataframe: MarkdownDataFrame

実行のためのclientや関数を定義。

import instructor
from openai import OpenAI
from typing import Iterable

# Apply the patch to the OpenAI client to support response_model
# Also use MD_JSON mode since the visin model does not support any special structured output mode
client = instructor.patch(OpenAI(), mode=instructor.function_calls.Mode.MD_JSON)


def extract_table(url: str) -> Iterable[Table]:
    return client.chat.completions.create(
        model="gpt-4-vision-preview",
        response_model=Iterable[Table],
        max_tokens=1800,
        messages=[
            {
                "role": "user",
                "content": [
                    {"type": "text", "text": "Extract table from image."},
                    {"type": "image_url", "image_url": {"url": url}},
                ],
            }
        ],
    )

試す画像の指定

今回試す画像は以下の通り。

from IPython.display import Image
from urllib.request import urlopen

# 試す画像
url = "https://a.storyblok.com/f/47007/2400x2000/bf383abc3c/231031_uk-ireland-in-three-charts_table_v01_b.png"
Image(urlopen(url).read())

テーブルの抽出

返り値を確認します。

# テーブルの抽出
tables = extract_table(url)
for table in tables:
    print(table.caption, end="\n")
    print(table.dataframe)
Top 10 grossing apps in October 2023 (Ireland) for Android
          App                           Category
 Rank
 1                          Google One         Productivity
 2                             Disney+        Entertainment
 3       TikTok - Videos, Music & LIVE        Entertainment
 4                    Candy Crush Saga                Games
 5      Tinder: Dating, Chat & Friends    Social networking
 6                         Coin Master                Games
 7                              Roblox                Games
 8      Bumble - Dating & Make Friends               Dating
 9                         Royal Match                Games
 10        Spotify: Music and Podcasts        Music & Audio
Top 10 grossing apps in October 2023 (Ireland) for iOS
          App                           Category
 Rank
 1      Tinder: Dating, Chat & Friends    Social networking
 2                             Disney+        Entertainment
 3      YouTube: Watch, Listen, Stream        Entertainment
 4        Audible: Audio Entertainment        Entertainment
 5                    Candy Crush Saga                Games
 6       TikTok - Videos, Music & LIVE        Entertainment
 7      Bumble - Dating & Make Friends               Dating
 8                              Roblox                Games
 9         LinkedIn: Job Search & News             Business
 10        Duolingo - Language Lessons            Education

無事テーブルの抽出ができました。

一回目試したときは上手く行かなかったのですが、その後は上手く行っています。

今回使ったコード

今回使ったコードになります。よかったらご活用ください。

おわりに

以上、お読みいただきありがとうございます。少しでも参考になればと思います。

もし似たようなコンテンツに興味があれば、フォローしていただけると嬉しいです:noteTwitter


関連


この記事が気に入ったらサポートをしてみませんか?