KIMOSSINO commited on
Commit
f79c89e
·
verified ·
1 Parent(s): 618c56b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +116 -304
app.py CHANGED
@@ -1,339 +1,151 @@
 
1
  import gradio as gr
2
  import whisper
3
- import os
4
- import asyncio
5
- import edge_tts
6
- from transformers import pipeline
7
- from deep_translator import GoogleTranslator
8
- from docx import Document
9
- import tempfile
10
- from datetime import datetime
11
- import logging
12
- import sys
13
 
14
- # إعداد التسجيل
15
- logging.basicConfig(
16
- level=logging.INFO,
17
- format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
18
- handlers=[
19
- logging.FileHandler('app.log'),
20
- logging.StreamHandler(sys.stdout)
21
- ]
22
- )
23
- logger = logging.getLogger(__name__)
24
 
25
- # قائمة اللغات المدعومة
26
  SUPPORTED_LANGUAGES = {
27
- 'ar': 'العربية',
28
- 'en': 'English',
29
- 'fr': 'Français',
30
- 'es': 'Español',
31
- 'de': 'Deutsch'
32
  }
33
 
34
- # تعيين أصوات لكل لغة
35
- VOICE_MAPPINGS = {
36
- 'ar': 'ar-EG-ShakirNeural',
37
- 'en': 'en-US-EricNeural',
38
- 'fr': 'fr-FR-HenriNeural',
39
- 'es': 'es-ES-AlvaroNeural',
40
- 'de': 'de-DE-ConradNeural'
 
41
  }
42
 
43
- # تحديد اللغات RTL
44
- RTL_LANGUAGES = ['ar']
45
-
46
- async def generate_speech(text, lang):
47
- """توليد الصوت باستخدام edge-tts"""
48
- try:
49
- voice = VOICE_MAPPINGS.get(lang, 'en-US-EricNeural')
50
- communicate = edge_tts.Communicate(text, voice)
51
-
52
- audio_path = tempfile.mktemp(suffix='.mp3')
53
- await communicate.save(audio_path)
54
-
55
- # التحقق من وجود الملف وحجمه
56
- if os.path.exists(audio_path) and os.path.getsize(audio_path) > 0:
57
- logger.info(f"تم إنشاء ملف صوتي: {audio_path}")
58
- return audio_path
59
- else:
60
- logger.error("فشل إنشاء ملف صوتي صالح")
61
- return None
62
-
63
- except Exception as e:
64
- logger.error(f"خطأ في توليد الصوت: {str(e)}")
65
- return None
66
-
67
- def text_to_speech(text, lang, progress=gr.Progress()):
68
- """واجهة لتحويل النص إلى صوت"""
69
- if not text:
70
- logger.warning("لم يتم تقديم نص للتحويل إلى صوت")
71
- return None
72
-
73
- try:
74
- progress(0.2, desc="جاري تجهيز الصوت...")
75
- logger.info(f"بدء تحويل النص إلى صوت باللغة: {lang}")
76
-
77
- # تقسيم النص إلى أجزاء إذا كان طويلاً
78
- max_length = 1000
79
- text_parts = [text[i:i+max_length] for i in range(0, len(text), max_length)]
80
-
81
- # إنشاء ملف صوتي لكل جزء
82
- audio_files = []
83
- for i, part in enumerate(text_parts):
84
- progress((i + 1) / len(text_parts), desc=f"معالجة الجزء {i+1} من {len(text_parts)}...")
85
- audio_path = asyncio.run(generate_speech(part, lang))
86
- if audio_path:
87
- audio_files.append(audio_path)
88
-
89
- if not audio_files:
90
- logger.error("لم يتم إنشاء أي ملفات صوتية")
91
- return None
92
-
93
- # إذا كان هناك جزء واحد فقط
94
- if len(audio_files) == 1:
95
- return audio_files[0]
96
-
97
- # دمج الملفات الصوتية إذا كان هناك أكثر من جزء
98
- from pydub import AudioSegment
99
-
100
- final_audio = AudioSegment.from_mp3(audio_files[0])
101
- for audio_file in audio_files[1:]:
102
- final_audio += AudioSegment.from_mp3(audio_file)
103
-
104
- final_path = tempfile.mktemp(suffix='.mp3')
105
- final_audio.export(final_path, format="mp3")
106
-
107
- # تنظيف الملفات المؤقتة
108
- for file in audio_files:
109
- try:
110
- os.remove(file)
111
- except:
112
- pass
113
-
114
- progress(1.0, desc="تم إنشاء الصوت بنجاح!")
115
- return final_path
116
-
117
- except Exception as e:
118
- logger.error(f"خطأ في تحويل النص إلى صوت: {str(e)}")
119
- return None
120
-
121
- def create_document(original_text, translated_text, source_lang, target_lang, progress=gr.Progress()):
122
- """إنشاء ملف Word يحتوي على النص الأصلي والترجمة"""
123
  try:
