binaryMao commited on
Commit
14776cb
·
verified ·
1 Parent(s): bd18b66

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +36 -26
app.py CHANGED
@@ -1,6 +1,6 @@
1
  # -*- coding: utf-8 -*-
2
  """
3
- ROBOTSMALI — Sous-titrage Bambara (VERSION COMPLÈTE V6.4 - FORCE OUTPUT)
4
  """
5
  import os
6
  import shlex
@@ -22,6 +22,9 @@ import gradio as gr
22
 
23
  # ---------------------------- # CONFIGURATION # ----------------------------
24
  DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
 
 
 
25
 
26
  MODELS = {
27
  "Soloni V1 (RNNT)": ("RobotsMali/soloni-114m-tdt-ctc-v1", "rnnt"),
@@ -48,7 +51,9 @@ def run_cmd(cmd):
48
 
49
  def load_model(name):
50
  if name in _cache: return _cache[name]
51
- _cache.clear() # Nettoyage RAM
 
 
52
 
53
  repo, mode = MODELS[name]
54
  folder = snapshot_download(repo, local_dir_use_symlinks=False)
@@ -66,12 +71,9 @@ def load_model(name):
66
  return model
67
 
68
  def burn_subtitles(video_path, words, duration):
69
- # SAUVEGARDE LOCALE PERSISTANTE
70
- out_name = f"resultat_final.mp4"
71
- out_path = os.path.join(os.getcwd(), out_name)
72
-
73
- # Nettoyage d'un ancien fichier si présent
74
- if os.path.exists(out_path): os.remove(out_path)
75
 
76
  chunk_size = 7
77
  with tempfile.NamedTemporaryFile(suffix=".srt", mode="w", encoding="utf-8", delete=False) as tf:
@@ -86,8 +88,7 @@ def burn_subtitles(video_path, words, duration):
86
  tf.write(f"{i+1}\n{t_srt(start)} --> {t_srt(end)}\n{txt}\n\n")
87
  srt_name = tf.name
88
 
89
- # Commande FFmpeg forcée sur les codecs web standards
90
- vf = f"subtitles={shlex.quote(srt_name)}:force_style='Fontsize=22,PrimaryColour=&HFFFFFF&'"
91
  cmd = (
92
  f'ffmpeg -hide_banner -loglevel error -y -i {shlex.quote(video_path)} '
93
  f'-vf {shlex.quote(vf)} -c:v libx264 -pix_fmt yuv420p -preset ultrafast -crf 28 '
@@ -101,9 +102,9 @@ def burn_subtitles(video_path, words, duration):
101
 
102
  def pipeline(video_input, model_name):
103
  try:
104
- if not video_input: return "❌ Vidéo introuvable", None, None
105
 
106
- yield "⏳ Phase 1/3 : Analyse Audio...", None, None
107
  wav_path = os.path.abspath("temp_audio.wav")
108
  run_cmd(f'ffmpeg -hide_banner -loglevel error -y -i {shlex.quote(video_input)} -vn -ac 1 -ar 16000 -f wav {shlex.quote(wav_path)}')
109
 
@@ -111,44 +112,53 @@ def pipeline(video_input, model_name):
111
  shell=True, stdout=subprocess.PIPE, text=True).stdout
112
  duration = float(dur_out.strip()) if dur_out.strip() else 10.0
113
 
114
- yield f"⏳ Phase 2/3 : Transcription IA...", None, None
115
  model = load_model(model_name)
116
  res = model.transcribe([wav_path])[0]
117
  text = res.text if hasattr(res, 'text') else str(res)
118
  words = [w for w in text.split() if len(w) > 1]
119
 
120
- if not words: return "⚠️ Pas de parole détectée", None, None
121
 
122
- yield "⏳ Phase 3/3 : Création de la vidéo...", None, None
123
  final_v = burn_subtitles(video_input, words, duration)
124
 
125
- yield "✅ Succès ! Vidéo générée.", final_v, final_v
 
 
126
 
127
  except Exception as e:
128
- yield f"❌ Erreur: {str(e)}", None, None
 
129
 
130
  # ---------------------------- # INTERFACE # ----------------------------
131
 
132
  custom_css = """
133
  body { background-color: #0b0e14; }
134
- .gradio-container { background: rgba(17, 25, 40, 0.9) !important; border-radius: 15px; }
135
- .gr-button-primary { background: #10b981 !important; }
 
136
  """
137
 
138
  with gr.Blocks(css=custom_css, theme=gr.themes.Soft()) as demo:
139
- gr.HTML("<h1 style='color:#facc15; text-align:center;'>🤖 ROBOTSMALI V6.4</h1>")
 
140
 
141
  with gr.Row():
142
  with gr.Column():
143
- v_in = gr.Video(label="Source")
 
144
  m_sel = gr.Dropdown(list(MODELS.keys()), value="Soloba V1 (CTC)", label="Modèle IA")
145
  btn = gr.Button("🚀 GÉNÉRER", variant="primary")
146
  with gr.Column():
147
- status = gr.Markdown("### Statut\n*Prêt*")
148
- v_out = gr.Video(label="Résultat")
149
- f_out = gr.File(label="Télécharger le fichier MP4")
 
150
 
151
  gr.Examples(examples=VIDEO_EXAMPLES, inputs=[v_in, m_sel], cache_examples=False)
152
- btn.click(pipeline, [v_in, m_sel], [status, v_out, f_out])
 
153
 
154
- demo.launch(share=True, debug=True)
 
 
1
  # -*- coding: utf-8 -*-
2
  """
3
+ ROBOTSMALI — Sous-titrage Bambara (VERSION COMPLÈTE V6.5 - INTERFACE ÉPURÉE)
4
  """
5
  import os
6
  import shlex
 
22
 
23
  # ---------------------------- # CONFIGURATION # ----------------------------
24
  DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
25
+ random.seed(1234)
26
+ np.random.seed(1234)
27
+ torch.manual_seed(1234)
28
 
29
  MODELS = {
30
  "Soloni V1 (RNNT)": ("RobotsMali/soloni-114m-tdt-ctc-v1", "rnnt"),
 
51
 
52
  def load_model(name):
53
  if name in _cache: return _cache[name]
54
+ if len(_cache) > 0:
55
+ _cache.clear()
56
+ if torch.cuda.is_available(): torch.cuda.empty_cache()
57
 
58
  repo, mode = MODELS[name]
59
  folder = snapshot_download(repo, local_dir_use_symlinks=False)
 
71
  return model
72
 
73
  def burn_subtitles(video_path, words, duration):
74
+ # Sauvegarde dans le dossier de travail pour la stabilité
75
+ out_name = f"resultat_robotsmali.mp4"
76
+ out_path = os.path.abspath(out_name)
 
 
 
77
 
78
  chunk_size = 7
79
  with tempfile.NamedTemporaryFile(suffix=".srt", mode="w", encoding="utf-8", delete=False) as tf:
 
88
  tf.write(f"{i+1}\n{t_srt(start)} --> {t_srt(end)}\n{txt}\n\n")
89
  srt_name = tf.name
90
 
91
+ vf = f"subtitles={shlex.quote(srt_name)}:force_style='Fontsize=22,PrimaryColour=&HFFFFFF&,OutlineColour=&H000000&'"
 
92
  cmd = (
93
  f'ffmpeg -hide_banner -loglevel error -y -i {shlex.quote(video_path)} '
94
  f'-vf {shlex.quote(vf)} -c:v libx264 -pix_fmt yuv420p -preset ultrafast -crf 28 '
 
102
 
103
  def pipeline(video_input, model_name):
104
  try:
105
+ if not video_input: return "❌ Vidéo introuvable", None
106
 
107
+ yield "⏳ Phase 1/3 : Analyse Audio...", None
108
  wav_path = os.path.abspath("temp_audio.wav")
109
  run_cmd(f'ffmpeg -hide_banner -loglevel error -y -i {shlex.quote(video_input)} -vn -ac 1 -ar 16000 -f wav {shlex.quote(wav_path)}')
110
 
 
112
  shell=True, stdout=subprocess.PIPE, text=True).stdout
113
  duration = float(dur_out.strip()) if dur_out.strip() else 10.0
114
 
115
+ yield f"⏳ Phase 2/3 : Transcription {model_name}...", None
116
  model = load_model(model_name)
117
  res = model.transcribe([wav_path])[0]
118
  text = res.text if hasattr(res, 'text') else str(res)
119
  words = [w for w in text.split() if len(w) > 1]
120
 
121
+ if not words: return "⚠️ Pas de parole détectée", None
122
 
123
+ yield "⏳ Phase 3/3 : Encodage de la vidéo...", None
124
  final_v = burn_subtitles(video_input, words, duration)
125
 
126
+ if os.path.exists(wav_path): os.remove(wav_path)
127
+
128
+ yield "✅ Sous-titrage terminé !", final_v
129
 
130
  except Exception as e:
131
+ traceback.print_exc()
132
+ yield f"❌ Erreur: {str(e)}", None
133
 
134
  # ---------------------------- # INTERFACE # ----------------------------
135
 
136
  custom_css = """
137
  body { background-color: #0b0e14; }
138
+ .gradio-container { background: rgba(17, 25, 40, 0.8) !important; border-radius: 20px; border: 1px solid rgba(255, 255, 255, 0.1); }
139
+ #header { text-align: center; padding: 20px; }
140
+ .gr-button-primary { background: linear-gradient(135deg, #059669, #10b981) !important; border: none !important; }
141
  """
142
 
143
  with gr.Blocks(css=custom_css, theme=gr.themes.Soft()) as demo:
144
+ with gr.Column(elem_id="header"):
145
+ gr.HTML("<h1 style='color:#facc15;'>🤖 ROBOTSMALI</h1><p style='color:#94a3b8;'>Sous-titrage Bambara Intégral</p>")
146
 
147
  with gr.Row():
148
  with gr.Column():
149
+ gr.Markdown("### 📥 Source")
150
+ v_in = gr.Video(label=None, mirror_webcam=False)
151
  m_sel = gr.Dropdown(list(MODELS.keys()), value="Soloba V1 (CTC)", label="Modèle IA")
152
  btn = gr.Button("🚀 GÉNÉRER", variant="primary")
153
  with gr.Column():
154
+ gr.Markdown("### 📤 Résultat")
155
+ status = gr.Markdown("*Prêt*")
156
+ # Une seule case vidéo pour le résultat
157
+ v_out = gr.Video(label="Vidéo finale (lecture et téléchargement)")
158
 
159
  gr.Examples(examples=VIDEO_EXAMPLES, inputs=[v_in, m_sel], cache_examples=False)
160
+
161
+ btn.click(pipeline, [v_in, m_sel], [status, v_out])
162
 
163
+ if __name__ == "__main__":
164
+ demo.launch(share=True, debug=True)