1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

こんにちは!

以前から、キャラクターの生成を自動化したく、画像生成AIをうまく活用できないかと考えてました。

考えてるうちにどんどん発展していったので、まずは一度やってみることにしました:slight_smile:

やりたいこと

  • パラメータをランダムに決定
  • モンスターを自動生成
  • 二体の親モンスターから子モンスターを生成

環境構築

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回実行して、モンスターを二体作ります。

create-parent.py
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")

次に、二体のモンスターから新しいモンスターを生成するコード。

create-child.py
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も忘れずに。

.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"}

生成されたモンスター画像
いい感じですね!
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"}

生成されたモンスター画像
こちらもいいですね。
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"}

生成されたモンスター画像
雰囲気出てますね!
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"}

生成されたモンスター画像
おー!個人的に好きです。
image_f8d7a0ff-81f6-4833-9fa7-4806073b201f.png

まとめ

DALL-E3を利用して、モンスターの自動生成と掛け合わせをしてみました。
掛け合わせと言っても、パラメータを引き継いでいるだけなので、厳密にはちょっと違うかもしれませんね。

今回はドラゴン同士の掛け合わせになったので、別のタイプが出るまでやってみようと思います。

色々とチャレンジすると楽しいですね!
みなさんも一緒に頑張りましょう!:smiley:

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?