124
- progress(0, desc="جاري إنشاء المستند...")
125
- doc = Document()
126
- doc.add_heading('النص الأصلي والترجمة', 0)
127
-
128
- progress(0.3, desc="جاري إضافة المحتوى...")
129
- # إضافة التاريخ والوقت
130
- doc.add_paragraph(f'تم الإنشاء في: {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}')
131
-
132
- # إضافة النص الأصلي
133
- doc.add_heading(f'النص الأصلي ({SUPPORTED_LANGUAGES[source_lang]})', level=1)
134
- doc.add_paragraph(original_text)
135
-
136
- progress(0.6, desc="جاري إضافة الترجمة...")
137
- # إضافة الترجمة
138
- doc.add_heading(f'الترجمة ({SUPPORTED_LANGUAGES[target_lang]})', level=1)
139
- doc.add_paragraph(translated_text)
140
-
141
- # حفظ الملف
142
- progress(0.9, desc="جاري حفظ المستند...")
143
- temp_path = tempfile.mktemp(suffix='.docx')
144
- doc.save(temp_path)
145
-
146
- progress(1.0, desc="تم إنشاء المستند بنجاح!")
147
- logger.info(f"تم إنشاء مستند Word: {temp_path}")
148
- return temp_path
149
-
150
  except Exception as e:
151
- logger.error(f"خطأ في إنشاء المستند: {str(e)}")
152
- return None
153
 
154
- def translate_text(text, source_lang, target_lang, progress=gr.Progress()):
155
- """ترجمة النص باستخدام deep-translator"""
156
  if source_lang == target_lang:
157
  return text
158
 
 
159
  try:
160
- progress(0.3, desc="جاري الترجمة...")
161
- logger.info(f"بدء الترجمة من {source_lang} إلى {target_lang}")
162
-
163
- translator = GoogleTranslator(source=source_lang, target=target_lang)
164
-
165
- # تقسيم النص إلى أجزاء إذا كان طويلاً
166
- max_length = 5000
167
- text_parts = [text[i:i+max_length] for i in range(0, len(text), max_length)]
168
-
169
- translated_parts = []
170
- for i, part in enumerate(text_parts):
171
- progress((i + 1) / len(text_parts), desc=f"ترجمة الجزء {i+1} من {len(text_parts)}...")
172
- translated_part = translator.translate(part)
173
- translated_parts.append(translated_part)
174
-
175
- translated_text = ' '.join(translated_parts)
176
- progress(1.0, desc="تمت الترجمة بنجاح!")
177
-
178
- return translated_text
179
 
 
180
  except Exception as e:
181
- logger.error(f"خطأ في الترجمة: {str(e)}")
182
  return f"خطأ في الترجمة: {str(e)}"
183
 
184
- def process_video(video, source_lang="en", target_lang="ar", progress=gr.Progress()):
185
- """معالجة الفيديو واستخراج النص وترجمته"""
186
- if video is None:
187
- return {
188
- "error": "الرجاء رفع ملف فيديو",
189
- "original": "",
190
- "translated": "",
191
- "document": None
192
- }
193
-
194
  try:
195
- # حفظ الفيديو مؤقتاً
196
- progress(0.1, desc="جاري تحميل الفيديو...")
197
- temp_path = video.name
198
- logger.info(f"تم استلام ملف فيديو: {temp_path}")
199
-
200
- # تحميل نموذج Whisper
201
- progress(0.3, desc="جاري تحميل نموذج التعرف على الكلام...")
202
- model = whisper.load_model("base")
203
-
204
- # استخراج النص
205
- progress(0.5, desc="جاري استخراج النص من الفيديو...")
206
- result = model.transcribe(temp_path, language=source_lang)
207
- transcribed_text = result["text"]
208
- logger.info("تم استخراج النص بنجاح")
209
 
