1e51ef7def
- 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>
98 lines
2.8 KiB
Python
98 lines
2.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Stadt-Symbolbilder fuer Busfahrt.
|
|
|
|
Liest cities.json, generiert fuer jede Stadt mit imagePrompt das fehlende
|
|
Bild via DALL-E-3 im verbindlichen GeoGraSim-Bildstil.
|
|
|
|
Aufruf:
|
|
set -a; source App/.env.local; set +a
|
|
python3 App/sims/busfahrt/scripts/generate-city-images.py # alles fehlende
|
|
python3 App/sims/busfahrt/scripts/generate-city-images.py tokio rom # gezielt
|
|
|
|
Ueberschreiben: FORCE=1 python3 ... tokio
|
|
"""
|
|
import json, os, sys, time, urllib.request, urllib.error
|
|
|
|
KEY = os.environ.get('OPENAI_API_KEY')
|
|
if not KEY:
|
|
sys.exit('OPENAI_API_KEY env var nicht gesetzt — vorher: set -a; source App/.env.local; set +a')
|
|
|
|
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
CITIES_FILE = os.path.join(SCRIPT_DIR, '..', 'assets', 'data', 'cities.json')
|
|
IMG_DIR = os.path.join(SCRIPT_DIR, '..', 'assets', 'cities')
|
|
os.makedirs(IMG_DIR, exist_ok=True)
|
|
|
|
with open(CITIES_FILE, encoding='utf-8') as f:
|
|
cities = json.load(f)
|
|
|
|
force = os.environ.get('FORCE') == '1'
|
|
arg_targets = set(sys.argv[1:])
|
|
|
|
todo = []
|
|
for city in cities:
|
|
if not city.get('imagePrompt'):
|
|
continue
|
|
if arg_targets and city['id'] not in arg_targets:
|
|
continue
|
|
out_path = os.path.join(IMG_DIR, f"{city['id']}.png")
|
|
if os.path.exists(out_path) and not force:
|
|
continue
|
|
todo.append((city, out_path))
|
|
|
|
if not todo:
|
|
print("nichts zu tun — alle Bilder vorhanden (FORCE=1 zum Ueberschreiben)")
|
|
sys.exit(0)
|
|
|
|
print(f"-> generiere {len(todo)} Bilder ...")
|
|
ok_count = 0
|
|
fail_count = 0
|
|
|
|
for i, (city, out_path) in enumerate(todo, 1):
|
|
print(f"[{i}/{len(todo)}] {city['id']}: ", end='', flush=True)
|
|
|
|
payload = json.dumps({
|
|
"model": "dall-e-3",
|
|
"prompt": city['imagePrompt'],
|
|
"n": 1,
|
|
"size": "1792x1024",
|
|
"quality": "standard",
|
|
}).encode()
|
|
|
|
req = urllib.request.Request(
|
|
"https://api.openai.com/v1/images/generations",
|
|
data=payload,
|
|
headers={
|
|
"Authorization": f"Bearer {KEY}",
|
|
"Content-Type": "application/json",
|
|
},
|
|
)
|
|
try:
|
|
with urllib.request.urlopen(req, timeout=180) as resp:
|
|
data = json.loads(resp.read().decode())
|
|
url = data['data'][0]['url']
|
|
except urllib.error.HTTPError as e:
|
|
body = e.read().decode()
|
|
print(f"x HTTP {e.code} — {body[:200]}")
|
|
fail_count += 1
|
|
time.sleep(5)
|
|
continue
|
|
except Exception as e:
|
|
print(f"x {e}")
|
|
fail_count += 1
|
|
time.sleep(5)
|
|
continue
|
|
|
|
try:
|
|
urllib.request.urlretrieve(url, out_path)
|
|
size = os.path.getsize(out_path)
|
|
print(f"ok ({size//1024} KB)")
|
|
ok_count += 1
|
|
except Exception as e:
|
|
print(f"x download {e}")
|
|
fail_count += 1
|
|
continue
|
|
|
|
time.sleep(2.5)
|
|
|
|
print(f"\nFertig: {ok_count} ok, {fail_count} Fehler")
|