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:
Hitonabi
2026-07-02 10:29:33 +02:00
parent aff0105700
commit 09a1c98514
49 changed files with 8231 additions and 0 deletions
+47
View File
@@ -0,0 +1,47 @@
# -*- coding: utf-8 -*-
"""ABSCHLUSS-TEST: beweist die Prompt-Wirkung. Dieselbe Lucy-Antwort im NEUEN Stil (kurze Sätze,
Punkte) vs. ALTEM Stil (Komma-Kette). Rendert auf :8134 + Desktop, misst Pausen (Whisper)."""
import os, io, json, urllib.request
import numpy as np, soundfile as sf
from faster_whisper import WhisperModel
SERVER = "http://127.0.0.1:8134/tts"
OUT = os.path.join(os.path.expanduser("~"), "Desktop", "lucy_test"); os.makedirs(OUT, exist_ok=True)
# Gleicher Inhalt, zwei Stile — so würde Lucy VORHER (Komma-Kette) und NACHHER (Prompt: kurze Sätze) antworten.
PAIRS = [
("A_backup",
"Klar, Commander, das Backup ist heute Nacht durchgelaufen, es gab keine Fehler, und die Datenbank läuft stabil bei 92 Prozent.",
"Klar, Commander. Das Backup lief heute Nacht durch. Keine Fehler. Die Datenbank ist stabil bei 92 Prozent."),
("B_status",
"Also, wenn ich das kurz zusammenfasse, die Verbindung war weg, dann lief das Update durch, danach musste ich neu starten, und jetzt sind alle Dienste wieder oben.",
"Kurz zusammengefasst, Commander. Die Verbindung war weg. Das Update lief durch. Ich musste neu starten. Jetzt sind alle Dienste wieder oben."),
]
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")
def measure(tag, text):
wav = render(text); path = os.path.join(OUT, tag + ".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 [])]
gaps = [words[i+1].start - words[i].end for i in range(len(words)-1)]
lang = [(words[i].word.strip(), gaps[i]) for i in range(len(gaps)) if gaps[i] >= 0.30]
total_pause = sum(g for g in gaps if g >= 0.15)
return dur, len(lang), total_pause, lang
for name, alt, neu in PAIRS:
d_a, n_a, tp_a, l_a = measure(f"{name}_ALT_komma", alt)
d_n, n_n, tp_n, l_n = measure(f"{name}_NEU_kurz", neu)
print(f"\n### {name}")
print(f" ALT (Komma-Kette): {d_a:4.1f}s | {n_a} LANG-Pausen | Summe Pausen {tp_a*1000:4.0f}ms")
print(f" LANG: " + (", ".join(f'{ww}\"={gg*1000:.0f}ms' for ww, gg in l_a) or "keine"))
print(f" NEU (kurze Sätze): {d_n:4.1f}s | {n_n} LANG-Pausen | Summe Pausen {tp_n*1000:4.0f}ms")
print(f" LANG: " + (", ".join(f'{ww}\"={gg*1000:.0f}ms' for ww, gg in l_n) or "keine"))
print(f" -> {d_a-d_n:+.1f}s Dauer, {tp_a*1000-tp_n*1000:+.0f}ms Pausen-Summe")
print("\n=== ABSCHLUSS-TEST FERTIG === (WAVs im Desktop\\lucy_test)")