mohamedlabed commited on
Commit
3889c5a
·
verified ·
1 Parent(s): 367e71a

Upload app_fixed_robust.py

Browse files
Files changed (1) hide show
  1. app_fixed_robust.py +340 -0
app_fixed_robust.py ADDED
@@ -0,0 +1,340 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Educational AI Assistant for Arabic Lessons - Hugging Face Spaces Version
4
+ Spécialement optimisée pour la reconnaissance vocale arabe
5
+ Version avec gestion d'erreurs renforcée
6
+ """
7
+
8
+ import gradio as gr
9
+ import torch
10
+ import os
11
+ import tempfile
12
+ import warnings
13
+ import gc
14
+ import time
15
+
16
+ warnings.filterwarnings("ignore")
17
+
18
+ # Fonction pour libérer la mémoire GPU
19
+ def clear_gpu_memory():
20
+ """Libère la mémoire GPU."""
21
+ if torch.cuda.is_available():
22
+ torch.cuda.empty_cache()
23
+ gc.collect()
24
+ print("Mémoire GPU libérée")
25
+
26
+ # Fonction pour extraire l'audio d'une vidéo
27
+ def extract_audio(video_path):
28
+ """Extrait l'audio d'un fichier vidéo."""
29
+ try:
30
+ import ffmpeg
31
+ audio_path = tempfile.mktemp(suffix=".wav")
32
+ print(f"Extraction de l'audio depuis {video_path} vers {audio_path}")
33
+
34
+ # Commande ffmpeg simplifiée
35
+ (ffmpeg
36
+ .input(video_path)
37
+ .output(audio_path,
38
+ acodec='pcm_s16le', # Format PCM non compressé
39
+ ac=1, # Mono
40
+ ar='16k') # 16kHz (optimal pour Whisper)
41
+ .run(capture_stdout=True, capture_stderr=True, overwrite_output=True))
42
+
43
+ print("Extraction audio réussie")
44
+ return audio_path
45
+ except Exception as e:
46
+ print(f"Erreur lors de l'extraction audio: {e}")
47
+ return None
48
+
49
+ # Fonction pour transcrire l'audio
50
+ def transcribe_audio(audio_path, progress=None):
51
+ """Transcrit l'audio arabe."""
52
+ if not audio_path:
53
+ return "Veuillez télécharger un fichier audio ou vidéo."
54
+
55
+ if progress:
56
+ progress(0.3, "Chargement du modèle ASR spécialisé pour l'arabe...")
57
+
58
+ try:
59
+ from transformers import pipeline
60
+
61
+ # Utiliser un modèle spécialisé pour l'arabe
62
+ model_name = "Salama1429/KalemaTech-Arabic-STT-ASR-based-on-Whisper-Small"
63
+
64
+ # Déterminer l'appareil à utiliser
65
+ device = "cuda:0" if torch.cuda.is_available() else "cpu"
66
+ print(f"Utilisation de l'appareil: {device}")
67
+
68
+ # Paramètres ultra-légers pour éviter les problèmes de mémoire
69
+ asr = pipeline(
70
+ "automatic-speech-recognition",
71
+ model=model_name,
72
+ chunk_length_s=10, # Chunks courts
73
+ batch_size=4, # Petit batch
74
+ device=device,
75
+ )
76
+
77
+ if progress:
78
+ progress(0.5, "Transcription en cours...")
79
+
80
+ print(f"Transcription du fichier audio: {audio_path}")
81
+ result = asr(audio_path, generate_kwargs={"language": "arabic"})
82
+
83
+ # Vérification robuste du résultat
84
+ if result and isinstance(result, dict) and "text" in result:
85
+ transcription = result["text"]
86
+ print("Transcription réussie")
87
+ else:
88
+ print("Format de résultat inattendu")
89
+ transcription = ""
90
+
91
+ # Nettoyage des fichiers temporaires
92
+ if "temp" in audio_path and os.path.exists(audio_path):
93
+ try:
94
+ os.remove(audio_path)
95
+ print(f"Fichier audio temporaire supprimé: {audio_path}")
96
+ except Exception as e:
97
+ print(f"Erreur lors de la suppression du fichier temporaire: {e}")
98
+
99
+ return transcription if transcription else "La transcription a échoué ou l'audio était silencieux."
100
+
101
+ except Exception as e:
102
+ print(f"Erreur pendant la transcription: {e}")
103
+ # Nettoyage des fichiers temporaires en cas d'erreur
104
+ if "temp" in audio_path and os.path.exists(audio_path):
105
+ try:
106
+ os.remove(audio_path)
107
+ except:
108
+ pass
109
+
110
+ return f"La transcription a échoué: {str(e)}"
111
+
112
+ # Fonction pour résumer le texte
113
+ def summarize_text(text, progress=None):
114
+ """Résume le texte arabe en entrée."""
115
+ if not text or not isinstance(text, str) or "transcription a échoué" in text.lower():
116
+ return "Veuillez fournir un texte à résumer (transcription nécessaire d'abord)."
117
+
118
+ if progress:
119
+ progress(0.6, "Chargement du modèle de résumé...")
120
+
121
+ try:
122
+ from transformers import pipeline
123
+
124
+ # Libérer la mémoire avant de charger un nouveau modèle
125
+ clear_gpu_memory()
126
+
127
+ # Utiliser un modèle de résumé pour l'arabe
128
+ model_name = "malmarjeh/t5-arabic-text-summarization"
129
+ device = "cuda:0" if torch.cuda.is_available() else "cpu"
130
+
131
+ summarizer = pipeline("summarization", model=model_name, device=device)
132
+
133
+ if progress:
134
+ progress(0.7, "Génération du résumé...")
135
+
136
+ print("Résumé du texte en cours...")
137
+
138
+ # Vérifier que le texte n'est pas vide
139
+ if not text.strip():
140
+ return "Le texte à résumer est vide."
141
+
142
+ # Limiter la longueur du texte pour éviter les problèmes de mémoire
143
+ max_input_length = 1024
144
+ if len(text) > max_input_length:
145
+ text = text[:max_input_length]
146
+ print(f"Texte tronqué à {max_input_length} caractères pour éviter les problèmes de mémoire")
147
+
148
+ # Vérification robuste du résultat
149
+ summary_result = summarizer(text, max_length=150, min_length=30, do_sample=False)
150
+
151
+ if summary_result and isinstance(summary_result, list) and len(summary_result) > 0 and 'summary_text' in summary_result[0]:
152
+ summary = summary_result[0]['summary_text']
153
+ print("Résumé réussi")
154
+ return summary
155
+ else:
156
+ print("Format de résultat de résumé inattendu")
157
+ return "Le résumé a échoué en raison d'un format de résultat inattendu."
158
+ except Exception as e:
159
+ print(f"Erreur pendant le résumé: {e}")
160
+ return f"Le résumé a échoué: {str(e)}"
161
+
162
+ # Fonction pour générer des questions
163
+ def generate_questions(text, progress=None):
164
+ """Génère des questions basées sur le texte arabe."""
165
+ if not text or not isinstance(text, str) or "transcription a échoué" in text.lower():
166
+ return "Veuillez fournir un texte pour générer des questions."
167
+
168
+ if progress:
169
+ progress(0.8, "Génération des questions...")
170
+
171
+ try:
172
+ # Version simplifiée avec des questions génériques
173
+ questions = """1. ما هي الفكرة الرئيسية للدرس؟
174
+ 2. ما هي أهم المفاهيم التي تم شرحها في هذا الدرس؟
175
+ 3. كيف يمكن تطبيق المعلومات الواردة في هذا الدرس في الحياة العملية؟
176
+ 4. ما هي العلاقة بين المفاهيم المختلفة التي تم تقديمها؟
177
+ 5. لو طلب منك تلخيص هذا الدرس في ثلاث نقاط، ماذا ستكتب؟"""
178
+
179
+ return questions
180
+ except Exception as e:
181
+ print(f"Erreur dans generate_questions: {e}")
182
+ return f"Erreur lors de la génération des questions: {str(e)}"
183
+
184
+ # Fonction pour générer une carte mentale
185
+ def generate_mind_map(text, progress=None):
186
+ """Génère une représentation de carte mentale simple."""
187
+ if not text or not isinstance(text, str) or "transcription a échoué" in text.lower():
188
+ return "Veuillez fournir un texte pour générer une carte mentale."
189
+
190
+ if progress:
191
+ progress(0.9, "Création de la carte mentale...")
192
+
193
+ try:
194
+ # Version ultra-simplifiée avec vérification des indices
195
+ lines = text.split('.')
196
+
197
+ # Création d'une structure Markdown basique
198
+ markdown_map = "# خريطة ذهنية للدرس\n\n"
199
+
200
+ # Titre principal - avec vérification que lines n'est pas vide
201
+ if lines and len(lines) > 0 and lines[0].strip():
202
+ main_idea = lines[0].strip()[:100] + ("..." if len(lines[0]) > 100 else "")
203
+ markdown_map += f"## الموضوع الرئيسي\n- {main_idea}\n\n"
204
+ else:
205
+ markdown_map += f"## الموضوع الرئيسي\n- (لم يتم العثور على موضوع رئيسي)\n\n"
206
+
207
+ # Points principaux (limités à 3 pour simplicité)
208
+ markdown_map += "## النقاط الرئيسية\n\n"
209
+
210
+ # Vérifier s'il y a des lignes supplémentaires
211
+ if len(lines) > 1:
212
+ count = 0
213
+ for line in lines[1:]:
214
+ if line and line.strip() and len(line.strip()) > 15:
215
+ point_text = line.strip()[:80] + ("..." if len(line) > 80 else "")
216
+ markdown_map += f"### نقطة {count+1}\n- {point_text}\n\n"
217
+ count += 1
218
+ if count >= 3:
219
+ break
220
+
221
+ # Si aucun point n'a été trouvé, ajouter un message
222
+ if "### نقطة" not in markdown_map:
223
+ markdown_map += "### ملاحظة\n- لم يتم العثور على نقاط رئيسية كافية في النص\n\n"
224
+
225
+ return markdown_map
226
+ except Exception as e:
227
+ print(f"Erreur dans generate_mind_map: {e}")
228
+ return f"Erreur lors de la création de la carte mentale: {str(e)}"
229
+
230
+ # Fonction principale de traitement
231
+ def process_lesson(file_obj, progress=gr.Progress()):
232
+ """Traite le fichier audio/vidéo avec une approche ultra-légère."""
233
+ if file_obj is None:
234
+ return "Veuillez télécharger un fichier.", "", "", ""
235
+
236
+ try:
237
+ progress(0.1, "Préparation du traitement...")
238
+
239
+ file_path = file_obj.name
240
+ file_name, file_extension = os.path.splitext(file_path)
241
+ file_extension = file_extension.lower()
242
+
243
+ audio_path = None
244
+ progress(0.2, "Préparation du fichier...")
245
+
246
+ # Traitement du fichier selon son type
247
+ try:
248
+ if file_extension in ['.mp4', '.mov', '.avi', '.mkv']:
249
+ audio_path = extract_audio(file_path)
250
+ if not audio_path:
251
+ return "Échec de l'extraction audio.", "", "", ""
252
+ elif file_extension in ['.mp3', '.wav', '.ogg', '.flac', '.m4a']:
253
+ audio_path = file_path
254
+ else:
255
+ return f"Type de fichier non pris en charge: {file_extension}. Veuillez télécharger un fichier audio ou vidéo.", "", "", ""
256
+ except Exception as e:
257
+ print(f"Erreur lors de la préparation du fichier: {e}")
258
+ return f"Erreur lors de la préparation du fichier: {str(e)}", "", "", ""
259
+
260
+ # 1. Transcription
261
+ try:
262
+ transcription = transcribe_audio(audio_path, progress)
263
+ except Exception as e:
264
+ print(f"Erreur lors de la transcription: {e}")
265
+ transcription = f"La transcription a échoué: {str(e)}"
266
+
267
+ # Libérer la mémoire après transcription
268
+ clear_gpu_memory()
269
+
270
+ # 2. Résumé (seulement si la transcription a réussi)
271
+ try:
272
+ if isinstance(transcription, str) and "échoué" not in transcription.lower():
273
+ summary = summarize_text(transcription, progress)
274
+ else:
275
+ summary = "Impossible de générer un résumé car la transcription a échoué."
276
+ except Exception as e:
277
+ print(f"Erreur lors du résumé: {e}")
278
+ summary = f"Le résumé a échoué: {str(e)}"
279
+
280
+ # Libérer la mémoire après résumé
281
+ clear_gpu_memory()
282
+
283
+ # 3. Génération de questions (simplifiée)
284
+ try:
285
+ questions = generate_questions(transcription, progress)
286
+ except Exception as e:
287
+ print(f"Erreur lors de la génération des questions: {e}")
288
+ questions = f"La génération des questions a échoué: {str(e)}"
289
+
290
+ # 4. Génération de la carte mentale (simplifiée)
291
+ try:
292
+ mind_map = generate_mind_map(summary, progress)
293
+ except Exception as e:
294
+ print(f"Erreur lors de la génération de la carte mentale: {e}")
295
+ mind_map = f"La génération de la carte mentale a échoué: {str(e)}"
296
+
297
+ progress(1.0, "Terminé!")
298
+ return transcription, summary, questions, mind_map
299
+
300
+ except Exception as e:
301
+ print(f"Erreur générale: {e}")
302
+ return f"Une erreur s'est produite: {str(e)}", "", "", ""
303
+
304
+ # Interface Gradio simplifiée
305
+ def create_interface():
306
+ with gr.Blocks(theme=gr.themes.Soft(), title="مساعد الدروس بالذكاء الاصطناعي") as demo:
307
+ gr.Markdown("## مساعد الدروس بالذكاء الاصطناعي")
308
+ gr.Markdown("قم برفع ملف صوتي أو فيديو لدرس باللغة العربية، وسيقوم التطبيق بتحويله إلى نص، تلخيصه، توليد أسئلة، وإنشاء خريطة ذهنية.")
309
+
310
+ with gr.Row():
311
+ input_file = gr.File(label="رفع ملف الدرس (صوت أو فيديو)", file_types=["audio", "video"])
312
+
313
+ process_button = gr.Button("معالجة الدرس")
314
+
315
+ with gr.Tabs():
316
+ with gr.TabItem("النص الكامل"):
317
+ output_transcription = gr.Textbox(label="النص المكتوب للدرس", lines=15, interactive=False)
318
+ with gr.TabItem("الملخص"):
319
+ output_summary = gr.Textbox(label="ملخص الدرس", lines=10, interactive=False)
320
+ with gr.TabItem("أسئلة الفهم"):
321
+ output_questions = gr.Textbox(label="أسئلة مقترحة", lines=10, interactive=False)
322
+ with gr.TabItem("الخريطة الذهنية"):
323
+ output_mindmap = gr.Markdown(label="خريطة ذهنية (بصيغة ماركداون)")
324
+
325
+ process_button.click(
326
+ fn=process_lesson,
327
+ inputs=input_file,
328
+ outputs=[output_transcription, output_summary, output_questions, output_mindmap]
329
+ )
330
+
331
+ gr.Markdown("--- Developed with AI ---")
332
+
333
+ return demo
334
+
335
+ # Point d'entrée principal pour Hugging Face Spaces
336
+ demo = create_interface()
337
+
338
+ # Cette ligne est nécessaire pour Hugging Face Spaces
339
+ if __name__ == "__main__":
340
+ demo.launch()