auto-git:
[add] scripts/.DS_Store [add] scripts/README.md [add] scripts/extract_texture_filename_from_3ds.py [add] scripts/generate_3d_glb.py [add] scripts/generate_json.py [add] scripts/image_from_json.py [add] scripts/naming.py [add] scripts/openai_image_gen.py [add] scripts/remesh_bake_batch.py [add] server/public/assets/images/.DS_Store [add] server/public/assets/models/spirits/.DS_Store [change] server/public/assets/.DS_Store [change] server/public/assets/models/.DS_Store
This commit is contained in:
188
scripts/image_from_json.py
Normal file
188
scripts/image_from_json.py
Normal file
@@ -0,0 +1,188 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
import json
|
||||
import requests
|
||||
import urllib.parse
|
||||
|
||||
def generate_image_prompt(entity_json: dict, chat_model: str, api_key: str) -> str:
|
||||
"""
|
||||
Generiert einen Bild-Prompt aus der JSON-Beschreibung mit Hilfe eines OpenAI-Chat-Modells.
|
||||
"""
|
||||
url = "https://api.openai.com/v1/chat/completions"
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {api_key}",
|
||||
}
|
||||
pretext = (
|
||||
"Ich schicke dir nun einen JSON-Abschnitt, der ein japanisches spirituelles Wesen beschreibt."
|
||||
" Du wirst das Internet bemühen, um nach Darstellungen und weitere Beschreibung der äußeren Erscheinung dieses Wesens zu finden."
|
||||
" Mit all diesen Informationen generierst du dann ein Bild von dem Wesen im Stil von moderner Low-Poly 3D-Grafik,"
|
||||
" ohne Hintergrund, nur das Wesen selbst. Das Wesen soll vollständig auf dem Bild dargestellt sein, nicht abgeschnitten."
|
||||
" Es soll dafür geeignet sein, ein 3D Objekt daraus zu bauen."
|
||||
" Hier der JSON-Abschnitt:"
|
||||
)
|
||||
content = f"{pretext}\n{json.dumps(entity_json, ensure_ascii=False)}"
|
||||
payload = {
|
||||
"model": chat_model,
|
||||
"messages": [
|
||||
{"role": "user", "content": content}
|
||||
],
|
||||
"temperature": 0.7,
|
||||
}
|
||||
resp = requests.post(url, headers=headers, json=payload)
|
||||
resp.raise_for_status()
|
||||
data = resp.json()
|
||||
# Annahme: Der Prompt steht im ersten Choice unter message.content
|
||||
prompt = data["choices"][0]["message"]["content"].strip()
|
||||
return prompt
|
||||
|
||||
|
||||
def generate_and_download_image(prompt: str,
|
||||
image_model: str,
|
||||
api_key: str,
|
||||
count: int,
|
||||
size: str,
|
||||
fmt: str,
|
||||
base_output: str):
|
||||
"""
|
||||
Generiert Bilder mit der OpenAI Image API und lädt sie herunter.
|
||||
"""
|
||||
url = "https://api.openai.com/v1/images/generations"
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {api_key}",
|
||||
}
|
||||
payload = {
|
||||
"model": image_model,
|
||||
"prompt": prompt,
|
||||
"n": count,
|
||||
"size": size,
|
||||
"response_format": fmt,
|
||||
}
|
||||
resp = requests.post(url, headers=headers, json=payload)
|
||||
resp.raise_for_status()
|
||||
data = resp.json().get("data", [])
|
||||
|
||||
for idx, item in enumerate(data, start=1):
|
||||
if fmt == "url":
|
||||
img_url = item.get("url")
|
||||
try:
|
||||
img_resp = requests.get(img_url)
|
||||
img_resp.raise_for_status()
|
||||
except requests.RequestException as e:
|
||||
print(f"Fehler beim Herunterladen des Bildes #{idx}: {e}", file=sys.stderr)
|
||||
continue
|
||||
# Dateinamen bestimmen
|
||||
if base_output:
|
||||
base, ext = os.path.splitext(base_output)
|
||||
ext = ext or os.path.splitext(urllib.parse.urlparse(img_url).path)[1]
|
||||
filename = f"{base}_{idx}{ext}" if count > 1 else base_output
|
||||
else:
|
||||
path = urllib.parse.urlparse(img_url).path
|
||||
filename = os.path.basename(path)
|
||||
with open(filename, "wb") as f:
|
||||
f.write(img_resp.content)
|
||||
print(f"Bild gespeichert: {filename}")
|
||||
else:
|
||||
# Base64 JSON direkt ausgeben
|
||||
b64 = item.get("b64_json")
|
||||
out_name = f"{base_output or 'image'}_{idx}.b64.txt"
|
||||
with open(out_name, "w") as f:
|
||||
f.write(b64)
|
||||
print(f"Base64 in Datei geschrieben: {out_name}")
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Generiere Bild-Prompts aus JSON und erstelle Bilder via OpenAI API"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--api_key", "-k",
|
||||
help="OpenAI API-Schlüssel (alternativ ENV OPENAI_API_KEY)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--chat_model", "-c",
|
||||
default="o4-mini-high",
|
||||
help="Modell für die Prompt-Generierung (z.B. 'o4-mini-high')",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--image_model", "-m",
|
||||
default="dall-e-3",
|
||||
help="Modell für die Bild-Generierung (z.B. 'dall-e-3')",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--input", "-i",
|
||||
required=True,
|
||||
help="Pfad zu JSON-Datei mit einer Liste von Entity-Objekten",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--count", "-n",
|
||||
type=int,
|
||||
default=1,
|
||||
help="Anzahl Bilder pro Entity",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--size", "-s",
|
||||
choices=["256x256", "512x512", "1024x1024"],
|
||||
default="1024x1024",
|
||||
help="Bildgröße",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--format", "-f",
|
||||
choices=["url", "b64_json"],
|
||||
default="url",
|
||||
help="Antwort-Format",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--output", "-o",
|
||||
help="Basis-Ausgabe-Dateiname oder Verzeichnis (Suffixe _1,_2 werden ergänzt)",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
api_key = args.api_key or os.getenv("OPENAI_API_KEY")
|
||||
if not api_key:
|
||||
print("Error: API-Schlüssel fehlt. Nutze --api_key oder setze OPENAI_API_KEY.", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# JSON-Datei einlesen
|
||||
try:
|
||||
with open(args.input, "r", encoding="utf-8") as f:
|
||||
entities = json.load(f)
|
||||
except Exception as e:
|
||||
print(f"Fehler beim Laden der JSON-Datei: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
if not isinstance(entities, list):
|
||||
print("Error: Die JSON-Datei muss eine Liste von Objekten enthalten.", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# Für jede Entity Prompt generieren und Bild erstellen
|
||||
for idx, entity in enumerate(entities, start=1):
|
||||
name_safe = entity.get("Name", f"entity_{idx}").replace(" ", "_")
|
||||
print(f"Verarbeite: {entity.get('Name', name_safe)}")
|
||||
|
||||
prompt = generate_image_prompt(entity, args.chat_model, api_key)
|
||||
print(f"Generierter Prompt: {prompt}\n")
|
||||
|
||||
base_out = None
|
||||
if args.output:
|
||||
# Wenn Ausgabe ein Verzeichnis ist, dort ablegen
|
||||
if os.path.isdir(args.output):
|
||||
base_out = os.path.join(args.output, f"{name_safe}.png")
|
||||
else:
|
||||
base_out = f"{os.path.splitext(args.output)[0]}_{name_safe}.png"
|
||||
|
||||
generate_and_download_image(
|
||||
prompt=prompt,
|
||||
image_model=args.image_model,
|
||||
api_key=api_key,
|
||||
count=args.count,
|
||||
size=args.size,
|
||||
fmt=args.format,
|
||||
base_output=base_out,
|
||||
)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user