Atlas: Deploy-Buendel vor Staustufen-Sprint
- Logistik: Musik-Player Playlist-Modus (5 Gruppen, 20 Tracks) - Heli: End-Screen auf .ggs-endscreen, Mission-Bilder, Voice-Lines, Briefing-Audio - Logistik: Layout-Tausch Auftraege+Fahrzeuge links, Karte rechts - Logistik: Tier-1-Staedte ausgebaut, Auto-Timescale-Badge - Logistik: Roadnet/Railnet Dijkstra-Routing, Balance-Updates - Atlas: 5 Atlas-Inbox-Nachrichten (Cards-Pattern, DALL-E-Key, Musik-Playlists) - Status-Updates Heli + Logistik Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
#!/usr/bin/env bash
|
||||
# Generisches Audio-Batch-Script via OpenAI TTS.
|
||||
# Nimmt JSON-Textbuch mit Struktur:
|
||||
# { "lines": [ {"id": "...", "text": "..."} ] }
|
||||
# und generiert MP3s in sounds/radio/<id>.mp3
|
||||
#
|
||||
# Voraussetzung: OPENAI_API_KEY (aus App/.env.local)
|
||||
#
|
||||
# Aufruf:
|
||||
# set -a; source App/.env.local; set +a
|
||||
# App/sims/heli/scripts/generate-audio-openai.sh tower-geo-lines.json
|
||||
# App/sims/heli/scripts/generate-audio-openai.sh tower-start-lines.json
|
||||
# FORCE=1 … überschreibt bestehende
|
||||
# OPENAI_VOICE=shimmer … andere Stimme
|
||||
set -e
|
||||
: "${OPENAI_API_KEY:?OPENAI_API_KEY muss gesetzt sein}"
|
||||
|
||||
VOICE="${OPENAI_VOICE:-nova}"
|
||||
MODEL="${OPENAI_MODEL:-gpt-4o-mini-tts}"
|
||||
# Stil-Instruktion nur bei gpt-4o-mini-tts wirksam. Warmherzige Fluglotsin,
|
||||
# ruhig, klare deutsche Aussprache, als ob sie Schuelerinnen begleitet.
|
||||
INSTRUCTIONS="${OPENAI_TTS_INSTRUCTIONS:-Speak warmly and patiently like an encouraging female flight controller guiding a young student co-pilot. Unhurried, clear, friendly German pronunciation. Gentle reassuring tone, never robotic.}"
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
OUT_DIR="$SCRIPT_DIR/../sounds/radio"
|
||||
mkdir -p "$OUT_DIR"
|
||||
|
||||
JSON_INPUT="$1"
|
||||
if [ -z "$JSON_INPUT" ]; then
|
||||
echo "Usage: $0 <json-file>"
|
||||
exit 2
|
||||
fi
|
||||
JSON_FILE="$SCRIPT_DIR/$JSON_INPUT"
|
||||
if [ ! -f "$JSON_FILE" ]; then
|
||||
echo "Datei nicht gefunden: $JSON_FILE"; exit 2
|
||||
fi
|
||||
|
||||
echo "Modell: $MODEL · Stimme: $VOICE"
|
||||
echo "Quelle: $JSON_INPUT"
|
||||
echo
|
||||
|
||||
generate() {
|
||||
local id="$1"
|
||||
local text="$2"
|
||||
local out="$OUT_DIR/${id}.mp3"
|
||||
if [ -f "$out" ] && [ -z "$FORCE" ]; then
|
||||
echo "ok ${id}.mp3 schon da"
|
||||
return 0
|
||||
fi
|
||||
echo "gen ${id}"
|
||||
local payload
|
||||
payload=$(TEXT="$text" MODEL="$MODEL" VOICE="$VOICE" INSTR="$INSTRUCTIONS" python -c '
|
||||
import json, os
|
||||
body = {
|
||||
"model": os.environ["MODEL"],
|
||||
"voice": os.environ["VOICE"],
|
||||
"input": os.environ["TEXT"],
|
||||
"response_format": "mp3"
|
||||
}
|
||||
# instructions nur bei gpt-4o-mini-tts unterstuetzt
|
||||
if "mini-tts" in os.environ["MODEL"]:
|
||||
body["instructions"] = os.environ["INSTR"]
|
||||
print(json.dumps(body, ensure_ascii=False))')
|
||||
local http
|
||||
http=$(curl -sS -w "%{http_code}" -o "$out" \
|
||||
-X POST https://api.openai.com/v1/audio/speech \
|
||||
-H "Authorization: Bearer $OPENAI_API_KEY" \
|
||||
-H "Content-Type: application/json; charset=utf-8" \
|
||||
-d "$payload")
|
||||
if [ "$http" != "200" ]; then
|
||||
echo "FEHLER ${id}: HTTP $http"
|
||||
cat "$out"; echo; rm -f "$out"
|
||||
return 1
|
||||
fi
|
||||
local size; size=$(wc -c <"$out")
|
||||
if [ "$size" -lt 1500 ]; then
|
||||
echo "FEHLER ${id}: Datei zu klein ($size B)"
|
||||
cat "$out"; rm -f "$out"
|
||||
return 1
|
||||
fi
|
||||
echo "ok ${id}.mp3 (${size} B)"
|
||||
sleep 0.2
|
||||
}
|
||||
|
||||
ok=0; fail=0
|
||||
while IFS=$'\t' read -r id text; do
|
||||
[ -z "$id" ] && continue
|
||||
if generate "$id" "$text"; then ok=$((ok+1)); else fail=$((fail+1)); fi
|
||||
done < <(python -c "
|
||||
import json, sys
|
||||
d = json.load(sys.stdin)
|
||||
for line in d['lines']: print(line['id'] + '\t' + line['text'])
|
||||
" < "$JSON_FILE")
|
||||
|
||||
echo
|
||||
echo "Zusammenfassung: ok=$ok, fail=$fail"
|
||||
ls -1 "$OUT_DIR"/*.mp3 2>/dev/null | wc -l | xargs printf "Dateien im Ordner: %s\n"
|
||||
Reference in New Issue
Block a user