こんにちは!
以前から、キャラクターの生成を自動化したく、画像生成AIをうまく活用できないかと考えてました。
考えてるうちにどんどん発展していったので、まずは一度やってみることにしました
やりたいこと
- パラメータをランダムに決定
- モンスターを自動生成
- 二体の親モンスターから子モンスターを生成
環境構築
Pythonの仮想環境を作ります。
python -m venv create-monster
cd create-monster
ディレクトリに移動した直後の状態
$ ls
bin/ include/ lib/ pyvenv.cfg
仮想環境の有効化
source bin/activate
必要なライブラリのインストール
pip install openai requests python-dotenv uuid requests
openaiとは
OpenAIのライブラリです。
クライアントを作成して操作します。
python-dotenvとは
環境変数を.envから読み込むためのライブラリです。
ディレクトリ構造
最終的なディレクトリ構造はこちら
create-monster/
├── .env
├── bin/
├── create-child.py
├── create-parent.py
├── include/
├── lib/
└── pyvenv.cfg
コード
まずは親モンスターの生成コード。
これを2回実行して、モンスターを二体作ります。
import openai
import os
import random
import json
import uuid
import requests
from dotenv import load_dotenv
load_dotenv()
api_key = os.getenv("OPENAI_API_KEY")
if not api_key:
raise ValueError("OPENAI_API_KEY環境変数が設定されていません。")
# OpenAIクライアントのインスタンスを作成
client = openai.OpenAI(api_key=api_key)
def generate_monster_gene():
colors = ['red', 'blue', 'green', 'yellow', 'purple', 'black', 'white', 'pink', 'gold', 'silver']
hat_colors = ['none'] * 98 + ['black', 'red']
accessories_options = ['none'] * 20 + ['earrings']
types = ['monster'] * 70 + ['dragon'] * 20 + ['devil'] * 9 + ['god']
backgrounds = ['ruins'] * 50 + ['battlefield'] * 49 + ['moon']
gene = {
'body': random.choice(colors),
'eye': random.choice(colors),
'hat': random.choice(hat_colors),
'accessories': random.choice(accessories_options),
'type': random.choice(types),
'background': random.choice(backgrounds),
}
return gene
def generate_visual_description(gene):
"""遺伝子情報からビジュアル記述を生成"""
parts = [
f"body: {gene['body']}" if gene['body'] != 'none' else "",
f"eye: {gene['eye']}" if gene['eye'] != 'none' else "",
f"hat: {gene['hat']}" if gene['hat'] != 'none' else "",
f"type: {gene['type']}",
f"accessories: {gene['accessories']}" if gene['accessories'] != 'none' else "",
]
description_parts = ', '.join(part for part in parts if part)
description = f"A full-body view of a cyber punks, {description_parts}, facing front. The background is {gene['background']}. The image should be photo-realistic."
return description
def request_dall_e_image(description):
"""DALL-E 3 APIを使用して画像を生成し、保存する関数"""
response = client.images.generate(
prompt=description,
n=1, # 生成する画像の数
size="512x512" # 画像のサイズ
)
# 画像URLを取得
image_url = response.data[0].url
# 画像をダウンロードして保存
image_response = requests.get(image_url)
image_filename = f"image_{uuid.uuid4()}.png"
with open(image_filename, 'wb') as file:
file.write(image_response.content)
return image_filename
# モンスター情報の生成
monster_gene = generate_monster_gene()
# ビジュアル記述の生成
description = generate_visual_description(monster_gene)
# DALL-E 3による画像生成
image_filename = request_dall_e_image(description)
# 情報と画像のファイル名を紐付けて保存
monster_data = {
'gene': monster_gene,
'image_filename': image_filename
}
uuid_key = str(uuid.uuid4())
with open(f"{uuid_key}.json", 'w') as file:
json.dump(monster_data, file)
print(f"モンスターの情報と画像ファイル名が保存されました:{uuid_key}.json")
次に、二体のモンスターから新しいモンスターを生成するコード。
import openai
import os
import random
import json
import uuid
import requests
import sys
from dotenv import load_dotenv
load_dotenv()
api_key = os.getenv("OPENAI_API_KEY")
if not api_key:
raise ValueError("OPENAI_API_KEY環境変数が設定されていません。")
# OpenAIクライアントのインスタンスを作成
client = openai.OpenAI(api_key=api_key)
def combine_genes(gene1, gene2):
"""二つのモンスターの情報を組み合わせる"""
combined_gene = {
'body': random.choice([gene1['body'], gene2['body']]),
'eye': random.choice([gene1['eye'], gene2['eye']]),
'hat': random.choice([gene1['hat'], gene2['hat']]),
'accessories': random.choice([gene1['accessories'], gene2['accessories']]),
'type': random.choice([gene1['type'], gene2['type']]),
'background': random.choice([gene1['background'], gene2['background']]),
}
return combined_gene
def generate_child_monster(uuid1, uuid2):
"""二つのUUIDに基づいて親モンスターの情報を読み込み、子モンスターを生成する"""
with open(f"{uuid1}.json", 'r') as file:
parent1_data = json.load(file)
with open(f"{uuid2}.json", 'r') as file:
parent2_data = json.load(file)
child_gene = combine_genes(parent1_data['gene'], parent2_data['gene'])
return child_gene
def request_dall_e_image(description):
"""DALL-E 3 APIを使用して画像を生成し、保存する関数"""
response = client.images.generate(
prompt=description,
n=1, # 生成する画像の数
size="512x512" # 画像のサイズ
)
# 画像URLを取得
image_url = response.data[0].url
# 画像をダウンロードして保存
image_response = requests.get(image_url)
image_filename = f"image_{uuid.uuid4()}.png"
with open(image_filename, 'wb') as file:
file.write(image_response.content)
return image_filename
def generate_visual_description(gene):
"""情報からビジュアル記述を生成"""
parts = [
f"body: {gene['body']}" if gene['body'] != 'none' else "",
f"eye: {gene['eye']}" if gene['eye'] != 'none' else "",
f"hat: {gene['hat']}" if gene['hat'] != 'none' else "",
f"accessories: {gene['accessories']}" if gene['accessories'] != 'none' else "",
f"type: {gene['type']}",
]
description_parts = ', '.join(part for part in parts if part)
description = f"A full-body view of a cyber punks, {description_parts}, facing front. The background is {gene['background']}. The image should be photo-realistic."
return description
def main():
if len(sys.argv) != 3:
print("Usage: python script.py <uuid1> <uuid2>")
sys.exit(1)
uuid1 = sys.argv[1]
uuid2 = sys.argv[2]
# 子モンスター情報の生成
child_monster_gene = generate_child_monster(uuid1, uuid2)
# 子モンスターのビジュアル記述を生成し、画像を生成
child_description = generate_visual_description(child_monster_gene)
child_image_filename = request_dall_e_image(child_description)
# 子モンスター情報と画像を保存
child_monster_data = {
'gene': child_monster_gene,
'image_filename': child_image_filename
}
child_uuid = str(uuid.uuid4())
with open(f"{child_uuid}.json", 'w') as file:
json.dump(child_monster_data, file)
print(f"子モンスターの情報と画像ファイル名が保存されました:{child_uuid}.json")
if __name__ == "__main__":
main()
.envも忘れずに。
OPENAI_API_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
実行
それでは、実行してみましょう!
親モンスターの生成
以下のコマンドを実行します。
python create-parent.py
まずは一体目
$ python create-parent.py
モンスターの情報と画像ファイル名が保存されました:0f4c17ba-ba04-4d7e-bdb7-8380c64cb165.json
生成されたJSONファイルの中身
{"gene": {"body": "red", "eye": "blue", "hat": "none", "accessories": "none", "type": "dragon", "background": "battlefield"}, "image_filename": "image_54cc99a4-ec56-4c4d-a405-ac50eb47bb9c.png"}
続いて二体目。
$ python create-parent.py
モンスターの情報と画像ファイル名が保存されました:ba6a5483-93e8-4e45-aedf-19bfc046a1a9.json
生成されたJSONファイルの中身
{"gene": {"body": "purple", "eye": "black", "hat": "none", "accessories": "none", "type": "dragon", "background": "ruins"}, "image_filename": "image_96637356-8d3c-4143-8d73-43ab20b03a5b.png"}
子モンスターの生成
親モンスターのJSONファイル名になっているUUIDを二つ渡します。
$ python create-child.py 0f4c17ba-ba04-4d7e-bdb7-8380c64cb165 ba6a5483-93e8-4e45-aedf-19bfc046a1a9
子モンスターの情報と画像ファイル名が保存されました:92534141-4885-4215-8f45-cd57de147637.json
生成されたJSONファイルの中身
{"gene": {"body": "purple", "eye": "black", "hat": "none", "accessories": "none", "type": "dragon", "background": "battlefield"}, "image_filename": "image_08b0f2b1-4a65-40d9-a2ea-2905831ad041.png"}
試しに、同じコマンドで再生成してみます。
$ python create-child.py 0f4c17ba-ba04-4d7e-bdb7-8380c64cb165 ba6a5483-93e8-4e45-aedf-19bfc046a1a9
子モンスターの情報と画像ファイル名が保存されました:88439ef4-b0ca-45c5-84f6-2dece87cde50.json
生成されたJSONファイルの中身
{"gene": {"body": "purple", "eye": "blue", "hat": "none", "accessories": "none", "type": "dragon", "background": "battlefield"}, "image_filename": "image_f8d7a0ff-81f6-4833-9fa7-4806073b201f.png"}
まとめ
DALL-E3を利用して、モンスターの自動生成と掛け合わせをしてみました。
掛け合わせと言っても、パラメータを引き継いでいるだけなので、厳密にはちょっと違うかもしれませんね。
今回はドラゴン同士の掛け合わせになったので、別のタイプが出るまでやってみようと思います。
色々とチャレンジすると楽しいですね!
みなさんも一緒に頑張りましょう!