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