🕌

AzureのGPT-4 Turbo with Visionではまった話

2024/03/30に公開

はじめに

  • Azure OpenAI Serviceで提供されるGPT-4 Turbo with VisionをPythonから操作した際に、直面した課題を紹介します。
  • Azure上のwith VisionではAzure のComputer Visionと組み合わせてOCRやグラウンディングの機能を拡張することが出来ます。
    • OCRの拡張をすることで、画像からテキストを抽出することができます。素のwith visionでも抽出可能ですが、組み合わせることでより精度が上がります。
    • グラウンディングの拡張をすることで画像内の物体の位置も特定できるようになります。以下の例では画像内の牛の位置を特定しています。

https://learn.microsoft.com/ja-jp/azure/ai-services/openai/concepts/gpt-with-vision

はまった内容

  • ドキュメント上では以下のようにextra_bodydataSourcesenhancementsを指定することでComputer Visionの機能を拡張できると記載されています。
  • しかし、実際にはextra_bodydataSourcesenhancementsを指定してもエラーが発生しました。

https://learn.microsoft.com/ja-jp/azure/ai-services/openai/how-to/gpt-with-vision?tabs=python%2Csystem-assigned%2Cresource#use-vision-enhancement-with-images

response = client.chat.completions.create(
    model=deployment_name,
    messages=[
        { "role": "system", "content": "You are a helpful assistant." },
        { "role": "user", "content": [  
            { 
                "type": "text", 
                "text": "Describe this picture:" 
            },
            { 
                "type": "image_url",
                "image_url": {
                    "url": "<image URL>"
                }
            }
        ] } 
    ],
    extra_body={
        "dataSources": [
            {
                "type": "AzureComputerVision",
                "parameters": {
                    "endpoint": "<your_computer_vision_endpoint>",
                    "key": "<your_computer_vision_key>"
                }
            }],
        "enhancements": {
            "ocr": {
                "enabled": True
            },
            "grounding": {
                "enabled": True
            }
        }
    },
    max_tokens=2000
)
print(response)
  • 以下のようなエラー内容が表示されます。
BadRequestError: Error code: 400 - {'error': {'message': '1 validation error for Request\nbody -> dataSources\n extra fields not permitted (type=value_error.extra)', 'type': 'invalid_request_error', 'param': None, 'code': None}} Output is truncated. View as a scrollable element or open in a text editor. Adjust cell output settings...
  • エラー内容をGitHub Copilotに聞いてみると
エラーメッセージによれば、APIリクエストの形式が正しくないことを示しています。具体的には、`extra_body``dataSources` フィールドに余分なフィールドが存在するとのことです。

Azure上のOpenAIのChat APIを使用している場合でも、`dataSources` フィールドはサポートされていない可能性があります。したがって、このフィールドをリクエストから削除するとエラーが解消するかもしれません。

ただし、Azure Computer Visionを使用するためには、`dataSources` フィールドが必要である可能性があります。その場合、Azure上のOpenAIのChat APIが`dataSources` フィールドをサポートするバージョンを使用しているかどうかを確認する必要があります。

Azure上のOpenAIのChat APIのバージョンや、そのバージョンがサポートするリクエストの形式については、Azureの公式ドキュメンテーションを参照してください。

と返ってきたのでAPIのドキュメントを確認してみます。

https://learn.microsoft.com/ja-jp/azure/ai-services/openai/reference#chat-completions

  • 新しく[2024-03-01-preview]がリリースされていたのでそちらを使用すると共に、仕様を確認します。
  • 3140行目に以下の記載がありました。dataSourcesではなくdata_sourcesと記載するのが正しいようです。
              "data_sources": { //こちらが正しい記載
                "type": "array",
                "description": "  The configuration entries for Azure OpenAI chat extensions that use them.\n  This additional specification is only compatible with Azure OpenAI.",
                "items": {
                  "$ref": "#/components/schemas/azureChatExtensionConfiguration"
                }
              },

https://github.com/Azure/azure-rest-api-specs/blob/main/specification/cognitiveservices/data-plane/AzureOpenAI/inference/preview/2024-03-01-preview/inference.json#L3140-L3146

  • いつの間にか仕様が変わっていたようです。data_sourcesに変更して再度実行するとエラーが解消し実行できました。

結論

  • リリース当初のコードでは実行できないので、新しいAPIの仕様に合わせて修正する必要があります。
  • playgroudやドキュメント上には反映されていない変更があるので、常に仕様を確認することが重要です。
  • 2023-12-01-previewも4月2日に廃止されるので常に新しいAPIを使用しましょう。

修正後のサンプルコード

  • 以下を実行すればひと通り試すことは出来ます。
  • imageは適宜修正してください。
from openai import AzureOpenAI
import json


api_endpoint = "<your_azure_openai_endpoint>" # your endpoint should look like the following https://YOUR_RESOURCE_NAME.openai.azure.com/
api_key = "<your_azure_openai_key>"
deployment_name = "<your_deployment_name>"
api_version = "2024-03-01-preview" # this might change in the future

client = AzureOpenAI(api_key=api_key, api_version=api_version, azure_endpoint=api_endpoint)

def show_json(obj):
    display(json.loads(obj.model_dump_json()))

  • data_sourcesに注意してください。
