File size: 6,294 Bytes
baaf343
947c9b1
 
baaf343
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56ea4f9
26908ae
 
 
baaf343
26908ae
 
baaf343
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26908ae
baaf343
26908ae
baaf343
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
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