Files
geograsim/App/php/generate-helicopter-images.php
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

112 lines
6.2 KiB
PHP

<?php
/**
* Helikopter-Typ-Bilder fuer Heli-Uebersichtskarte (Quartett-Cards).
* Stil exakt wie Logistik (Flat Scandinavian), Format 1024x1024.
* Pro Typ realitaetsnahe Detail-Merkmale + korrekte Lackierung.
*/
set_time_limit(0);
ignore_user_abort(true);
header('Content-Type: text/plain; charset=utf-8');
$envFile = __DIR__ . '/../.env.local';
if (!file_exists($envFile)) { exit("ERROR: .env.local fehlt\n"); }
$OPENAI_KEY = '';
foreach (file($envFile) as $ln) {
$ln = trim($ln);
if ($ln === '' || $ln[0] === '#') continue;
if (preg_match('/^OPENAI_API_KEY\s*=\s*(.+)$/', $ln, $m)) {
$OPENAI_KEY = trim($m[1], " \t\"'");
break;
}
}
if (!$OPENAI_KEY) { exit("ERROR: OPENAI_API_KEY nicht in .env.local gefunden\n"); }
// Stil: Flat Scandinavian, aber mit erlaubter Lackierungs-Farbe
// (yellow-red fuer Notarzt-Heli, dark-blue+yellow fuer Polizei, olive-green fuer Bundesheer)
$STYLE_BASE = "Flat Scandinavian illustration, painted style with clean vector shapes, side-view profile of a helicopter centered in the frame, simplified beige (#e8e4d8) background with subtle sage green (#4a7c4e) ground silhouette and small white cloud accents, white highlights on the helicopter body. No text, no watermark, no logos, no borders, no frame.";
$HELIS = [
'heli-ec135' => [
'label' => 'Eurocopter EC135',
'scene' => "Subject: Eurocopter EC135 light twin-engine medical rescue helicopter shown as a clean side-view profile filling the frame edge-to-edge (NOT inside any circle or vignette). CRITICAL detail: the tail must end in a FENESTRON — a thick circular DISC-SHAPED HOUSING built into the tail fin, completely hiding the rotor blades behind a smooth flat disk surface. Absolutely NO open spinning tail rotor blades visible — the tail looks like a flat round wheel. Compact body, retractable skid landing gear, large sliding side door with red cross marking. Livery: bright Notarzt-Heli yellow (#e8c547) body with bold red (#c85c4a) horizontal accent stripe along the lower fuselage. Main rotor blades visible above the cabin.",
],
'heli-h145' => [
'label' => 'Airbus H145',
'scene' => "Subject: Airbus H145 medium twin-engine medical rescue helicopter shown as a clean side-view profile filling the frame edge-to-edge (NOT inside any circle or vignette — straight rectangular composition). CRITICAL detail: the tail ends in a FENESTRON — a thick circular DISC-SHAPED HOUSING built into the tail fin, completely hiding the rotor blades behind a smooth flat disk. Absolutely NO open spinning tail rotor visible. Larger fuselage than the EC135, prominent rear clamshell doors at the back, skid landing gear, large side sliding door with red cross marking. Five-blade main rotor visible above the cabin. Livery: bright Notarzt-Heli yellow (#e8c547) body with bold red (#c85c4a) horizontal accent stripe along the lower fuselage.",
],
'heli-aw169' => [
'label' => 'Leonardo AW169',
'scene' => "Subject: Leonardo AW169 medium twin-engine helicopter in side-view profile, in Austrian Police 'Libelle' configuration. Distinctive features: sleek modern fuselage, OPEN classical tail rotor (NOT a fenestron — clearly visible separate small rotor on tail boom), retractable wheeled landing gear (not skids), large windows. Five-blade main rotor visible above the cabin. Livery: dark navy blue (#1f3a5a) main body with bright yellow-mustard (#e8c547) high-visibility stripes along the lower side and tail.",
],
'heli-ab212' => [
'label' => 'Agusta-Bell AB212',
'scene' => "Subject: Agusta-Bell AB212 utility twin-engine military helicopter in side-view profile, classic 1970s design. Distinctive features: long narrow tail boom, OPEN two-blade tail rotor on the boom (NOT a fenestron), classic two-blade main rotor with semi-rigid teetering hub, skid landing gear, large sliding side door, slightly bulky engine cowling on top. Livery: matte olive-green military camouflage (#4a5a3a) with small Austrian Bundesheer red-white-red roundel insignia visible.",
],
];
$outDir = __DIR__ . '/../sims/heli/assets/helis-new';
if (!is_dir($outDir)) mkdir($outDir, 0777, true);
$ids = isset($_GET['ids']) ? array_filter(array_map('trim', explode(',', $_GET['ids']))) : array_keys($HELIS);
$force = !empty($_GET['force']);
echo "Helikopter-Typ-Generator (DALL-E 3, 1024x1024)\n";
echo "Modus: " . ($force ? 'FORCE' : 'skip if exists') . "\n";
echo str_repeat('-', 64) . "\n";
@ob_flush(); @flush();
$ok = 0; $skip = 0; $fail = 0;
foreach ($ids as $id) {
if (!isset($HELIS[$id])) { echo "x $id: unbekannt\n"; $fail++; continue; }
$out = $outDir . '/' . $id . '.png';
if (file_exists($out) && !$force) {
echo "skip $id.png (vorhanden)\n";
$skip++;
continue;
}
$prompt = $STYLE_BASE . ' ' . $HELIS[$id]['scene'];
$body = json_encode([
'model' => 'dall-e-3',
'prompt' => $prompt,
'n' => 1,
'size' => '1024x1024',
'quality' => 'standard',
]);
echo "-> $id (" . $HELIS[$id]['label'] . ") generiere ... ";
@ob_flush(); @flush();
$ch = curl_init('https://api.openai.com/v1/images/generations');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $OPENAI_KEY,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => $body,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 180,
]);
$resp = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($code !== 200) {
echo "FAIL ($code) — " . substr($resp, 0, 200) . "\n";
$fail++;
continue;
}
$data = json_decode($resp, true);
$url = $data['data'][0]['url'] ?? null;
if (!$url) { echo "FAIL keine URL\n"; $fail++; continue; }
$img = @file_get_contents($url);
if (!$img || strlen($img) < 1000) { echo "FAIL Download\n"; $fail++; continue; }
file_put_contents($out, $img);
$ok++;
echo "ok (" . round(strlen($img) / 1024) . " kB)\n";
@ob_flush(); @flush();
sleep(2);
}
echo str_repeat('-', 64) . "\n";
echo "Zusammenfassung: ok=$ok, skip=$skip, fail=$fail\n";
echo "Ordner: $outDir\n";