fix(voice): §7 — coupe-silence + troncature phrase (anti mot parasite)
Le cap dur à 16s coupait la réf en plein mot ; l'auto-ASR transcrivait le bout tronqué (ex. 'présenter') et OmniVoice le recrachait en tête de chaque génération. - prepare_wav : couper sur une frontière de silence (librosa.effects.split), jamais à cap brut → clip finit en silence, mots entiers. - enroll : tronquer ref_text à la dernière phrase complète (. ! ?). Validé sur le consentement réel de richard : 24.4s→15.7s, ref_text finit '…des oiseaux.' (plus de mot parasite). NB : voix enrôlées avec l'ancien cap = à ré-enrôler. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
6640cfd79e
commit
0bf399cb79
|
|
@ -27,12 +27,24 @@ class EnrollmentError(RuntimeError):
|
|||
|
||||
def prepare_wav(in_path: str, out_path: str, target_s: float = OV_TARGET_S) -> dict:
|
||||
import librosa, soundfile as sf
|
||||
cap = min(target_s, _HARD_MAX_S)
|
||||
y, _ = librosa.load(in_path, sr=_PREP_SR, mono=True)
|
||||
orig_s = len(y) / _PREP_SR
|
||||
yt, _ = librosa.effects.trim(y, top_db=30)
|
||||
if yt.size == 0:
|
||||
yt = y
|
||||
yt = yt[: int(min(target_s, _HARD_MAX_S) * _PREP_SR)]
|
||||
# §7 FIX : couper sur une FRONTIÈRE DE SILENCE, jamais à `cap` brut (= en plein mot,
|
||||
# ce qui faisait recracher le dernier mot tronqué en tête de chaque génération).
|
||||
# Garder les segments non-silencieux jusqu'à ~cap, finir à la fin du dernier segment.
|
||||
end = 0
|
||||
for _s, e in librosa.effects.split(yt, top_db=30):
|
||||
if e / _PREP_SR <= cap:
|
||||
end = e
|
||||
else:
|
||||
break
|
||||
if end == 0: # un seul long segment → repli au cap dur
|
||||
end = min(len(yt), int(cap * _PREP_SR))
|
||||
yt = yt[:end]
|
||||
final_s = len(yt) / _PREP_SR
|
||||
sf.write(out_path, yt, _PREP_SR, subtype="PCM_16")
|
||||
return {"orig_s": round(orig_s, 1), "final_s": round(final_s, 1), "too_short": final_s < _MIN_WARN_S}
|
||||
|
|
@ -81,6 +93,12 @@ def enroll(wav_path: str, text: str, out_path: str) -> dict:
|
|||
if C != 8:
|
||||
raise EnrollmentError(f"attendu 8 codebooks, eu {C}")
|
||||
ref_text = (getattr(vcp, "ref_text", "") or text or "").strip()
|
||||
# §7 FIX (ceinture+bretelles) : tronquer à la dernière phrase complète (. ! ?), pour
|
||||
# qu'un éventuel mot tronqué de fin de réf ne soit jamais recraché en tête de synthèse.
|
||||
import re
|
||||
_ends = list(re.finditer(r"[.!?]", ref_text))
|
||||
if _ends:
|
||||
ref_text = ref_text[: _ends[-1].end()].strip()
|
||||
txt = ref_text.encode("utf-8")
|
||||
os.makedirs(os.path.dirname(os.path.abspath(out_path)), exist_ok=True)
|
||||
with open(out_path, "wb") as f:
|
||||
|
|
|
|||
Loading…
Reference in New Issue