Lucy-TTS/F5: Skripte + Batches versionieren, schwere Assets ignoriert
- pocket_server.py (Produktions-TTS mit Stimmen-Waechter), text_norm, Bench-/Diag-Skripte - lucy-f5: f5_server/f5_test/bench_dml (DirectML-Experiment, Phase C/D offen) - .gitignore: venvs/Modelle/Audio/Logs der beiden Ordner + box_recon/gemma_swap-Scratch Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Deutscher TTS-Stresstest: rendert 10 Sätze (typische DE-Fallen, alle Längen), transkribiert per
|
||||
Whisper (SOLL vs IST) und misst Pausen/Prosodie. Server muss auf :8134 laufen (pocket_server /tts)."""
|
||||
import os, io, json, urllib.request
|
||||
import numpy as np, soundfile as sf, librosa
|
||||
from faster_whisper import WhisperModel
|
||||
|
||||
SERVER = "http://127.0.0.1:8134/tts"
|
||||
OUT = r"C:\Users\TobisPC\Desktop\lucy_de_stress"; os.makedirs(OUT, exist_ok=True)
|
||||
|
||||
TESTS = [
|
||||
("01_kurz_umlaut", "kurz", "Schön, dass du da bist, Commander."),
|
||||
("02_kurz_zahlen", "kurz", "Es ist 21 Uhr 40, und wir haben noch 16 GB frei."),
|
||||
("03_komposita", "mittel", "Die Geschwindigkeitsbegrenzung und die Aufmerksamkeitsspanne sind heute besonders wichtig."),
|
||||
("04_ss_sch_ch", "mittel", "Ich weiß nicht, ob die Straße noch frei ist, aber ich schaue gleich mal nach."),
|
||||
("05_umlaut_haeufung", "mittel", "Über fünf Türme, größere Bäume und schöne Flüsse führt die Röhre nach Süden."),
|
||||
("06_fremdwoerter", "mittel", "Das Backup-Skript läuft im Terminal, der Router ist online und der Server antwortet sofort."),
|
||||
("07_lang_gemischt", "lang", "Guten Morgen, Commander. Das nächtliche Backup ist um 3 Uhr durchgelaufen, es gab keine Fehler, und die Datenbank läuft mit 92 Prozent Auslastung völlig stabil."),
|
||||
("08_sehr_lang", "sehr lang", "Also, Commander, wenn ich das kurz zusammenfassen darf: heute früh war die Verbindung weg, dann lief das Update durch, danach musste ich zweimal neu starten, und jetzt sind endlich alle Dienste oben, das Gedächtnis ist warm, und wir können ganz entspannt weitermachen."),
|
||||
("09_akronyme", "mittel", "Die CPU der RX 9070 XT und die GPU laufen mit ROCm, sagt der PC über das LAN."),
|
||||
("10_zungenbrecher", "kurz", "Der Frühstücksfleischklößchenlieferant frühstückt fröhlich am frühen Freitag."),
|
||||
]
|
||||
|
||||
def render(text):
|
||||
req = urllib.request.Request(SERVER, data=json.dumps({"text": text}).encode("utf-8"),
|
||||
headers={"Content-Type": "application/json"})
|
||||
return urllib.request.urlopen(req, timeout=180).read()
|
||||
|
||||
w = WhisperModel("small", device="cpu", compute_type="int8")
|
||||
for name, length, text in TESTS:
|
||||
wav = render(text)
|
||||
path = os.path.join(OUT, name + ".wav")
|
||||
open(path, "wb").write(wav)
|
||||
a, sr = sf.read(io.BytesIO(wav)); a = np.asarray(a, dtype=np.float32).reshape(-1); dur = len(a) / sr
|
||||
segs, _ = w.transcribe(path, language="de", beam_size=5, word_timestamps=True)
|
||||
words = [x for s in segs for x in (s.words or [])]
|
||||
got = " ".join(x.word.strip() for x in words)
|
||||
pauses = [(words[i].word.strip(), words[i + 1].start - words[i].end)
|
||||
for i in range(len(words) - 1) if (words[i + 1].start - words[i].end) >= 0.25]
|
||||
f0 = librosa.yin(a, fmin=80, fmax=400, sr=sr, frame_length=1024); f0v = f0[(f0 > 90) & (f0 < 380)]
|
||||
med = np.median(f0v) if f0v.size else 0; rng = (np.percentile(f0v, 90) - np.percentile(f0v, 10)) if f0v.size else 0
|
||||
print(f"\n### {name} [{length}] {dur:.1f}s Tempo {len(words)/max(dur,.01):.1f}W/s F0 {med:.0f}Hz/Spanne {rng:.0f}")
|
||||
print(f"SOLL: {text}")
|
||||
print(f"IST : {got}")
|
||||
if pauses:
|
||||
print("PAUSEN: " + ", ".join(f'„{ww}"={gg*1000:.0f}ms' for ww, gg in sorted(pauses, key=lambda t: -t[1])[:6]))
|
||||
print("\n=== STRESSTEST FERTIG ===")
|
||||
Reference in New Issue
Block a user