210
- # ترجمة النص
211
- progress(0.7, desc="جاري ترجمة النص...")
212
- translated_text = translate_text(transcribed_text, source_lang, target_lang)
213
 
214
- # إنشاء ملف Word
215
- progress(0.9, desc="جاري إنشاء المستند...")
216
- doc_path = create_document(transcribed_text, translated_text, source_lang, target_lang)
217
-
218
- progress(1.0, desc="تمت المعالجة بنجاح!")
219
- return {
220
- "error": None,
221
- "original": transcribed_text,
222
- "translated": translated_text,
223
- "document": doc_path
224
- }
225
 
 
226
  except Exception as e:
227
- logger.error(f"خطأ في معالجة الفيديو: {str(e)}")
228
- return {
229
- "error": f"حدث خطأ: {str(e)}",
230
- "original": "",
231
- "translated": "",
232
- "document": None
233
- }
234
 
235
- def create_ui():
236
- """إنشاء واجهة المستخدم"""
237
- with gr.Blocks(theme=gr.themes.Soft(
238
- primary_hue="blue",
239
- secondary_hue="indigo",
240
- )) as demo:
241
- gr.Markdown(
242
- """
243
- # 🎥 منصة تحويل الفيديو إلى نص مع الترجمة
244
- ### قم برفع فيديو للحصول على النص والترجمة مع إمكانية تحويل النص إلى صوت
245
- """
246
- )
247
-
248
  with gr.Row():
249
- with gr.Column(scale=2):
250
- video_input = gr.File(
251
- label="📁 رفع فيديو",
252
- file_types=["video"],
253
- elem_id="video_input"
254
- )
255
- with gr.Column(scale=1):
256
- source_lang = gr.Dropdown(
257
- choices=list(SUPPORTED_LANGUAGES.keys()),
258
- value="en",
259
- label="🗣️ لغة الفيديو الأصلية"
260
- )
261
- target_lang = gr.Dropdown(
262
- choices=list(SUPPORTED_LANGUAGES.keys()),
263
- value="ar",
264
- label="🌐 لغة الترجمة"
265
- )
266
- process_btn = gr.Button("🎯 معالجة الفيديو", variant="primary")
267
-
268
  with gr.Row():
269
- error_output = gr.Textbox(label="⚠️ الأخطاء", visible=False)
270
-
271
- with gr.Tabs():
272
- with gr.TabItem("📝 النص الأصلي"):
273
- original_text = gr.Textbox(
274
- label="النص المستخرج من الفيديو",
275
- lines=10,
276
- elem_classes=["ltr"]
277
- )
278
- with gr.Row():
279
- generate_original_audio = gr.Button("🔊 توليد الصوت", variant="secondary")
280
- original_audio = gr.Audio(label="الصوت", visible=True)
281
-
282
- with gr.TabItem("🔄 النص المترجم"):
283
- translated_text = gr.Textbox(
284
- label="النص المترجم",
285
- lines=10,
286
- elem_classes=["rtl"]
287
- )
288
- with gr.Row():
289
- generate_translated_audio = gr.Button("🔊 توليد الصوت", variant="secondary")
290
- translated_audio = gr.Audio(label="الصوت", visible=True)
291
 
292
  with gr.Row():
293
- download_btn = gr.File(
294
- label="📥 تحميل المستند (Word)",
295
- interactive=False
296
- )
297
-
298
- def update_ui(video, src_lang, tgt_lang):
299
- result = process_video(video, src_lang, tgt_lang)
300
-
301
- # تحديث اتجاه النص
302
- original_classes = "rtl" if src_lang in RTL_LANGUAGES else "ltr"
303
- translated_classes = "rtl" if tgt_lang in RTL_LANGUAGES else "ltr"
304
-
305
- return {
306
- error_output: gr.update(value=result["error"], visible=bool(result["error"])),
307
- original_text: gr.update(value=result["original"], elem_classes=[original_classes]),
308
- translated_text: gr.update(value=result["translated"], elem_classes=[translated_classes]),
309
- download_btn: result["document"]
310
- }
311
-
312
- # ربط الأحداث
313
- process_btn.click(
314
- fn=update_ui,
315
- inputs=[video_input, source_lang, target_lang],
316
- outputs=[error_output, original_text, translated_text, download_btn]
317
- )
318
-
319
- generate_original_audio.click(
320
- fn=text_to_speech,
321
- inputs=[original_text, source_lang],
322
- outputs=[original_audio]
323
  )
 
 
 
 
 
