mirror of
https://github.com/R0m1k3/Socialflow.git
synced 2026-10-17 04:09:51 +02:00
Intonation : - Gemini reçoit une température basse et une graine fixe (réglables) : la lecture ne change plus de ton d'une génération à l'autre - SRT : tout le texte est lu d'une seule traite puis découpé phrase par phrase, au lieu d'une génération (et d'une intonation) par sous-titre ; un seul traitement de niveau, plus de sauts de volume entre les phrases Mots coupés : - La voix est découpée dans ses vrais silences (silencedetect), plus aux bornes des mots estimées par Whisper qui rognaient les syllabes ; fondus de 10 ms aux coupes - Whisper n'est plus amorcé avec le texte attendu : il hallucinait des répétitions qui masquaient les fins tronquées Fiabilité : - Chaque voix Gemini est réécoutée : mots sautés, fin tronquée ou consigne lue à voix haute déclenchent une nouvelle génération (3 au plus), puis repli sur Edge avec avertissement - Consigne de lecture intégrale ajoutée au prompt Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018Ze4bs7tpF1KGWUk6ZZSZ4
42 lines
1.5 KiB
Python
42 lines
1.5 KiB
Python
from app.align import Word
|
|
from app.quality import check_reading, cut_point, parse_silences, speech_bounds
|
|
|
|
|
|
def _heard(text: str) -> list[Word]:
|
|
return [Word(t, i * 0.3, i * 0.3 + 0.25) for i, t in enumerate(text.split())]
|
|
|
|
|
|
def test_complete_reading_is_accepted():
|
|
check = check_reading(
|
|
"Découvrez nos nouveautés en magasin", _heard("découvrez nos nouveautés en magasin")
|
|
)
|
|
assert check.acceptable and check.coverage == 1.0
|
|
|
|
|
|
def test_truncated_ending_is_rejected():
|
|
check = check_reading("Découvrez nos nouveautés en magasin", _heard("découvrez nos nouveautés"))
|
|
assert not check.ending_ok and not check.acceptable
|
|
|
|
|
|
def test_instruction_read_aloud_is_rejected():
|
|
heard = _heard("lis ce texte sur un ton dynamique découvrez nos nouveautés en magasin")
|
|
assert not check_reading("Découvrez nos nouveautés en magasin", heard).acceptable
|
|
|
|
|
|
def test_silences_are_parsed_from_ffmpeg_log():
|
|
log = (
|
|
"[silencedetect] silence_start: 0\n[silencedetect] silence_end: 0.21 | silence_duration: 0.21\n"
|
|
"[silencedetect] silence_start: 1.5\n"
|
|
)
|
|
assert parse_silences(log, 2.0) == [(0.0, 0.21), (1.5, 2.0)]
|
|
|
|
|
|
def test_speech_bounds_drop_leading_and_trailing_silence():
|
|
start, end = speech_bounds([(0.0, 0.3), (1.5, 2.0)], 2.0, pad=0.1)
|
|
assert round(start, 3) == 0.2 and round(end, 3) == 1.6
|
|
|
|
|
|
def test_cut_point_prefers_the_longest_nearby_silence():
|
|
assert cut_point([(1.0, 1.1), (1.2, 1.8)], after=1.0, before=1.9) == 1.5
|
|
assert cut_point([], after=1.0, before=2.0) == 1.5
|