Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -96,18 +96,34 @@ def _get_kokoro():
|
|
| 96 |
kokoro_pipeline = pipeline("text-to-speech", model="onnx-community/Kokoro-82M-v1.0-ONNX")
|
| 97 |
return kokoro_pipeline
|
| 98 |
|
| 99 |
-
def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 100 |
import soundfile as sf
|
| 101 |
out = os.path.join(TMP_DIR, f"kokoro_{uuid.uuid4().hex}.wav")
|
| 102 |
try:
|
| 103 |
kokoro = _get_kokoro()
|
| 104 |
-
|
|
|
|
|
|
|
|
|
|
| 105 |
sf.write(out, result["audio"], result["sampling_rate"])
|
| 106 |
return out
|
| 107 |
except Exception as e:
|
| 108 |
-
|
| 109 |
return tts_gtts(text, lang=langue)
|
| 110 |
|
|
|
|
| 111 |
def tts_gtts(text: str, lang: str = "fr") -> str:
|
| 112 |
from gtts import gTTS
|
| 113 |
out = os.path.join(TMP_DIR, f"gtts_{uuid.uuid4().hex}.mp3")
|
|
@@ -303,11 +319,15 @@ def build_capsule(titre, sous_titre, texte_voix, texte_ecran, theme,
|
|
| 303 |
fond_mode="plein écran",
|
| 304 |
image_presentateur=None, voix_type="Féminine",
|
| 305 |
position_presentateur="bottom-right", plein=False,
|
| 306 |
-
moteur_voix="Kokoro (HuggingFace, offline)", langue="fr"):
|
| 307 |
|
| 308 |
# 1) TTS
|
| 309 |
engine = "Kokoro" if moteur_voix.startswith("Kokoro") else ("gTTS" if moteur_voix.startswith("gTTS") else "Kokoro")
|
| 310 |
-
audio_mp =
|
|
|
|
|
|
|
|
|
|
|
|
|
| 311 |
audio_wav = _normalize_audio_to_wav(audio_mp)
|
| 312 |
|
| 313 |
# 2) Fond (PIL)
|
|
@@ -449,7 +469,25 @@ with gr.Blocks(title="Créateur de Capsules CPAS – SadTalker + Kokoro",
|
|
| 449 |
titre = gr.Textbox(label="Titre", value="Aide médicale urgente / Dringende medische hulp")
|
| 450 |
sous_titre = gr.Textbox(label="Sous-titre", value="Soins accessibles à tous / Toegankelijke zorg voor iedereen")
|
| 451 |
theme = gr.Radio(list(THEMES.keys()), label="Thème", value="Bleu Professionnel")
|
| 452 |
-
langue = gr.Radio(["fr","nl"], label="Langue de la voix", value="fr")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 453 |
voix_type = gr.Radio(["Féminine","Masculine"], label="Voix IA", value="Féminine")
|
| 454 |
moteur_voix = gr.Radio(
|
| 455 |
["Kokoro (HuggingFace, offline)", "gTTS (en ligne)"],
|
|
@@ -489,12 +527,12 @@ with gr.Blocks(title="Créateur de Capsules CPAS – SadTalker + Kokoro",
|
|
| 489 |
sortie_finale = gr.Video(label="Vidéo finale")
|
| 490 |
btn_asm.click(lambda: assemble_final(), [], [sortie_finale, message])
|
| 491 |
|
| 492 |
-
def creer_capsule_ui(t, st, tv, te, th, img, fmode, logo, pos_logo, ip, vx, pos_p, plein, motor, lang):
|
| 493 |
try:
|
| 494 |
vid, msg, srt = build_capsule(t, st, tv, te, th,
|
| 495 |
img, logo, pos_logo, fmode,
|
| 496 |
ip, vx, pos_p, plein,
|
| 497 |
-
motor, lang)
|
| 498 |
return vid, srt, msg, table_capsules()
|
| 499 |
except Exception as e:
|
| 500 |
return None, None, f"❌ Erreur: {e}\n\n{traceback.format_exc()}", table_capsules()
|
|
@@ -504,9 +542,11 @@ with gr.Blocks(title="Créateur de Capsules CPAS – SadTalker + Kokoro",
|
|
| 504 |
[titre, sous_titre, texte_voix, texte_ecran, theme,
|
| 505 |
image_fond, fond_mode, logo_path, logo_pos,
|
| 506 |
image_presentateur, voix_type, position_presentateur,
|
| 507 |
-
plein, moteur_voix, langue],
|
| 508 |
[sortie, srt_out, statut, liste]
|
| 509 |
)
|
| 510 |
|
|
|
|
|
|
|
| 511 |
if __name__ == "__main__":
|
| 512 |
demo.launch()
|
|
|
|
| 96 |
kokoro_pipeline = pipeline("text-to-speech", model="onnx-community/Kokoro-82M-v1.0-ONNX")
|
| 97 |
return kokoro_pipeline
|
| 98 |
|
| 99 |
+
def get_kokoro_voices(lang="fr"):
|
| 100 |
+
"""Retourne la liste des speakers Kokoro disponibles pour une langue."""
|
| 101 |
+
try:
|
| 102 |
+
from transformers import AutoProcessor
|
| 103 |
+
model_id = "onnx-community/Kokoro-82M-v1.0-ONNX"
|
| 104 |
+
processor = AutoProcessor.from_pretrained(model_id)
|
| 105 |
+
voices = sorted([v for v in processor.speakers if v.startswith(lang)])
|
| 106 |
+
return voices
|
| 107 |
+
except Exception as e:
|
| 108 |
+
print(f"[Kokoro] Impossible de charger les voix ({e})")
|
| 109 |
+
return []
|
| 110 |
+
|
| 111 |
+
def tts_kokoro(text: str, langue: str = "fr", speaker: Optional[str] = None) -> str:
|
| 112 |
import soundfile as sf
|
| 113 |
out = os.path.join(TMP_DIR, f"kokoro_{uuid.uuid4().hex}.wav")
|
| 114 |
try:
|
| 115 |
kokoro = _get_kokoro()
|
| 116 |
+
args = {"text": text}
|
| 117 |
+
if speaker:
|
| 118 |
+
args["speaker_id"] = speaker
|
| 119 |
+
result = kokoro(**args)
|
| 120 |
sf.write(out, result["audio"], result["sampling_rate"])
|
| 121 |
return out
|
| 122 |
except Exception as e:
|
| 123 |
+
print(f"[Kokoro] Erreur TTS: {e}")
|
| 124 |
return tts_gtts(text, lang=langue)
|
| 125 |
|
| 126 |
+
|
| 127 |
def tts_gtts(text: str, lang: str = "fr") -> str:
|
| 128 |
from gtts import gTTS
|
| 129 |
out = os.path.join(TMP_DIR, f"gtts_{uuid.uuid4().hex}.mp3")
|
|
|
|
| 319 |
fond_mode="plein écran",
|
| 320 |
image_presentateur=None, voix_type="Féminine",
|
| 321 |
position_presentateur="bottom-right", plein=False,
|
| 322 |
+
moteur_voix="Kokoro (HuggingFace, offline)", langue="fr",speaker=None):
|
| 323 |
|
| 324 |
# 1) TTS
|
| 325 |
engine = "Kokoro" if moteur_voix.startswith("Kokoro") else ("gTTS" if moteur_voix.startswith("gTTS") else "Kokoro")
|
| 326 |
+
audio_mp = (
|
| 327 |
+
tts_kokoro(texte_voix, langue=langue, speaker=speaker)
|
| 328 |
+
if engine == "Kokoro"
|
| 329 |
+
else tts_gtts(texte_voix, lang=langue)
|
| 330 |
+
)
|
| 331 |
audio_wav = _normalize_audio_to_wav(audio_mp)
|
| 332 |
|
| 333 |
# 2) Fond (PIL)
|
|
|
|
| 469 |
titre = gr.Textbox(label="Titre", value="Aide médicale urgente / Dringende medische hulp")
|
| 470 |
sous_titre = gr.Textbox(label="Sous-titre", value="Soins accessibles à tous / Toegankelijke zorg voor iedereen")
|
| 471 |
theme = gr.Radio(list(THEMES.keys()), label="Thème", value="Bleu Professionnel")
|
| 472 |
+
langue = gr.Radio(["fr", "nl"], label="Langue de la voix", value="fr")
|
| 473 |
+
|
| 474 |
+
def maj_voix(lang):
|
| 475 |
+
try:
|
| 476 |
+
voices = get_kokoro_voices(lang)
|
| 477 |
+
if not voices:
|
| 478 |
+
return gr.update(choices=["(aucune disponible)"], value="(aucune disponible)")
|
| 479 |
+
return gr.update(choices=voices, value=voices[0])
|
| 480 |
+
except Exception as e:
|
| 481 |
+
return gr.update(choices=[], value=None)
|
| 482 |
+
|
| 483 |
+
speaker_id = gr.Dropdown(
|
| 484 |
+
label="👤 Voix / Speaker Kokoro",
|
| 485 |
+
choices=get_kokoro_voices("fr"),
|
| 486 |
+
value=None
|
| 487 |
+
)
|
| 488 |
+
langue.change(maj_voix, [langue], [speaker_id])
|
| 489 |
+
|
| 490 |
+
|
| 491 |
voix_type = gr.Radio(["Féminine","Masculine"], label="Voix IA", value="Féminine")
|
| 492 |
moteur_voix = gr.Radio(
|
| 493 |
["Kokoro (HuggingFace, offline)", "gTTS (en ligne)"],
|
|
|
|
| 527 |
sortie_finale = gr.Video(label="Vidéo finale")
|
| 528 |
btn_asm.click(lambda: assemble_final(), [], [sortie_finale, message])
|
| 529 |
|
| 530 |
+
def creer_capsule_ui(t, st, tv, te, th, img, fmode, logo, pos_logo, ip, vx, pos_p, plein, motor, lang, speaker):
|
| 531 |
try:
|
| 532 |
vid, msg, srt = build_capsule(t, st, tv, te, th,
|
| 533 |
img, logo, pos_logo, fmode,
|
| 534 |
ip, vx, pos_p, plein,
|
| 535 |
+
motor, lang, speaker=speaker)
|
| 536 |
return vid, srt, msg, table_capsules()
|
| 537 |
except Exception as e:
|
| 538 |
return None, None, f"❌ Erreur: {e}\n\n{traceback.format_exc()}", table_capsules()
|
|
|
|
| 542 |
[titre, sous_titre, texte_voix, texte_ecran, theme,
|
| 543 |
image_fond, fond_mode, logo_path, logo_pos,
|
| 544 |
image_presentateur, voix_type, position_presentateur,
|
| 545 |
+
plein, moteur_voix, langue, speaker_id],
|
| 546 |
[sortie, srt_out, statut, liste]
|
| 547 |
)
|
| 548 |
|
| 549 |
+
|
| 550 |
+
|
| 551 |
if __name__ == "__main__":
|
| 552 |
demo.launch()
|