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
+63
View File
@@ -0,0 +1,63 @@
# -*- coding: utf-8 -*-
"""Tail-Blip-Killer gegen das End-'taa' (isolierter, leiser Hall nach großer Lücke).
Verifiziert auf kurz/mittel/lang @ lsd6/t0.9: Blip weg, echte Endungen unangetastet."""
import os, numpy as np, soundfile as sf, librosa
from pocket_tts import TTSModel
BASE = r"F:\Coding Stuff\mission-control-2\client\lucy-tts"
OUT = r"C:\Users\TobisPC\Desktop\lucy_tailfix"; os.makedirs(OUT, exist_ok=True)
src, _ = librosa.load(os.path.join(BASE, "ref.mp3"), sr=24000, mono=True)
srt, _ = librosa.effects.trim(src, top_db=30); ref = os.path.join(BASE, "ref.wav")
sf.write(ref, srt[:int(18*24000)], 24000)
SENT = {
"kurz": "Hallo Commander, ich höre dich.",
"mittel":"Guten Morgen, Commander. Das Backup ist sauber durchgelaufen und es gab keine Fehler.",
"lang": "Natürlich kümmere ich mich darum, Commander. Ich starte den Dienst neu, prüfe die Protokolle und melde mich, sobald alles wieder läuft.",
}
def drop_tail_blip(a, sr):
"""Entferne isolierten, leisen/kurzen Schwanz-Blip (Modell-Halluzination)."""
for _ in range(3): # bis zu 3 Blips hintereinander
iv = librosa.effects.split(a, top_db=35)
if len(iv) < 2:
break
speech_rms = float(np.median([np.sqrt(np.mean(a[s:e]**2)) for s, e in iv[:-1]]))
s, e = iv[-1]
last_dur = (e - s) / sr
last_rms = float(np.sqrt(np.mean(a[s:e]**2)))
gap = (s - iv[-2][1]) / sr
# isoliert (große Lücke) UND (kurz ODER deutlich leiser als Sprache) -> Halluzination
if gap > 0.30 and (last_dur < 0.30 or last_rms < 0.45 * speech_rms):
a = a[: iv[-2][1]]
else:
break
return a
def cleanup_v3(a, sr):
a = np.asarray(a, dtype=np.float32).reshape(-1)
if a.size == 0: return a
a = drop_tail_blip(a, sr) # NEU: End-'taa' weg
peak = float(np.max(np.abs(a)))
if peak > 0: a = a * (0.95 / peak)
yt, _ = librosa.effects.trim(a, top_db=45); a = yt if yt.size else a
fi = min(int(0.01*sr), a.size//2)
if fi > 0:
a[:fi] *= np.linspace(0.,1.,fi,dtype=np.float32); a[-fi:] *= np.linspace(1.,0.,fi,dtype=np.float32)
pad = np.zeros(int(0.09*sr), dtype=np.float32)
return np.concatenate([pad, a, pad])
m = TTSModel.load_model(language="german_24l", lsd_decode_steps=6, temp=0.9)
vs = m.get_state_for_audio_prompt(ref); sr = m.sample_rate
for name, text in SENT.items():
raw = m.generate_audio(vs, text, frames_after_eos=4)
raw = raw.numpy() if hasattr(raw,"numpy") else np.asarray(raw)
raw = np.asarray(raw, dtype=np.float32).reshape(-1)
fixed = cleanup_v3(raw, sr)
sf.write(os.path.join(OUT, f"t090_{name}.wav"), fixed, sr)
# Verifikations-Log: letzte Segmente vorher/nachher
iv0 = librosa.effects.split(raw, top_db=35)
print(f"[{name:6}] raw_dur={raw.size/sr:.2f}s -> fixed_dur={fixed.size/sr:.2f}s raw_segmente={len(iv0)}", flush=True)
if len(iv0):
s,e = iv0[-1]; print(f" raw letztes Segment: {s/sr:.2f}..{e/sr:.2f}s rms={np.sqrt(np.mean(raw[s:e]**2)):.3f}", flush=True)
print("TAILFIX_DONE", flush=True)