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>
87 lines
3.0 KiB
PHP
87 lines
3.0 KiB
PHP
<?php
|
|
/**
|
|
* Atlas-Tool: Sprachausgabe generieren mit ElevenLabs.
|
|
*
|
|
* NUR LOKAL ausführen. API-Key liegt in v2-platform/.env.local.
|
|
*
|
|
* Aufruf:
|
|
* php voice.php --text "..." --voice <pool-id> --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 <pool-id> --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);
|