PostmanでGPT-V(Vision) APIを呼び出して、伝票の読み取りをしてもらった


先日のOpenAI dev dayにて、ついにGPT-VをAPIから呼び出すことができるようになりました。今日はこのAPIを呼び出して、レシートに記載されている情報を読み取ってJSONで返してもらってみようと思います。


## APIの仕様を確認する

対象のAPIのドキュメントは以下にあります。

https://platform.openai.com/docs/guides/vision

ドキュメントによると、以下のような形でリクエストを投げると結果が得られるとあります。
`image_url`のところを見るとわかる通り、この例ではインターネット上の画像を読み取り、結果を返すサンプルとなっています。

```shell
curl https://api.openai.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "model": "gpt-4-vision-preview",
    "messages": [
      {
        "role": "user",
        "content": [
          {
            "type": "text",
            "text": "What’s in this image?"
          },
          {
            "type": "image_url",
            "image_url": {
              "url": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg"
            }
          }
        ]
      }
    ],
    "max_tokens": 300
  }'
```

では、インターネット上に存在しない、手元やアプリケーションサーバ上にあるイメージを読み取ってもらうようにするにはどうすれば良いのでしょうか？

ドキュメントのもう少し下の方を確認すると、ありました。
base64形式で画像の情報を渡すことで実現できそうです。

```python
import base64
import requests

# OpenAI API Key
api_key = "YOUR_OPENAI_API_KEY"

# Function to encode the image
def encode_image(image_path):
  with open(image_path, "rb") as image_file:
    return base64.b64encode(image_file.read()).decode('utf-8')

# Path to your image
image_path = "path_to_your_image.jpg"

# Getting the base64 string
base64_image = encode_image(image_path)

headers = {
  "Content-Type": "application/json",
  "Authorization": f"Bearer {api_key}"
}

payload = {
  "model": "gpt-4-vision-preview",
  "messages": [
    {
      "role": "user",
      "content": [
        {
          "type": "text",
          "text": "What’s in this image?"
        },
        {
          "type": "image_url",
          "image_url": {
            "url": f"data:image/jpeg;base64,{base64_image}" // ←ここにBase64の値を入れる
          }
        }
      ]
    }
  ],
  "max_tokens": 300
}

response = requests.post("https://api.openai.com/v1/chat/completions", headers=headers, json=payload)

print(response.json())
```


## Postmanで試してみる

どのようにリクエストを投げれば良いかがわかったところで、Postmanを使って試してみたいと思います。

#### リクエストを作成

Postmanを起動して、MethodをPOST、URLのところには以下の値を設定します
```bash:url
https://api.openai.com/v1/chat/completions
```

bodyに以下のJSONを貼り付けます。AuthenticationのところにAPI-Keyを設定するのも忘れないようにしてください。

```json:body
{
    "model": "gpt-4-vision-preview",
    "messages": [
      {
        "role": "user",
        "content": [
          {
            "type": "text",
            "text": "この画像に含まれている値をJSONで返してください"
          },
          {
            "type": "image_url",
            "image_url": {
              "url": "ここにBase64データを貼り付ける"
            }
          }
        ]
      }
    ],
    "max_tokens": 300
  }
```


#### 画像をBase64に変換する

まず、GPT-Vに渡したい画像をBase64形式に変換します。Base64とは、バイナリデータをテキスト形式で表現するエンコーディング方式です。

まず、以下のサイトにアクセスします。そしてDRAG & DROP IMAGES ... のところにGPT-Vに渡したい画像ファイルをドラッグします。

今回は以下のレシートを読み込んでみたいと思います。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77722/1a29df67-b940-892f-9c31-8062f6afef29.jpeg" width="300">



:::note warn
アップロード可能なファイルサイズは1MBに制限されていますので、ファイルサイズが大きい場合は画像ツール等を使ってサイズを小さくする必要があります。
:::

https://www.base64-image.de/


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77722/23f7c8c0-eb94-9e2a-cc31-e62424abbeb5.png)




すると、以下のような形でBASE64の文字列が出力されますので、右上のcopyボタンをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77722/16acb58d-c1b1-a2df-fe89-feb9de6509d3.png)


次に、Postmanからのリクエストの渡し方は以下の様な形で、urlのところに貼り付けてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77722/42832217-b481-b936-ea4c-4826d8a1c0bb.png)








### 結果確認

Sendをクリックすすると、以下のようなレスポンスが返ってきました


```json
{
    "id": "chatcmpl-8MewgmC3RDNlV3ovgzRXqm1bVG0j9",
    "object": "chat.completion",
    "created": 1700411302,
    "model": "gpt-4-1106-vision-preview",
    "usage": {
        "prompt_tokens": 1471,
        "completion_tokens": 300,
        "total_tokens": 1771
    },
    "choices": [
        {
            "message": {
                "role": "assistant",
                "content": "画像から読み取れる情報をJSON形式にして提供します。以下がその内容です。\n\n```json\n{\n  \"Store\": \"CAFÉ de CRIÉ\",\n  \"StorePhone\": \"052-680-7838\",\n  \"Message\": \"商品代金無料キャンペーン中！さっさと買って、かばんを軽くしようーたくさん買ってスタンプ！\",\n  \"Date\": \"2023年11月19日\",\n  \"Time\": \"14時39分\",\n  \"ReceiptNumber\": \"000101\",\n  \"Items\": [\n    {\n      \"Name\": \"ボルテージ\",\n      \"Price\": \"790円\"\n    }\n  ],\n  \"Subtotal\": \"790円\",\n  \"Tax\": [\n    {\n      \"Type\": \"10%内税対象\",\n      \"Amount\": \"71円\"\n    }\n  ],\n  \"Total\": \"790円\",\n  \"PaymentMethod\": \"交通系IC\",\n  \"PointsEarned\": {\n    \"Amount\": \"71\",\n    \"Description\": \"ポイント対象\"\n  },\n  \"ItemCount\": \"1点\",\n  \"Note\": \"※領収書は税法法令順守品です。\",\n  \"ReceiptInformation\": {\n    \"TaxID\": \"T"
            },
            "finish_details": {
                "type": "max_tokens"
            },
            "index": 0
        }
    ]
}
```


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77722/208c14d0-b6eb-5ab0-0ee9-ea980006be5b.png)

単価やSubTotalなど、きちんと読めてそうですね。
さすがGPT・・・ただ、ボルチーニがボルテージになってしまっているのは気になります。


## まとめ

Postmanを使って画像（バイナリ）ファイルを渡すやり方をみてきました。
プログラムを書けば同じことはできますが、プログラム上で試す前に、こうやってAPIを呼んで動きを確認することができるのはとても便利ですよね。
Postmanを使えば、一度投げたリクエストは保存をしておけば必要な時に何度も呼び出して利用することもできますのでとても便利です。
無料で利用できるので有効に使って、開発効率を上げていきましょう！