Files
geograsim/App/assets/img/avatars/scripts/generate-via-openrouter.py
T
Adminator 1e51ef7def Nachtrag: alle bisher untracked Ordner + hängende Änderungen mit-committen
- Konzept/, didaktik_geografie/, didaktik_simulation/, v2-modules/, v2-platform/
- 12 code-workspace-Files
- STATUS-*.md
- viele M/D/R-Änderungen an bereits getrackten Files
- .gitignore verstärkt: **/.humaninput/, **/secret_keys.txt

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-08 02:27:02 +02:00

156 lines
13 KiB
Python

#!/usr/bin/env python3
"""
Generator fuer die 42 neuen Avatar-PNGs via OpenRouter + Gemini 2.5 Flash Image.
Fallback weil OpenAI-Org (gpt-image-*) wegen fehlender Verification blockiert ist.
Usage:
set -a; source App/.env.local; set +a
python App/assets/img/avatars/scripts/generate-via-openrouter.py
# FORCE=1 ueberschreibt bestehende PNGs
"""
import os, sys, json, time, base64, subprocess, tempfile
from pathlib import Path
API_KEY = os.environ.get("OPENROUTER_API_KEY")
if not API_KEY:
print("ERR: OPENROUTER_API_KEY fehlt — source App/.env.local !")
sys.exit(1)
DEST = Path(__file__).resolve().parents[1]
FORCE = os.environ.get("FORCE", "") == "1"
STYLE = (
"Flat Scandinavian portrait illustration, square 1:1 composition, painted style "
"with clean vector shapes, dark forest green (#1f4b37) and sage green (#4a7c4e) tones, "
"yellow-mustard (#e8c547) accents, beige (#e8e4d8) backgrounds, white highlights. "
"Friendly character portrait, centered face, soft shoulder framing, plain calm background. "
"No text, no watermark, no logo, no borders, no frame."
)
# slug → szenenspezifischer Prompt-Suffix
SPECS = [
("ozeanographin", "Portrait of a young female oceanographer named Linnea, Scandinavian features, navy blue research-vessel jacket with a small whale-tail brooch, holding a clipboard."),
("tropenbiologe", "Portrait of a young male tropical biologist named Kwame, West African features, olive field shirt, brass magnifier on a lanyard, suggested green tropical leaves behind."),
("skaterin", "Portrait of a young female skater named Reni, multi-ethnic, short pink hair, beanie cap, skateboard slung over the shoulder."),
("dj", "Portrait of a young male DJ named Kofi, West African features, wireless headphones around the neck, casual yellow hoodie."),
("wolf-tundra", "Portrait of a friendly tundra wolf cub named Yuki, white-gray fur, kind blue eyes, sitting in fresh snow."),
("krake-tiefsee", "Portrait of a friendly deep-sea octopus named Otto, purple-pink skin, large curious eyes, two arms gently waving, soft underwater glow."),
# Aliens — bewusst comic-/cartoon-freundlich: grosse runde Augen, weiches
# Laecheln, sanfte Proportionen, freundliche kindgerechte Erscheinung.
("alien-geologin", "CUTE FRIENDLY CARTOON style with big round expressive eyes, soft warm smile, rounded child-like proportions. Portrait of a friendly cartoon alien geologist named Zorblax, lavender skin, three big sparkling eyes, small wiggly antennae with glowing tips, holding a sparkly quartz crystal. Cheerful, approachable, suitable for children."),
("alien-ozean", "CUTE FRIENDLY CARTOON style with big round expressive eyes, soft warm smile, rounded child-like proportions. Portrait of a friendly cartoon alien oceanographer named Aquana, teal-blue translucent skin, big curious eyes, tiny cute fish-like gills on the cheeks, holding a glowing water-sample tube. Cheerful, approachable."),
("alien-wetter", "CUTE FRIENDLY CARTOON style with big round expressive eyes, soft warm smile, rounded child-like proportions. Portrait of a friendly cartoon alien meteorologist named Tempest, fluffy cloud-gray skin, tiny smiling lightning bolts dancing around the head, holding a happy mini cloud."),
("alien-stadt", "CUTE FRIENDLY CARTOON style with big round expressive eyes, soft warm smile, rounded child-like proportions. Portrait of a friendly cartoon alien urban analyst named Urbanix, silver-mint skin, cute geometric markings on the cheeks like glowing pixels, holding a tiny holographic city in the palm."),
("alien-tiere", "CUTE FRIENDLY CARTOON style with big round expressive eyes, soft warm smile, rounded child-like proportions. Portrait of a friendly cartoon alien biologist named Faunor, soft sand-yellow fur, big floppy cat-like ears, gently holding a colorful alien butterfly. Adorable, kid-friendly."),
("alien-pflanzen", "CUTE FRIENDLY CARTOON style with big round expressive eyes, soft warm smile, rounded child-like proportions. Portrait of a friendly cartoon alien botanist named Floranth, leaf-green skin, tiny cheerful flowers blooming from the hair, holding a sprouting seed with a smile."),
("alien-vulkan", "CUTE FRIENDLY CARTOON style with big round expressive eyes, soft warm smile, rounded child-like proportions. Portrait of a friendly cartoon alien volcanologist named Magmara, warm orange-red skin, gentle glowing seams like cooling lava on the arms, holding a small smooth obsidian stone, friendly expression — not scary."),
("alien-arktis", "CUTE FRIENDLY CARTOON style with big round expressive eyes, soft warm smile, rounded child-like proportions. Portrait of a friendly cartoon alien glaciologist named Glacium, pale ice-blue skin, sparkly frost crystals on the shoulders, holding a small glowing ice core. Bundled in a cozy scarf."),
("alien-wueste", "CUTE FRIENDLY CARTOON style with big round expressive eyes, soft warm smile, rounded child-like proportions. Portrait of a friendly cartoon alien desert researcher named Solara, golden-tan skin, cute sun-disc headpiece, holding a tiny smiling cactus."),
("alien-regenwald", "CUTE FRIENDLY CARTOON style with big round expressive eyes, soft warm smile, rounded child-like proportions. Portrait of a friendly cartoon alien rainforest scout named Veridia, jade-green skin, vine-like hair with tiny leaves, a small colorful parrot perched on the shoulder."),
("alien-berg", "CUTE FRIENDLY CARTOON style with big round expressive eyes, soft warm smile, rounded child-like proportions. Portrait of a friendly cartoon alien mountaineer named Altimos, stone-gray skin with gentle geological strata pattern on the cheeks, holding a small brass compass with a smile."),
("alien-meer", "CUTE FRIENDLY CARTOON style with big round expressive eyes, soft warm smile, rounded child-like proportions. Portrait of a friendly cartoon alien ocean explorer named Marinus, deep blue skin, cute coral-like crown, holding a glowing pearly seashell."),
("bathyscaph-trieste", "Portrait of the Trieste bathyscaph, a 1960 deep-sea submersible used by Jacques Piccard and Don Walsh, sturdy steel sphere with portholes, deep ocean blue background."),
("zeppelin-graf", "Portrait of the Graf Zeppelin airship from 1929, silver fabric envelope with crew gondola, gentle clouds and earth horizon."),
("ballon-charliere", "Portrait of the Charlière hydrogen balloon from 1783, brown wicker basket beneath a beige spherical envelope with rope netting, calm golden sky."),
("polar-fram", "Portrait of the polar research vessel Fram from 1893 (Nansen), wooden hull designed for drift ice, sails furled, surrounded by ice and northern light."),
("dampfschiff-beagle", "Portrait of HMS Beagle from 1831 (Darwin), three-masted brig with steam funnel, anchored at a tropical island shore, palm silhouettes."),
("tauchglocke-halley", "Portrait of Halley's diving bell from 1690, wooden barrel-shaped chamber with weighted base, suspended underwater by ropes, fish silhouettes around."),
("sonde-voyager", "Portrait of Voyager 1 space probe from 1977, golden record disc visible, parabolic dish antenna, deep starfield background."),
("eisbohrer-vostok", "Portrait of a Vostok ice-core sample being lifted from an Antarctic drill, scientists in red parkas in the background, clear ice cylinder with visible layers."),
("rover-curiosity", "Portrait of the Curiosity Mars rover from 2012, six wheels, robotic arm extended, mast camera, on red Martian terrain with butte."),
("satellit-landsat", "Portrait of a Landsat earth-observation satellite, large solar panel arrays like wings, orbiting Earth, blue planet in the background."),
("forschungsschiff-meteor", "Portrait of FS Meteor research vessel, white hull with German flag, scientific equipment on deck, calm sea."),
("wettersatellit-meteosat", "Portrait of a Meteosat geostationary weather satellite, cylindrical body with solar cells, viewed against Earth with European cloud patterns."),
("humboldt-alexander", "Portrait of Alexander von Humboldt (1769-1859), European scholar in formal early-19th-century coat, holding a botanical sample, gentle Andean landscape behind."),
("mercator-gerhard", "Portrait of Gerhard Mercator (1512-1594), Flemish cartographer in Renaissance clothing with beard, holding a globe and pair of compasses."),
("cook-james", "Portrait of Captain James Cook (1728-1779), British naval officer in 18th-century uniform with tricorn hat, Pacific island behind."),
("polo-marco", "Portrait of Marco Polo (1254-1324), young Venetian merchant in medieval traveling clothes, holding a small jade figurine, hint of Silk Road."),
("ibn-battuta", "Portrait of Ibn Battuta (1304-1369), Moroccan scholar-traveler in traditional robes and turban, holding a travel journal, suggestion of desert and minaret."),
("nansen-fridtjof", "Portrait of Fridtjof Nansen (1861-1930), Norwegian polar explorer in fur-trimmed parka, ice-axe in hand, polar light."),
("piccard-auguste", "Portrait of Auguste Piccard (1884-1962), Swiss physicist with characteristic large forehead and round glasses, vintage flight suit, stratosphere balloon in background."),
("amundsen-roald", "Portrait of Roald Amundsen (1872-1928), Norwegian polar explorer in fur parka with hood, holding the Norwegian flag, Antarctic ice horizon."),
("earhart-amelia", "Portrait of Amelia Earhart (1897-1937), American aviator in leather flight jacket with aviator goggles pushed up, short tousled hair, vintage propeller plane behind."),
("earle-sylvia", "Portrait of Sylvia Earle (born 1935), American marine biologist in diving suit holding helmet under arm, ocean reef behind, white wavy hair, warm smile."),
("anning-mary", "Portrait of Mary Anning (1799-1847), English paleontologist in 19th-century shawl and bonnet, holding an ammonite fossil, Jurassic coast cliffs behind."),
("carson-rachel", "Portrait of Rachel Carson (1907-1964), American environmental scientist with notebook and binoculars, gentle pastoral nature background."),
]
URL = "https://openrouter.ai/api/v1/chat/completions"
def generate(slug, suffix):
out = DEST / f"avatar-{slug}.png"
if out.exists() and not FORCE:
print(f" skip {out.name} (existiert; FORCE=1 zum Ueberschreiben)")
return "skip"
prompt = f"{STYLE} {suffix}"
payload_str = json.dumps({
"model": "google/gemini-2.5-flash-image",
"messages": [{"role": "user", "content": prompt}],
"modalities": ["image", "text"],
})
# curl statt urllib, weil Inkscape-Python keine root certs hat.
with tempfile.NamedTemporaryFile("w", suffix=".json", delete=False, encoding="utf-8") as tf:
tf.write(payload_str)
payload_path = tf.name
try:
proc = subprocess.run(
["curl", "-s", "-X", "POST", URL,
"-H", f"Authorization: Bearer {API_KEY}",
"-H", "Content-Type: application/json",
"-H", "HTTP-Referer: https://geograsim.at",
"-H", "X-Title: GeoGraSim Avatar Generator",
"-d", "@" + payload_path],
capture_output=True, text=False, timeout=180,
)
if proc.returncode != 0:
print(f" fail {out.name}: curl exit={proc.returncode} stderr={proc.stderr[:120]}")
return "fail"
raw = proc.stdout
data = json.loads(raw.decode("utf-8"))
except Exception as e:
print(f" fail {out.name}: {e}")
return "fail"
finally:
try: os.unlink(payload_path)
except Exception: pass
if "error" in data:
print(f" fail {out.name}: {data['error']}")
return "fail"
try:
imgs = data["choices"][0]["message"].get("images") or []
if not imgs:
print(f" fail {out.name}: no images in response")
return "fail"
url = imgs[0]["image_url"]["url"]
b64 = url.split(",", 1)[1]
out.write_bytes(base64.b64decode(b64))
size_kb = out.stat().st_size / 1024
print(f" ok {out.name} ({size_kb:.0f} KB)")
return "ok"
except Exception as e:
print(f" fail {out.name}: parse {e}")
return "fail"
def main():
# Optional: LIMIT=10 begrenzt auf erste 10 Slugs (fuer Qualitaets-Check).
limit = int(os.environ.get("LIMIT", "0")) or len(SPECS)
specs = SPECS[:limit]
stats = {"ok": 0, "skip": 0, "fail": 0}
print(f"Generiere {len(specs)} Avatare (insgesamt definiert: {len(SPECS)})")
print()
for slug, suffix in specs:
r = generate(slug, suffix)
stats[r] = stats.get(r, 0) + 1
time.sleep(1.5)
print()
print(f"Fertig: {stats['ok']} neu, {stats['skip']} geskippt, {stats['fail']} Fehler.")
if stats["ok"] > 0:
print("Naechster Schritt: powershell -ExecutionPolicy Bypass -File App/Don_t_Deploy/build-avatar-thumbs.ps1")
return 0 if stats["fail"] == 0 else 1
if __name__ == "__main__":
sys.exit(main())