Spaces:
Sleeping
Sleeping
github-actions[bot]
Deploy from Achraf-cyber/hackton-locallang@33b4b15dab9911f53f924fa89d70b6b276b3cb4c
710ee6f | import pytest | |
| from app.services.translator import Translator | |
| from app.services.tts import TTS | |
| def test_translate_fr_to_dyu_real(): | |
| translator = Translator.get_instance() | |
| result = translator.translate("Bonjour, comment allez-vous ?", src="fr", tgt="dyu") | |
| assert isinstance(result, str) | |
| assert result.strip() != "" | |
| def test_tts_merges_bare_numbered_list_markers(): | |
| """Regression : une liste numerotee ('1. Xxx. 2. Yyy.') donne des segments | |
| '1.'/'2.' de 2 caracteres apres decoupe par phrase ; VITS plante | |
| (narrow(): length must be non-negative) si on les synthetise seuls.""" | |
| # Instanciation directe (pas get_instance()) : construire un TTS ne charge | |
| # aucun modele (lazy par langue), donc pas besoin du mock get_instance() | |
| # utilise pour les autres tests rapides. | |
| tts = TTS() | |
| text = ( | |
| "1. " + ("Allez a la mairie avec vos papiers d identite. " * 6) | |
| + "2. " + ("Presentez votre demande au guichet. " * 6) | |
| ) | |
| assert len(text) > 500 # declenche la decoupe en segments | |
| segments = tts._split_text(text) | |
| assert all(len(s) > 5 for s in segments), segments | |
| def test_tts_packs_multiple_sentences_per_segment(): | |
| """Regression : decouper phrase par phrase cree une coupure de prosodie | |
| audible (redemarrage) ENTRE CHAQUE phrase, pas seulement en fin de texte. | |
| On doit regrouper les phrases par paquets (<=500 caracteres chacun) et ne | |
| couper qu'en cas de depassement, pas a chaque point.""" | |
| tts = TTS() | |
| sentence = "Ceci est une phrase de taille moyenne pour le test. " | |
| text = sentence * 12 # ~624 caracteres, 12 phrases identiques | |
| assert len(text) > 500 | |
| segments = tts._split_text(text) | |
| # Avant le correctif : 12 segments (un par phrase). Le regroupement doit | |
| # produire beaucoup moins de segments que de phrases. | |
| assert len(segments) < 4, segments | |
| assert all(len(s) <= 500 + 60 for s in segments), segments # marge : derniere phrase du paquet | |
| def test_tts_softens_internal_sentence_ends_only(): | |
| """Regression : VITS traite chaque ponctuation finale comme une fin de | |
| discours (intonation descendante + pause longue), meme au milieu d'un | |
| texte. On adoucit donc les points internes en virgule et on garde | |
| uniquement la ponctuation finale du segment.""" | |
| tts = TTS() | |
| result = tts._soften_internal_sentence_ends("Phrase un. Phrase deux ! Phrase trois ?") | |
| assert result == "Phrase un, Phrase deux , Phrase trois ?" | |
| # Une seule phrase : rien a adoucir. | |
| assert tts._soften_internal_sentence_ends("Une seule phrase.") == "Une seule phrase." | |
| def test_tts_normalizes_foreign_chars_for_mos(): | |
| """Regression : le tokenizer VITS de mms-tts-mos SUPPRIME SILENCIEUSEMENT | |
| toute lettre absente de son vocabulaire ('c', 'h', 'j', 'q', 'x' n'y sont | |
| pas). Un nom propre francais non traduit par NLLB (normal : NLLB ne | |
| traduit pas les noms propres) perdait donc des lettres entieres | |
| ('Achraf' -> 'araf'). On les remplace par l'approximation la plus proche | |
| au lieu de les perdre.""" | |
| tts = TTS() | |
| assert tts._normalize_foreign_chars("Achraf", "mos") == "Asraf" | |
| assert tts._normalize_foreign_chars("Jean", "mos") == "zean" | |
| assert tts._normalize_foreign_chars("Cherif", "mos") == "serif" | |
| # Aucune lettre du resultat ne doit etre hors du vocabulaire mos (a part | |
| # l'espace/apostrophe/tiret, toujours autorises). | |
| allowed = tts._get_allowed_chars("mos") | |
| for word in ["Achraf", "Jean", "Cherif", "Québec"]: | |
| normalized = tts._normalize_foreign_chars(word, "mos") | |
| for ch in normalized: | |
| assert ch in allowed or ch.lower() in allowed, (word, normalized, ch) | |
| def test_tts_normalize_foreign_chars_is_noop_for_dyu_native_letters(): | |
| """dyu a deja 'c'/'h'/'j' dans son vocabulaire : un mot les utilisant ne | |
| doit pas etre modifie (contrairement a mos).""" | |
| tts = TTS() | |
| assert tts._normalize_foreign_chars("Achraf", "dyu") == "Achraf" | |
| assert tts._normalize_foreign_chars("Jean", "dyu") == "Jean" | |
| def test_tts_speak_numbered_list_real(): | |
| """Reproduit le crash original avec une vraie synthese VITS.""" | |
| tts = TTS.get_instance() | |
| text = ( | |
| "1. Allez a la mairie avec vos papiers d identite et un justificatif de " | |
| "domicile recent, puis attendez votre tour dans la file d attente prevue " | |
| "a cet effet pour les demandes administratives courantes. " | |
| "2. Presentez votre demande au guichet approprie et attendez votre tour " | |
| "patiemment en respectant les horaires d ouverture affiches devant le " | |
| "batiment principal de la mairie. " | |
| "3. Payez les frais administratifs requis pour le traitement de votre " | |
| "dossier officiel aupres du caissier designe et conservez precieusement " | |
| "votre recu de paiement." | |
| ) | |
| out = tts.speak(text, lang="dyu", output_path="test_numbered_list.wav") | |
| assert out == "test_numbered_list.wav" | |