--output path/to/file.mp3 [--dry-run] * * Stimmen-Pool-IDs sind in voices.json zentral gepflegt. Module geben * Pool-ID an (z.B. "narrator-warm"), nicht direkt ElevenLabs-IDs. * * Status: Skelett — echte API-Call-Implementierung folgt. */ declare(strict_types=1); require_once __DIR__ . '/../../php/config.php'; $opts = getopt('', ['text:', 'voice:', 'output:', 'dry-run']); if (empty($opts['text']) || empty($opts['voice']) || empty($opts['output'])) { fwrite(STDERR, "Usage: php voice.php --text \"...\" --voice --output path.mp3 [--dry-run]\n"); exit(1); } $text = $opts['text']; $voicePoolId = $opts['voice']; $output = $opts['output']; $dryRun = isset($opts['dry-run']); // === Pool-ID → ElevenLabs-ID auflösen === $voicesFile = __DIR__ . '/voices.json'; if (!file_exists($voicesFile)) { fwrite(STDERR, "[asset-gen/voice] FEHLER: voices.json fehlt in tools/asset-gen/\n"); exit(2); } $voices = json_decode(file_get_contents($voicesFile), true); if (!isset($voices[$voicePoolId])) { fwrite(STDERR, "[asset-gen/voice] FEHLER: Pool-ID '$voicePoolId' nicht in voices.json definiert.\n"); fwrite(STDERR, " Verfügbar: " . implode(', ', array_keys($voices)) . "\n"); exit(2); } $elevenlabsId = $voices[$voicePoolId]['elevenlabs_id']; echo "[asset-gen/voice] Text: " . substr($text, 0, 80) . (strlen($text) > 80 ? '…' : '') . "\n"; echo "[asset-gen/voice] Pool-ID: $voicePoolId\n"; echo "[asset-gen/voice] ElevenLabs: $elevenlabsId\n"; echo "[asset-gen/voice] Output: $output\n"; if (empty(V2_ELEVENLABS_KEY)) { fwrite(STDERR, "[asset-gen/voice] FEHLER: ELEVENLABS_API_KEY nicht gesetzt.\n"); exit(2); } if ($dryRun) { echo "[asset-gen/voice] --dry-run, würde TTS generieren.\n"; exit(0); } // === TODO: echter API-Call === // $url = "https://api.elevenlabs.io/v1/text-to-speech/$elevenlabsId"; // $ch = curl_init($url); // curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // curl_setopt($ch, CURLOPT_HTTPHEADER, [ // 'xi-api-key: ' . V2_ELEVENLABS_KEY, // 'Content-Type: application/json', // 'Accept: audio/mpeg', // ]); // curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([ // 'text' => $text, // 'model_id' => 'eleven_multilingual_v2', // 'voice_settings' => ['stability' => 0.55, 'similarity_boost' => 0.75], // ])); // $audio = curl_exec($ch); // $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); // curl_close($ch); // if ($code === 200 && $audio) { // @mkdir(dirname($output), 0775, true); // file_put_contents($output, $audio); // echo "[asset-gen/voice] OK: gespeichert nach $output\n"; // exit(0); // } // fwrite(STDERR, "[asset-gen/voice] FEHLER: HTTP $code\n"); // exit(3); fwrite(STDERR, "[asset-gen/voice] HINWEIS: Echter API-Call noch nicht implementiert. Stub liefert nichts.\n"); exit(0);