Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import os | |
| from .config import THEMES | |
| from .tts_utils import get_edge_voices, init_edge_voices | |
| from .capsule_builder import ( | |
| build_capsule, table_capsules, assemble_final, supprimer_capsule, deplacer_capsule | |
| ) | |
| def build_ui(): | |
| print("[INIT] Lancement de Gradio...") | |
| init_edge_voices() | |
| with gr.Blocks(title="Créateur de Capsules CPAS – Version avec vidéo présentateur", | |
| theme=gr.themes.Soft()) as demo: | |
| gr.Markdown("## 🎬 Créateur de Capsules CPAS – Version avec vidéo présentateur") | |
| gr.Markdown("**Nouveau** : Utilisez directement une vidéo de présentateur au lieu d'une image.") | |
| with gr.Tab("Créer une capsule"): | |
| with gr.Row(): | |
| with gr.Column(): | |
| image_fond = gr.Image(label="🖼 Image de fond", type="filepath") | |
| fond_mode = gr.Radio(["plein écran", "moitié gauche", "moitié droite", "moitié bas"], | |
| label="Mode d'affichage du fond", value="plein écran") | |
| logo_path = gr.Image(label="🏛 Logo", type="filepath") | |
| logo_pos = gr.Radio(["haut-gauche","haut-droite","centre"], | |
| label="Position logo", value="haut-gauche") | |
| video_presentateur = gr.File(label="🎬 Vidéo ou image du présentateur", type="filepath") | |
| position_presentateur = gr.Radio(["bas-droit","bas-gauche","haut-droit","haut-gauche","centre"], | |
| label="Position", value="bas-droit") | |
| plein = gr.Checkbox(label="Plein écran", value=False) | |
| with gr.Column(): | |
| titre = gr.Textbox(label="Titre", value="") | |
| sous_titre = gr.Textbox(label="Sous-titre", value="") | |
| theme = gr.Radio(list(THEMES.keys()), label="Thème", value="Bleu Professionnel") | |
| langue = gr.Radio(["fr", "nl"], label="Langue de la voix", value="fr") | |
| def maj_voix(lang): | |
| try: | |
| voices = get_edge_voices(lang) | |
| return gr.update(choices=voices, value=voices[0] if voices else None) | |
| except Exception: | |
| return gr.update(choices=[], value=None) | |
| speaker_id = gr.Dropdown( | |
| label="🎙 Voix Edge-TTS", | |
| choices=get_edge_voices("fr"), | |
| value="fr-FR-DeniseNeural", | |
| info="Liste dynamique des voix Edge-TTS (FR & NL)" | |
| ) | |
| langue.change(maj_voix, [langue], [speaker_id]) | |
| voix_type = gr.Radio(["Féminine","Masculine"], label="Voix IA", value="Féminine") | |
| moteur_voix = gr.Radio(["Edge-TTS (recommandé)", "gTTS (fallback)"], | |
| label="Moteur voix", value="Edge-TTS (recommandé)") | |
| texte_voix = gr.Textbox(label="Texte voix off", lines=4, | |
| value="") | |
| texte_ecran = gr.Textbox(label="Texte à l'écran", lines=4, | |
| value="") | |
| btn = gr.Button("🎬 Créer Capsule", variant="primary") | |
| sortie = gr.Video(label="Capsule générée") | |
| srt_out = gr.File(label="Sous-titres .srt") | |
| statut = gr.Markdown() | |
| with gr.Tab("Gestion & Assemblage"): | |
| gr.Markdown("### 🗂 Gestion des capsules") | |
| liste = gr.Dataframe( | |
| headers=["N°","Titre","Langue","Durée","Thème","Voix","Fichier"], | |
| value=table_capsules(), | |
| interactive=False | |
| ) | |
| with gr.Row(): | |
| index = gr.Number(label="Index capsule", value=1, precision=0) | |
| btn_up = gr.Button("⬆️ Monter") | |
| btn_down = gr.Button("⬇️ Descendre") | |
| btn_del = gr.Button("🗑 Supprimer") | |
| message = gr.Markdown() | |
| btn_up.click(lambda i: deplacer_capsule(i, "up"), [index], [message, liste]) | |
| btn_down.click(lambda i: deplacer_capsule(i, "down"), [index], [message, liste]) | |
| btn_del.click(supprimer_capsule, [index], [message, liste]) | |
| gr.Markdown("### 🎬 Assemblage final") | |
| btn_asm = gr.Button("🎥 Assembler la vidéo complète", variant="primary") | |
| sortie_finale = gr.Video(label="Vidéo finale") | |
| btn_asm.click(lambda: assemble_final(), [], [sortie_finale, message]) | |
| # --- Export ZIP intégré --- | |
| from .capsule_builder import export_project_zip | |
| btn_zip = gr.Button("📦 Télécharger projet complet (ZIP)", variant="secondary") | |
| zip_file = gr.File(label="ZIP exporté") | |
| def zip_action(): | |
| path = export_project_zip() | |
| if path and os.path.exists(path): | |
| return path | |
| else: | |
| raise gr.Error("Erreur : impossible de générer le ZIP.") | |
| btn_zip.click(zip_action, [], [zip_file]) | |
| def creer_capsule_ui(t, st, tv, te, th, img, fmode, logo, pos_logo, vp, vx, pos_p, plein, motor, lang, speaker): | |
| try: | |
| vid, msg, srt = build_capsule(t, st, tv, te, th, | |
| img, logo, pos_logo, fmode, | |
| vp, vx, pos_p, plein, | |
| motor, lang, speaker=speaker) | |
| return vid, srt, msg, table_capsules() | |
| except Exception as e: | |
| import traceback | |
| return None, None, f"❌ Erreur: {e}\n\n{traceback.format_exc()}", table_capsules() | |
| btn.click( | |
| creer_capsule_ui, | |
| [titre, sous_titre, texte_voix, texte_ecran, theme, | |
| image_fond, fond_mode, logo_path, logo_pos, | |
| video_presentateur, voix_type, position_presentateur, | |
| plein, moteur_voix, langue, speaker_id], | |
| [sortie, srt_out, statut, liste] | |
| ) | |
| return demo | |