GPT-4 Vision API で遊ぶ
はじめに
おはこんにちばんは、えるです❢
OpenAI DevDayでなんだかいろいろ発表されたので遊ぼうシリーズ(?)の第2弾は GPT-4 Vision APIです✨
ちなみに第1弾noteは以下
DALLE3 APIを使用した ふわっと画像生成|える (note.com)
ひとまずは上記noteの実装をベースに、画像を取り込んだ際はGPT-4Vを呼ぶような実装にしてみます
ただ、GPT-4Vは現在のところ制約もあるみたいです、そのあたりにまずは触れてみようかと思います
GPT-4V の現状
まずは素直に公式まにあるを頑張って読みます
Vision - OpenAI API
えるさんは英語ワカンナイ人なので、ところどころ日本語に翻訳しつつ読みます。。
割と大事なことがさらっと書いてあります
・Assistants APIは画像入力をサポートしていない
・functions/toolsには対応していない
とかがひとまず気になった点でしょうか
というか、えるさんは第1弾noteをベースに作っていたのでfunctions/tools未対応の部分でもしっかり躓きました。。
functions/toolsとはFunction callingのことです、たぶん。
確かにFunction Callingのサポートモデルにも入ってないんですよね
なんでだろう、将来的には入るとは思うんですが何か理由があるのかな?
未対応といえば、systemメッセージにも現状未対応みたいです
あとはLimitationとかも読んでおきます
実装方法とか結果
①初期化
import asyncio
import json
import aiohttp
import os
import discord
import openai
import requests
import base64
import random
import io
from PIL import Image, PngImagePlugin
from openai import OpenAI
bot_token = os.environ['KEMI_BOT_KEY']
openai_key = os.environ['GPT_KEY']
ここは第一弾noteと変わらないですね、urlは不要だったので削ったくらいです
②Discord bot記述部
### discord initial
intents = discord.Intents.default()
intents.message_content = True
client = discord.Client(intents=intents)
message_chunks = []
@client.event
async def on_ready():
print(f'{client.user.name} has connected to Discord!')
@client.event
async def on_message(message):
img_url = []
print(message.content)
if message.author == client.user:
return
if message.attachments:
for attachment in message.attachments:
img_url.append(attachment.url)
state,data = gpt_msg(message.content,img_url)
await message.channel.send(state)
await message.channel.send(data)
client.run(bot_token)
第一弾noteと比較して削り忘れた記述の削除と、discordの添付ファイルを画像と解釈し画像のURLを覚えておく処理を追加しています
そして画像のURLをGPT-4Vのinputにしているので、現状だと他の添付ファイルはエラーになるはずです(試してませんが恐らく)
③gpt_msg部
def gpt_msg(question,img_url):
img_cnt=0
img_description = ""
for images in img_url:
print(images)
img_cnt+=1
model_name = "gpt-4-vision-preview"
client = OpenAI()
response = client.chat.completions.create(
model="gpt-4-vision-preview",
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": "どのような画像か詳細を説明してください"},
{
"type": "image_url",
"image_url": {
"url": images,
},
},
],
}
],
max_tokens=800,
)
img_description = str(img_cnt)+"枚目の画像は"+response.choices[0].message.content+"です。"
model_name = "gpt-4-1106-preview"
client = OpenAI()
if img_cnt > 0:
question = img_description+question
messages = [{"role": "user", "content": question}]
response = client.chat.completions.create(
model=model_name,
messages=[
{"role": "user", "content": question},
],
tools=tools,
tool_choice="auto",
)
response_message = response.choices[0].message
send_message = response.choices[0].message.content
tool_calls = response_message.tool_calls
if tool_calls:
available_functions = {
"generate_image": generate_image,
}
messages.append(response_message)
for tool_call in tool_calls:
function_name = tool_call.function.name
function_to_call = available_functions[function_name]
function_args = json.loads(tool_call.function.arguments)
prompt = function_args.get("prompt")
second_response = client.chat.completions.create(
model=model_name,
messages=[
{"role": "user", "content": prompt+"がモチーフの画像を作りたいので、その詳細な描写を画像生成AIに伝えるためのプロンプトを提案してください。 回答は英語が嬉しいです。プロンプトのみの回答が嬉しいです。"},
],
)
input_text = second_response.choices[0].message.content
input_text = dalle_api(input_text)
return "--generate--", input_text
else:
return "----", send_message
…長い!! ので第一弾noteと比較して追加や変更した部分をまずは抜粋します
img_cnt=0
img_description = ""
for images in img_url:
print(images)
img_cnt+=1
model_name = "gpt-4-vision-preview"
client = OpenAI()
response = client.chat.completions.create(
model="gpt-4-vision-preview",
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": "どのような画像か詳細を説明してください"},
{
"type": "image_url",
"image_url": {
"url": images,
},
},
],
}
],
max_tokens=800,
)
img_description = str(img_cnt)+"枚目の画像は"+response.choices[0].message.content+"です。"
model_name = "gpt-4-1106-preview"
client = OpenAI()
if img_cnt > 0:
question = img_description+question
概要としては、GPT-4Vにどんな画像か聞いて、その結果を「1枚目の画像は~、2枚目の画像は~」と繋げています
上記の結果をユーザー入力に繋いでいるので、「画像の説明と、画像に関連する質問」をユーザーがしている感じにしています。
④tool部(旧function部)
tools=[
{
"type": "function",
"function": {
"name": "generate_image",
"description": "イラスト生成を指示する文の場合、イラスト生成用のキーワードを作成する。",
"parameters": {
"type": "object",
"properties": {
"prompt": {
"type": "string",
"description": "生成用キーワードなど",
},
},
"required": ["prompt"],
},
},
}
]
ここは第一弾noteと変わらないです
⑤DALLE3 API部
### DALLE setting
def dalle_api(input_text):
client = OpenAI()
response = client.images.generate(
model="dall-e-3",
prompt=input_text,
size="1024x1024",
quality="standard",
n=1,
)
image_url = response.data[0].url
return image_url
ここも第一弾noteと変わらないです
結果
以下の感じで、画像が解釈可能になりました
私の実装の場合画像の説明でDALLE3を呼びに行ってしまうのですが、
「イラストは作成しないで」というと作成しませんでした、それでいけちゃうんだ。。
イラストからイラスト生成に繋ぐことも一応できちゃいます
現在の実装方法の問題点
1) discordの画像以外の添付ファイル未対応
現状の私の使い方ならいいかーと思ってますが、これって対応できるのかな? ファイル名拡張子で弾くとか??
2)複数枚の画像の読み込み
現状は1枚ずつ読み込んでますが、GPT-4Vはマルチにも読めるので、本来はそちらのほうが良い気がします
これは単に1枚読みのほうが取り合えずの実装が容易だったのが理由なので、今後試してみたいですね
3)複数枚画像の解釈失敗
例えば2枚画像を読み、「1枚目の説明をお願い」とした場合、なぜか2枚目の画像を説明してくれました
この辺りは複数枚読み込みにするとむしろ安定するのかな?
4)GPT4の呼び出し回数
現状は画像ありの場合で例えば「画像説明をして」の場合GPT-4V→GPT4の具合に必ず2回呼びますが、
本来だとGPT-4Vを1回呼べば良いですよねえ、、とか考えつつ実装の容易性で現状になってます
このあたりはGPT-4Vがfunction callingに対応すれば解決するので、待ちかなあ
この記事が気に入ったらサポートをしてみませんか?