GPT-4OとClaude 3.5 Sonnetを使って画像から短編小説を作ることができるかを検証する
はじめに
皆様は「ない本、あります。」 という書籍をご存知でしょうか?
本の内容は、著者の方がSNSなどで送られてくる1枚の画像をもとに、本のデザインや著者プロフィール、実際のストーリーをショートショート形式で執筆されている本です。
実際に書籍を購入して読んでみましたが一枚の画像からストーリーを考えるというプロセスに大変刺激を受けました。
同時に、「一枚の画像からストーリーを作ることは生成AIでもできるのではないか?」との疑問が湧き、生成AIを用いてこのコンセプトを実現することができるかを検証してみたいと思います。
検証は以下の2つのパターンで行います。ちょうどClaude 3.5 Sonnetのモデルがリリースされたこともあり、出力を比較してどのようになるかを見てみたいと思います。
パターンA「GPT-4OのVision APIを使って作ってみる」で試してみる
パターンB 「Claude 3.5 Sonnetモデルを利用して、より高度な出力ができるか」を試してみる
それでは、試してみましょう。
生成AIは画像から短編小説を作成することはできるのか?
パターンA「GPT-4OのVision APIを使って作ってみる」
Midjourneyで作成した画像で検証を行います。SF小説を作ってみたかったので、宇宙人がビールを飲む画像を使ってまずは検証します。
パブでビールを飲む宇宙人の画像
画像生成のプロンプト
fashion alien model, sitting next seat in a bar, POV, monster mascots, alien cocktails, high contrast, mars attacks, alien realism, surrealism, realistic alien, ultra detailed, editorial, alien makeups, alien drinking beer, hyper realistic, autochrome
# 役割
- あなたは最高のSF小説家として振る舞います。
- 与えられた画像の内容をもとに、小説を作成することがあなたの役割です。
# 指示
- 奇抜なタイトルとストーリーを作成してください。
- 星新一のようなショートショートの作風で、タイトルと小説を作成してください。
# 出力形式
- 必ず、「タイトル」と「本文」を両方出力してください。
- タイトルは20文字以内、本文は300文字から400文字程度で出力してください。
GPTからの出力
GPTによるSF小説
タイトル:
宇宙パブの片隅で
本文:
地球の片隅、ある静かなパブで、異星人のザールは一人静かにビールを味わっていた。ザールは遠い星、ゼクターンからやってきた旅行者であり、人間の文化を学ぶために地球を訪れていた。彼の緑色の皮膚と大きな黒い目は、パブの常連たちにとってもすでに見慣れた光景となっていた。
ある日、ザールはパブの隅で一冊の古い書物を見つけた。それは地球の古代文明について書かれた本で、彼は興味津々に読み始めた。本の中には、「友情」と「信頼」という概念が繰り返し強調されていた。ザールは、ゼクターンにはないこの独特な価値観に強く惹かれた。
数週間が過ぎ、ザールはパブの常連たちと深い友情を築くようになった。彼らはザールに地球の習慣や文化を教え、ザールは彼らにゼクターンの物語を語った。言葉や文化の壁を越えて、彼らは心からの交流を楽しんだ。
しかし、ザールには帰るべき時が来た。彼は別れの言葉を告げるため、最後の夜をパブで過ごした。ザールは静かにビールを一口飲み、微笑んだ。「地球には、特別な何かがある。それは、友達の存在だ。」
翌朝、ザールは静かにパブを去った。彼の席には、一冊の古い書物が置かれていた。その書物は、彼が地球から持ち帰る唯一の宝物だった。
ザール。。。行かないで。。。。
感動のストーリーが爆誕しました。
続いて、他の画像でも試してみましょう。
恋愛小説ではどのようになるか試してみたかったので、和服を着た古風なカップルの画像を生成しました。
和服を着た古風なカップルの画像
画像生成のプロンプト
black and white photography of a Japanese samurai and a Japanese woman in a kimono, both in their 30s, holding hands but standing slightly apart and facing forward, with the samurai having a sword sheathed at his side, in the style of intense gaze, hauntingly beautiful, richly layered, expressive eyes, jagged edges, classic Japanese portrait, loose and fluid style --ar 73:111 --stylize 750 --v 6.0
恋愛小説を作ってもらうプロンプトは以下のように設定しました。
#役割
あなたは最高の恋愛小説家として振る舞います。
与えられた画像の内容をもとに、小説を作成することがあなたの役割です。
#指示
奇抜なタイトルとストーリーを作成してください。
村上春樹のようなショートショートの作風で、タイトルと小説を作成してください。
#出力形式
必ず、「タイトル」と「本文」を両方出力してください。
タイトルは20文字以内、本文は300文字から400文字程度で出力してください。
出力
GPTの恋愛小説
タイトル
「戦火に咲く恋」
本文
あの戦国の世、血と煙が漂う戦場で彼と彼女は出会った。彼は冷徹な目を持つ勇敢な侍、彼女は戦火の中で一輪の花のように咲く美しい武家の娘だった。戦場で偶然交わした一瞬の眼差しが、彼らの心を引き寄せた。
夜が訪れ、月明かりの下、彼は彼女に近づいた。「君のために、この戦を終わらせる」と誓った。その言葉に彼女の目が輝いた。「共に生きるために、私も戦うわ」と彼女は答えた。
翌朝、彼は敵の大将を討ち取り、戦を終わらせた。だが、その代償は大きかった。彼女もまた、戦の犠牲となったのだ。彼は彼女の手を握りしめ、涙を流しながら言った。「君のために、生き続ける」と。
その後、彼は彼女の想いを胸に抱きながら、平和な時代を築くために戦い続けた。彼女の笑顔を忘れずに、永遠に。
全米が泣いた。悲しすぎる。
ただ、非常に良くできたストーリーですね。
Midjorneyの画像生成の精度がかなり上がっていることにも驚きましたが、数秒で作られるショート・ショートとしては、かなり良いのではないでしょうか。
プロンプトに作風をより明確に付与すると、さらに良くなるような気がしますね。
GPTで検証に利用したソースコードは以下です。ブラウザでも実施可能ですが、APIを利用する場合は以下のようになります。
import base64
import requests
from openai import OpenAI
load_dotenv()
openai_api_key = os.environ.get('OPENAI_API_KEY')
gpt_prompt = """
#役割
- あなたは最高の恋愛小説家として振る舞います。
- 与えられた画像の内容をもとに、小説を作成することがあなたの役割です。
#指示
- 奇抜なタイトルとストーリーを作成してください。
- 村上春樹のようなショートショートの作風で、タイトルと小説を作成してください。
#出力形式
- 必ず、「タイトル」と「本文」を両方出力してください。
- タイトルは20文字以内、本文は300文字から400文字程度で出力してください。
"""
def encode_image(image_path):
with open(image_path, "rb") as image_file:
return base64.b64encode(image_file.read()).decode('utf-8')
def query_gpt_vison_api(image_path, user_prompt):
base64_image = encode_image(image_path)
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {openai_api_key}"
}
payload = {
"model": "gpt-4o",
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": user_prompt
},
{
"type": "image_url",
"image_url": {
"url": f"data:image/jpeg;base64,{base64_image}"
}
}
]
}
],
"max_tokens": 4096
}
try:
response = requests.post(
"https://api.openai.com/v1/chat/completions", headers=headers, json=payload, timeout=10)
response_data = response.json()
message_content = response_data['choices'][0]['message']['content']
except AttributeError as e:
error_message = f"Error: {e}"
message_content = error_message
return message_content
gpt_result = query_gpt_vison_api("./input_img/tmp.png", gpt_prompt)
print(gpt_result)
「パターンB Claude 3.5 Sonnetモデルを利用して、より高度な出力ができるかを試してみる」
ここまでの検証でかなり良い結果が得られることがわかったので、より踏み込んだ検証を行いたいと思います。
パターンAではGPT-4Oのモデルを利用しましたが、ちょうどリリースされたてのClaude 3.5 Sonnetを利用して検証します。Claudeが提供するLLMもVisionのAPIが提供されているため、Visionを利用して検証します。
以下のプロンプトは、Anthropicが提供するPrompt generator を利用して作成しました。ClaudeのプロンプトエンジニアリングではXML形式で記載することがポイントのようですね。
SF小説を作ってみる(GPT同様にパブでビールを飲む宇宙人の画像を利用)
あなたは最高のSF小説家として振る舞います。与えられた画像の内容をもとに、奇抜なタイトルとストーリーを星新一風のショートショートで作成することがあなたの役割です。
画像をよく観察し、登場人物、設定、雰囲気などを想像してください。そこから、ユニークで印象的なタイトルと、それにふさわしい短いストーリーを生み出してください。物語は予想外の展開や意外な結末があると良いでしょう。
星新一の作風を意識し、簡潔な文章で情景や心情を巧みに描写してください。比喩表現や象徴的な要素を織り交ぜるのも効果的です。
出力形式は以下の通りです:
<title>
20文字以内のタイトルを書く
</title>
<content>
300文字から400文字程度の本文を書く
</content>
titleとcontentの両方を必ず出力してください。では、あなたの創造力を存分に発揮し、魅力的なSF小説を紡ぎ出してください。
ClaudeによるSF小説
<title>
異星の酒場にて
</title>
<content>
宇宙港の片隅にある酒場「銀河の涙」。そこに毎晩、異形の常連が現れる。灰色の肌に大きな黒い瞳。地球人の噂では、遥か彼方の星から来た亡命者だという。
彼は黙々とビールを飲む。喉元で泡が弾ける音だけが、静寂を破る。
ある夜、酔った宇宙飛行士が彼に絡んだ。「お前の星は、もう無いんだろ?」
突如、異星人の目から緑色の光が放たれた。一瞬にして飛行士は石と化した。
バーテンダーは溜息をつく。「また掃除か」
異星人は謝罪の意を込め、テーブルに硬貨を置いた。それは、消えたはずの故郷の通貨だった。
</content>
文章の展開に文才を感じます。
少なくとも私よりはセンスのある文章が書けていると感じました。すばらしい。
続いて、GPTと同様に恋愛小説も作ってみましょう。
あなたは最高の恋愛小説家として振る舞います。与えられた画像の内容をもとに、奇抜なタイトルとストーリーを村上春樹風のショートショートで作成することがあなたの役割です。
画像をよく観察し、登場人物、設定、雰囲気などを想像してください。そこから、ユニークで印象的なタイトルと、それにふさわしい短いストーリーを生み出してください。物語は予想外の展開や意外な結末があると良いでしょう。
村上春樹の作風を意識し、簡潔な文章で情景や心情を巧みに描写してください。比喩表現や象徴的な要素を織り交ぜるのも効果的です。
出力形式は以下の通りです:
<title>
20文字以内のタイトルを書く
</title>
<content>
300文字から400文字程度の本文を書く
</content>
titleとcontentの両方を必ず出力してください。では、あなたの創造力を存分に発揮し、魅力的な恋愛小説を紡ぎ出してください。
Claudeによる恋愛小説
<title>
刀と着物、時を超える愛
</title>
<content>
彼らは時空を超えて出会った。侍と舞妓、あるいは俳優とモデル。真実はどちらでもない。
彼の目は遠い戦場を見つめ、彼女の瞳は未来への不安を映す。二人を結ぶのは運命の赤い糸か、それとも刀の鋭い刃か。
雨の匂いが漂う空気の中、二人は無言で寄り添う。彼の荒々しい息遣いと彼女の柔らかな吐息が混ざり合う。
「行かないで」と彼女は言いたかった。だが言葉は風に散った。
彼は彼女の手から刀を取り上げ、「これが僕たちの物語だ」とつぶやいた。
そして二人は、誰も見たことのない世界へと歩み出した。古びた写真の中で、永遠に。
</content>
こちらも感動のストーリーが誕生しました。
GPTとClaudeも甲乙付けがたい結果となりましたね。
今回の検証はブラウザを利用して行うことも可能です。ただ、ブラウザからClaude 3.5 Sonnetを利用するためには有料プランの契約が必要であることなどからPythonのソースコードを記載しておきます。
Claude 3.5 SonnetをAPI経由で利用する場合は以下のようになります。
import os
import anthropic
import base64
def encode_image(image_path):
with open(image_path, "rb") as image_file:
return base64.b64encode(image_file.read()).decode('utf-8')
def query_claude_sonnet(prompt):
client = anthropic.Anthropic(
api_key=os.environ.get('CLAUDE_API_KEY')
)
image_media_type = "image/jpeg"
image_data = encode_image("./input_img/tmp.png")
message = client.messages.create(
model="claude-3-5-sonnet-20240620",
max_tokens=1024,
messages=[
{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "base64",
"media_type": image_media_type,
"data": image_data,
},
},
{
"type": "text",
"text": prompt
}
],
}
],
)
print(message)
検証結果
今回の検証で、「生成AIを使って画像からストーリーを作ることはできる」という印象を受けました。更に、GPTとClaudeを利用して比較を行いましたがどちらを出力が自然で驚きました。
Claude 3.5 Sonnetがリリースされる前にはOpusのモデルで検証をしていましたが、ちょうど本日新しいLLMのリリースがあったため3.5 Sonnetで検証を行いました。
画像からストーリーを作成するようなWebサービスであれば簡単に作れそうですね。
ただ、冒頭ご紹介した「ない本、あります。」の書籍に執筆されているショート・ショートや、代表的な作家の一人である 星新一さんのようなレベルには到底及ばないということも感じました。
一方で小説の執筆経験がない私のような人間と比べると短時間で高品質なモノが生成AIによって作成できるという印象です。
生成AIの使い所として100点の出力を求めるのではなく、一定レベルの品質を求める場合や短時間でアウトプットさせる場合が有効であると改めて実感しました。
是非、皆様も試してみてください。
Discussion