KIMOSSINO commited on
Commit
85b4f05
·
verified ·
1 Parent(s): 8dc41e4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +149 -89
app.py CHANGED
@@ -1,17 +1,15 @@
1
  import gradio as gr
2
  import whisper
3
  import os
 
 
 
 
 
4
  import tempfile
5
  from datetime import datetime
6
  import logging
7
  import sys
8
- from transformers import pipeline, SpeechT5Processor, SpeechT5ForTextToSpeech, SpeechT5HifiGan
9
- from deep_translator import GoogleTranslator
10
- from docx import Document
11
- import time
12
- import torch
13
- import soundfile as sf
14
- import numpy as np
15
 
16
  # إعداد التسجيل
17
  logging.basicConfig(
@@ -24,10 +22,6 @@ logging.basicConfig(
24
  )
25
  logger = logging.getLogger(__name__)
26
 
27
- # إنشاء مجلد للملفات المؤقتة
28
- TEMP_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'temp_files')
29
- os.makedirs(TEMP_DIR, exist_ok=True)
30
-
31
  # قائمة اللغات المدعومة
32
  SUPPORTED_LANGUAGES = {
33
  'ar': 'العربية',
@@ -37,113 +31,158 @@ SUPPORTED_LANGUAGES = {
37
  'de': 'Deutsch'
38
  }
39
 
40
- def cleanup_temp_files():
41
- """تنظيف الملفات المؤقتة"""
 
 
 
 
 
 
 
 
 
 
 
 
42
  try:
43
- current_time = time.time()
44
- for filename in os.listdir(TEMP_DIR):
45
- file_path = os.path.join(TEMP_DIR, filename)
46
- if os.path.getmtime(file_path) < current_time - 300: # 5 minutes
47
- try:
48
- os.remove(file_path)
49
- except Exception as e:
50
- logger.error(f"خطأ في حذف الملف المؤقت {file_path}: {str(e)}")
 
 
 
 
 
 
51
  except Exception as e:
52
- logger.error(f"خطأ في تنظيف الملفات المؤقتة: {str(e)}")
 
53
 
54
  def text_to_speech(text, lang, progress=gr.Progress()):
55
- """تحويل النص إلى صوت"""
56
  if not text:
 
57
  return None
58
-
59
- try:
60
- progress(0.2, desc="جاري تحميل النماذج...")
61
 
62
- # تحميل النماذج
63
- processor = SpeechT5Processor.from_pretrained("microsoft/speecht5_tts")
64
- model = SpeechT5ForTextToSpeech.from_pretrained("microsoft/speecht5_tts")
65
- vocoder = SpeechT5HifiGan.from_pretrained("microsoft/speecht5_hifigan")
66
 
67
  # تقسيم النص إلى أجزاء إذا كان طويلاً
68
- max_length = 500
69
- text_chunks = [text[i:i+max_length] for i in range(0, len(text), max_length)]
 
 
 
 
 
 
 
 
70
 
71
- all_speech = []
72
- for i, chunk in enumerate(text_chunks):
73
- progress((i + 1) / len(text_chunks) * 0.8, desc=f"معالجة الجزء {i+1} من {len(text_chunks)}...")
74
 
75
- # تجهيز النص
76
- inputs = processor(text=chunk, return_tensors="pt")
 
77
 
78
- # توليد الصوت
79
- speech = model.generate_speech(inputs["input_ids"], vocoder)
80
- all_speech.append(speech.numpy())
81
-
82
- # دمج كل الأجزاء
83
- final_speech = np.concatenate(all_speech)
84
 
85
- # حفظ الملف
86
- output_file = os.path.join(TEMP_DIR, f'speech_{time.time()}.wav')
87
- sf.write(output_file, final_speech, 16000)
 
 
 
 
 
 
 
 
 
 
88
 
89
  progress(1.0, desc="تم إنشاء الصوت بنجاح!")
90
- return output_file
91
-
92
  except Exception as e:
93
  logger.error(f"خطأ في تحويل النص إلى صوت: {str(e)}")
94
  return None
95
 
96
- def translate_text(text, source_lang, target_lang, progress=gr.Progress()):
97
- """ترجمة النص"""
98
- if source_lang == target_lang:
99
- return text
100
-
101
- try:
102
- progress(0.3, desc="جاري الترجمة...")
103
- translator = GoogleTranslator(source=source_lang, target=target_lang)
104
-
105
- # تقسيم النص إلى أجزاء صغيرة
106
- max_chunk_size = 1000
107
- chunks = [text[i:i+max_chunk_size] for i in range(0, len(text), max_chunk_size)]
108
- translated_chunks = []
109
-
110
- for i, chunk in enumerate(chunks):
111
- progress((i + 1) / len(chunks), desc=f"ترجمة الجزء {i+1} من {len(chunks)}...")
112
- translated_chunk = translator.translate(chunk)
113
- translated_chunks.append(translated_chunk)
114
- time.sleep(0.5) # تأخير صغير لتجنب التحميل الزائد
115
-
116
- return ' '.join(translated_chunks)
117
- except Exception as e:
118
- logger.error(f"خطأ في الترجمة: {str(e)}")
119
- return f"خطأ في الترجمة: {str(e)}"
120
-
121
  def create_document(original_text, translated_text, source_lang, target_lang, progress=gr.Progress()):
122
- """إنشاء ملف Word"""
123
  try:
124
- progress(0.3, desc="جاري إنشاء المستند...")
125
  doc = Document()
126
  doc.add_heading('النص الأصلي والترجمة', 0)
127
 
 
 
128
  doc.add_paragraph(f'تم الإنشاء في: {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}')
129
 
 
130
  doc.add_heading(f'النص الأصلي ({SUPPORTED_LANGUAGES[source_lang]})', level=1)
131
  doc.add_paragraph(original_text)
132
 
 
 
133
  doc.add_heading(f'الترجمة ({SUPPORTED_LANGUAGES[target_lang]})', level=1)
134
  doc.add_paragraph(translated_text)
135
 
136
- doc_path = os.path.join(TEMP_DIR, f'document_{time.time()}.docx')
137
- doc.save(doc_path)
 
 
138
 
139
  progress(1.0, desc="تم إنشاء المستند بنجاح!")
140
- return doc_path
 
 
141
  except Exception as e:
142
  logger.error(f"خطأ في إنشاء المستند: {str(e)}")
143
  return None
144
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
  def process_video(video, source_lang="en", target_lang="ar", progress=gr.Progress()):
146
- """معالجة الفيديو"""
147
  if video is None:
148
  return {
149
  "error": "الرجاء رفع ملف فيديو",
@@ -153,8 +192,10 @@ def process_video(video, source_lang="en", target_lang="ar", progress=gr.Progres
153
  }
154
 
155
  try:
156
- cleanup_temp_files()
157
  progress(0.1, desc="جاري تحميل الفيديو...")
 
 
158
 
159
  # تحميل نموذج Whisper
160
  progress(0.3, desc="جاري تحميل نموذج التعرف على الكلام...")
@@ -162,8 +203,9 @@ def process_video(video, source_lang="en", target_lang="ar", progress=gr.Progres
162
 
163
  # استخراج النص
164
  progress(0.5, desc="جاري استخراج النص من الفيديو...")
165
- result = model.transcribe(video.name, language=source_lang)
166
  transcribed_text = result["text"]
 
167
 
168
  # ترجمة النص
169
  progress(0.7, desc="جاري ترجمة النص...")
@@ -173,12 +215,14 @@ def process_video(video, source_lang="en", target_lang="ar", progress=gr.Progres
173
  progress(0.9, desc="جاري إنشاء المستند...")
174
  doc_path = create_document(transcribed_text, translated_text, source_lang, target_lang)
175
 
 
176
  return {
177
  "error": None,
178
  "original": transcribed_text,
179
  "translated": translated_text,
180
  "document": doc_path
181
  }
 
182
  except Exception as e:
183
  logger.error(f"خطأ في معالجة الفيديو: {str(e)}")
184
  return {
@@ -190,7 +234,10 @@ def process_video(video, source_lang="en", target_lang="ar", progress=gr.Progres
190
 
191
  def create_ui():
192
  """إنشاء واجهة المستخدم"""
193
- with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue")) as demo:
 
 
 
194
  gr.Markdown(
195
  """
196
  # 🎥 منصة تحويل الفيديو إلى نص مع الترجمة
@@ -202,7 +249,8 @@ def create_ui():
202
  with gr.Column(scale=2):
203
  video_input = gr.File(
204
  label="📁 رفع فيديو",
205
- file_types=["video"]
 
206
  )
207
  with gr.Column(scale=1):
208
  source_lang = gr.Dropdown(
@@ -217,13 +265,15 @@ def create_ui():
217
  )
218
  process_btn = gr.Button("🎯 معالجة الفيديو", variant="primary")
219
 
220
- error_output = gr.Textbox(label="⚠️ الأخطاء", visible=False)
 
221
 
222
  with gr.Tabs():
223
  with gr.TabItem("📝 النص الأصلي"):
224
  original_text = gr.Textbox(
225
  label="النص المستخرج من الفيديو",
226
- lines=10
 
227
  )
228
  with gr.Row():
229
  generate_original_audio = gr.Button("🔊 توليد الصوت", variant="secondary")
@@ -232,20 +282,30 @@ def create_ui():
232
  with gr.TabItem("🔄 النص المترجم"):
233
  translated_text = gr.Textbox(
234
  label="النص المترجم",
235
- lines=10
 
236
  )
237
  with gr.Row():
238
  generate_translated_audio = gr.Button("🔊 توليد الصوت", variant="secondary")
239
  translated_audio = gr.Audio(label="الصوت", visible=True)
240
 
241
- download_btn = gr.File(label="📥 تحميل المستند (Word)", visible=True)
 
 
 
 
242
 
243
  def update_ui(video, src_lang, tgt_lang):
244
  result = process_video(video, src_lang, tgt_lang)
 
 
 
 
 
245
  return {
246
  error_output: gr.update(value=result["error"], visible=bool(result["error"])),
247
- original_text: result["original"],
248
- translated_text: result["translated"],
249
  download_btn: result["document"]
250
  }
251
 
 
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(
 
22
  )
23
  logger = logging.getLogger(__name__)
24
 
 
 
 
 
25
  # قائمة اللغات المدعومة
26
  SUPPORTED_LANGUAGES = {
27
  'ar': 'العربية',
 
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": "الرجاء رفع ملف فيديو",
 
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="جاري تحميل نموذج التعرف على الكلام...")
 
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="جاري ترجمة النص...")
 
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 {
 
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
  # 🎥 منصة تحويل الفيديو إلى نص مع الترجمة
 
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(
 
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")
 
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