324
 
325
- generate_translated_audio.click(
 
 
 
 
 
 
 
 
 
 
 
 
 
326
  fn=text_to_speech,
327
- inputs=[translated_text, target_lang],
328
- outputs=[translated_audio]
329
  )
330
-
331
- return demo
332
 
333
- if __name__ == "__main__":
334
- try:
335
- logger.info("بدء تشغيل التطبيق")
336
- demo = create_ui()
337
- demo.launch()
338
- except Exception as e:
339
- logger.error(f"خطأ في تشغيل التطبيق: {str(e)}")
 
1
+ import os
2
  import gradio as gr
3
  import whisper
4
+ from transformers import MarianMTModel, MarianTokenizer
5
+ import torch
6
+ from TTS.api import TTS
 
 
 
 
 
 
 
7
 
8
+ # تهيئة النماذج
9
+ DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
10
+ whisper_model = whisper.load_model("base")
 
 
 
 
 
 
 
11
 
12
+ # قاموس للغات المدعومة
13
  SUPPORTED_LANGUAGES = {
14
+ "ar": "العربية",
15
+ "en": "English",
16
+ "fr": "Français",
17
+ "es": "Español"
 
18
  }
19
 
20
+ # قاموس لنماذج الترجمة
21
+ TRANSLATION_MODELS = {
22
+ "ar-en": "Helsinki-NLP/opus-mt-ar-en",
23
+ "en-ar": "Helsinki-NLP/opus-mt-en-ar",
24
+ "fr-en": "Helsinki-NLP/opus-mt-fr-en",
25
+ "en-fr": "Helsinki-NLP/opus-mt-en-fr",
26
+ "es-en": "Helsinki-NLP/opus-mt-es-en",
27
+ "en-es": "Helsinki-NLP/opus-mt-en-es"
28
  }
29
 