response = client.chat.completions.create(
    model=deployment_name,
    messages=[
        { "role": "system", "content": "You are an AI assistant that helps people find information." },
        { "role": "user", "content": [  
            { 
                "type": "text", 
                "text": "describe this picture in Japanese.:" 
            },
            { 
                "type": "image_url",
                "image_url": {
                    "url": "https://cdn.openai.com/API/docs/images/diagram-1.png" #サンプル画像
                }
            }
        ] } 
    ],
    extra_body={
        "data_sources": [
            {
                "type": "AzureComputerVision",
                "parameters": {
                    "endpoint": "<your_computer_vision_endpoint>",
                    "key": "<your_computer_vision_key>"
                }
            }],
        "enhancements": {
            "ocr": {
                "enabled": True
            },
            "grounding": {
                "enabled": True
            }
        }
    },
    max_tokens=2000
)

show_json(response)
  • 出力結果
{'id': 'chatcmpl-98J89OB1LiAu9jDY0tEpTwARDHM9C',
 'choices': [{'finish_reason': 'stop',
   'index': 0,
   'logprobs': None,
   'message': {'content': 'この画像は、異なるステータス間の遷移を示すフローチャートです。ステータスは以下の順に並んでいます:\n\n- 水色の「queued」(キューに入れられた)\n- 紫色の「in_progress」(進行中)\n- 更に紫色の「requires_action」(アクションが必要)\n- 緑色の「completed」(完了)\n- 灰色の「expired」(期限切れ)\n- ピンク色の「failed」(失敗)\n- もう一つの紫色の「cancelling」(キャンセル中)\n- 赤色の「cancelled」(キャンセルされた)\n\nそれぞれのステータスは矢印で繋がれており、プロセスの流れを表しています。たとえば、「queued」から「in_progress」へ、「in_progress」から「completed」、「failed」、「cancelled」、「requires_action」へと遷移しています。また、「requires_action」状態は「expired」になることも示されています。「cancelling」は「cancelled」へと変わります。フローチャートはプロセスやタスクがどのように処理されるかの条件を視覚化しています。',
    'role': 'assistant',
    'function_call': None,
    'tool_calls': None},
   'content_filter_results': {'hate': {'filtered': False, 'severity': 'safe'},
    'self_harm': {'filtered': False, 'severity': 'safe'},
    'sexual': {'filtered': False, 'severity': 'safe'},
    'violence': {'filtered': False, 'severity': 'safe'}},
   'enhancements': {'grounding': {'lines': [{'text': 'この画像は、異なるステータス間の遷移を示すフローチャートです。ステータスは以下の順に並んでいます:\n\n- 水色の「queued」(キューに入れられた)\n- 紫色の「in_progress」(進行中)\n- 更に紫色の「requires_action」(アクションが必要)\n- 緑色の「completed」(完了)\n- 灰色の「expired」(期限切れ)\n- ピンク色の「failed」(失敗)\n- もう一つの紫色の「cancelling」(キャンセル中)\n- 赤色の「cancelled」(キャンセルされた)\n\nそれぞれのステータスは矢印で繋がれており、プロセスの流れを表しています。たとえば、「queued」から「in_progress」へ、「in_progress」から「completed」、「failed」、「cancelled」、「requires_action」へと遷移しています。また、「requires_action」状態は「expired」になることも示されています。「cancelling」は「cancelled」へと変わります。フローチャートはプロセスやタスクがどのように処理されるかの条件を視覚化しています。',
       'spans': []}],
     'status': 'Success'}}}],
 'created': 1711767189,
 'model': 'gpt-4',
 'object': 'chat.completion',
 'system_fingerprint': None,
 'usage': {'completion_tokens': 349,
  'prompt_tokens': 739,
  'total_tokens': 1088},
 'prompt_filter_results': [{'prompt_index': 0,
   'content_filter_results': {'hate': {'filtered': False, 'severity': 'safe'},
    'self_harm': {'filtered': False, 'severity': 'safe'},
    'sexual': {'filtered': False, 'severity': 'safe'},
    'violence': {'filtered': False, 'severity': 'safe'}}}]}

  • contentのみ抽出する場合は以下のようにします。
print(response.choices[0].message.content)
  • 必要な情報のみ抽出できました。
この画像は、特定のプロセスやタスクの状態遷移を示すフローチャートのようです。以下に日本語で説明します。

- 青色の長方形には「queued」(キューイングされた)と書かれており、次の状態は紫色の長方形で「in_progress」(進行中)に遷移します。
- 「in_progress」からは、3つの異なる状態に遷移する可能性があります。「requires_action」(行動が必要)に進むことができる紫色の長方形、「cancelling」(キャンセル中)の紫色の長方形、「expired」(期限切れ)の灰色の長方形です。
- 「requires_action」は再び「queued」に戻ることができ、このフローは繰り返しになる可能性があります。
- 「cancelling」は最終的に「cancelled」(キャンセルされた)のピンク色の長方形に遷移します。
- 「in_progress」からは直接「completed」(完了)の緑色の長方形に遷移することも可能ですし、「failed」(失敗)のピンク色の長方形に遷移することも可能です。

この画像には矢印で状態間の遷移が示されており、ある状態から他の複数の状態への遷移や、ある状態に戻るループなども確認できます。

以上です。

Discussion