30
+ def transcribe_audio(audio_file, source_lang):
31
+ """تحويل الصوت إلى نص باستخدام Whisper"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  try:
33
+ result = whisper_model.transcribe(audio_file, language=source_lang)
34
+ return result["text"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  except Exception as e:
36
+ return f"خطأ في التحويل: {str(e)}"
 
37
 
38
+ def translate_text(text, source_lang, target_lang):
39
+ """ترجمة النص بين اللغات"""
40
  if source_lang == target_lang:
41
  return text
42
 
43
+ model_key = f"{source_lang}-en" if source_lang != "en" else f"en-{target_lang}"
44
  try:
45
+ model_name = TRANSLATION_MODELS[model_key]
46
+ model = MarianMTModel.from_pretrained(model_name)
47
+ tokenizer = MarianTokenizer.from_pretrained(model_name)
48
+
49
+ inputs = tokenizer(text, return_tensors="pt", padding=True)
50
+ translated = model.generate(**inputs)
51
+ result = tokenizer.decode(translated[0], skip_special_tokens=True)
52
+
53
+ # إذا كانت اللغة المصدر ليست الإنجليزية والهدف ليس الإنجليزية
54
+ if source_lang != "en" and target_lang != "en":
55
+ # ترجمة إضافية من الإنجليزية إلى اللغة الهدف
56
+ model_name = TRANSLATION_MODELS[f"en-{target_lang}"]
57
+ model = MarianMTModel.from_pretrained(model_name)
58
+ tokenizer = MarianTokenizer.from_pretrained(model_name)
59
+
60
+ inputs = tokenizer(result, return_tensors="pt", padding=True)
61
+ translated = model.generate(**inputs)
62
+ result = tokenizer.decode(translated[0], skip_special_tokens=True)
 
63
 
64
+ return result
65
  except Exception as e:
 
66
  return f"خطأ في الترجمة: {str(e)}"
67
 
68
+ def text_to_speech(text, target_lang, gender, style):
69
+ """تحويل النص إلى صوت"""
 
 
 
 
 
 
 
 
70
  try:
71
+ # اختيار النموذج المناسب بناءً على اللغة والجنس
72
+ tts = TTS(model_name="tts_models/multilingual/multi-dataset/your_tts", progress_bar=False)
 
 
 
 
 
 
 
 
 
 
 
 
73
 
74
+ # تعيين معرف المتحدث والنمط
75
+ speaker_id = "female" if gender == "أنثى" else "male"
76
+ speed = 1.0 if style == "عادي" else 1.3 if style == "سريع" else 0.8
77
 
78
+ output_path = "output.wav"
79
+ tts.tts_to_file(text=text, speaker=speaker_id, speed=speed, file_path=output_path)
 
 
 
 
 
 
 
 
 
80
 
81
+ return output_path
82
  except Exception as e:
83
+ return f"خطأ في تحويل النص إلى صوت: {str(e)}"
 
 
 
 
 
 
84
 
85
+ # إنشاء واجهة Gradio
86
+ with gr.Blocks(title="معالج الصوت والترجمة", theme=gr.themes.Soft()) as demo:
87
+ gr.Markdown("# معالج الصوت والترجمة متعدد اللغات")
88
+
89
+ with gr.Tab("تحويل الصوت إلى نص"):
 
 
 
 
 
 
 
 
90
  with gr.Row():
91
+ audio_input = gr.Audio(type="filepath", label="الملف الصوتي")
92
+ source_lang = gr.Dropdown(choices=list(SUPPORTED_LANGUAGES.keys()),
93
+ value="ar",
94
+ label="لغة الملف الصوتي")
95
+
96
+ transcribe_btn = gr.Button("تحويل إلى نص")
97
+ transcribed_text = gr.Textbox(label="النص المستخرج", lines=5)
98
+
99
+ transcribe_btn.click(
100
+ fn=transcribe_audio,
101
+ inputs=[audio_input, source_lang],
102
+ outputs=transcribed_text
103
+ )
104
+
105
+ with gr.Tab("ترجمة النص"):
 
 
 
 
106
  with gr.Row():
107
+ input_text = gr.Textbox(label="النص المراد ترجمته", lines=5)
108
+ translated_text = gr.Textbox(label="النص المترجم", lines=5)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
 
110
  with gr.Row():
111
+ trans_source_lang = gr.Dropdown(choices=list(SUPPORTED_LANGUAGES.keys()),
112
+ value="ar",
113
+ label="اللغة المصدر")
114
+ trans_target_lang = gr.Dropdown(choices=list(SUPPORTED_LANGUAGES.keys()),
115
+ value="en",
116
+ label="اللغة الهدف")
117
+
118
+ translate_btn = gr.Button("ترجمة")
119
+
120
+ translate_btn.click(
121
+ fn=translate_text,
122
+ inputs=[input_text, trans_source_lang, trans_target_lang],
123
+ outputs=translated_text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
  )
125
+
126
+ with gr.Tab("تحويل النص إلى صوت"):
127
+ with gr.Row():
128
+ tts_text = gr.Textbox(label="النص المراد تحويله إلى صوت", lines=5)
129
+ tts_output = gr.Audio(label="الصوت الناتج")
130
 
131
+ with gr.Row():
132
+ tts_lang = gr.Dropdown(choices=list(SUPPORTED_LANGUAGES.keys()),
133
+ value="ar",
134
+ label="لغة النص")
135
+ tts_gender = gr.Radio(choices=["ذكر", "أنثى"],
136
+ value="ذكر",
137
+ label="جنس المتحدث")
138
+ tts_style = gr.Radio(choices=["سريع", "عادي", "تعليق صوتي"],
139
+ value="عادي",
140
+ label="نمط الإلقاء")
141
+
142
+ tts_btn = gr.Button("تحويل إلى صوت")
143
+
144
+ tts_btn.click(
145
  fn=text_to_speech,
146
+ inputs=[tts_text, tts_lang, tts_gender, tts_style],
147
+ outputs=tts_output
148
  )
 
 
149
 
150
+ # تشغيل التطبيق
151
+ demo.launch()