KIMOSSINO commited on
Commit
d5f394e
·
verified ·
1 Parent(s): 29a413e

Create APP.PY

Browse files
Files changed (1) hide show
  1. APP.PY +281 -0
APP.PY ADDED
@@ -0,0 +1,281 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ from pydub import AudioSegment
14
+ import time
15
+ import torch
16
+ from concurrent.futures import ThreadPoolExecutor
17
+ from functools import lru_cache
18
+
19
+ # تكوين التسجيل
20
+ logging.basicConfig(
21
+ level=logging.INFO,
22
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
23
+ handlers=[
24
+ logging.FileHandler('app.log'),
25
+ logging.StreamHandler(sys.stdout)
26
+ ]
27
+ )
28
+ logger = logging.getLogger(__name__)
29
+
30
+ # تحديد الجهاز المستخدم (GPU إذا كان متاحاً)
31
+ DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
32
+ logger.info(f"Using device: {DEVICE}")
33
+
34
+ # حجم النموذج - يمكن تغييره حسب الحاجة
35
+ MODEL_SIZE = "base"
36
+
37
+ # تخزين مؤقت للنماذج
38
+ _models = {}
39
+
40
+ # قائمة اللغات المدعومة
41
+ SUPPORTED_LANGUAGES = {
42
+ 'ar': 'العربية',
43
+ 'en': 'English',
44
+ 'fr': 'Français',
45
+ 'es': 'Español',
46
+ 'de': 'Deutsch'
47
+ }
48
+
49
+ # تعيين أصوات لكل لغة
50
+ VOICE_MAPPINGS = {
51
+ 'ar': {
52
+ 'male': 'ar-EG-ShakirNeural',
53
+ 'female': 'ar-EG-SalmaNeural'
54
+ },
55
+ 'en': {
56
+ 'male': 'en-US-ChristopherNeural',
57
+ 'female': 'en-US-JennyNeural'
58
+ },
59
+ 'fr': {
60
+ 'male': 'fr-FR-HenriNeural',
61
+ 'female': 'fr-FR-DeniseNeural'
62
+ },
63
+ 'es': {
64
+ 'male': 'es-ES-AlvaroNeural',
65
+ 'female': 'es-ES-ElviraNeural'
66
+ },
67
+ 'de': {
68
+ 'male': 'de-DE-ConradNeural',
69
+ 'female': 'de-DE-KatjaNeural'
70
+ }
71
+ }
72
+
73
+ RTL_LANGUAGES = ['ar']
74
+
75
+ def get_whisper_model():
76
+ """الحصول على نموذج Whisper مع التخزين المؤقت"""
77
+ if 'whisper' not in _models:
78
+ _models['whisper'] = whisper.load_model(MODEL_SIZE, device=DEVICE)
79
+ return _models['whisper']
80
+
81
+ @lru_cache(maxsize=100)
82
+ async def generate_speech_cached(text, voice):
83
+ """توليد الصوت مع التخزين المؤقت"""
84
+ try:
85
+ communicate = edge_tts.Communicate(text, voice)
86
+ audio_path = tempfile.mktemp(suffix='.mp3')
87
+ await communicate.save(audio_path)
88
+ return audio_path if os.path.exists(audio_path) and os.path.getsize(audio_path) > 0 else None
89
+ except Exception as e:
90
+ logger.error(f"خطأ في توليد الصوت: {str(e)}")
91
+ return None
92
+
93
+ def text_to_speech(text, lang, voice_gender='male', progress=gr.Progress()):
94
+ """تحسين تحويل النص إلى صوت"""
95
+ if not text:
96
+ return None
97
+
98
+ try:
99
+ progress(0.2, desc="جاري تجهيز الصوت...")
100
+ voice = VOICE_MAPPINGS.get(lang, {}).get(voice_gender, VOICE_MAPPINGS['en']['male'])
101
+
102
+ # تقسيم النص إلى أجزاء أصغر للمعالجة المتوازية
103
+ chunk_size = 500
104
+ chunks = [text[i:i+chunk_size] for i in range(0, len(text), chunk_size)]
105
+
106
+ audio_files = []
107
+ with ThreadPoolExecutor() as executor:
108
+ futures = []
109
+ for chunk in chunks:
110
+ future = asyncio.run(generate_speech_cached(chunk, voice))
111
+ futures.append(future)
112
+
113
+ for i, future in enumerate(futures):
114
+ progress((i + 1) / len(futures), desc=f"معالجة الجزء {i+1} من {len(futures)}...")
115
+ if future:
116
+ audio_files.append(future)
117
+
118
+ if not audio_files:
119
+ return None
120
+
121
+ if len(audio_files) == 1:
122
+ return audio_files[0]
123
+
124
+ # دمج الملفات الصوتية
125
+ final_audio = AudioSegment.from_mp3(audio_files[0])
126
+ for audio_file in audio_files[1:]:
127
+ final_audio += AudioSegment.from_mp3(audio_file)
128
+
129
+ final_path = tempfile.mktemp(suffix='.mp3')
130
+ final_audio.export(final_path, format="mp3")
131
+
132
+ # تنظيف الملفات المؤقتة
133
+ for file in audio_files:
134
+ try:
135
+ os.remove(file)
136
+ except:
137
+ pass
138
+
139
+ return final_path
140
+
141
+ except Exception as e:
142
+ logger.error(f"خطأ في تحويل النص إلى صوت: {str(e)}")
143
+ return None
144
+
145
+ @lru_cache(maxsize=50)
146
+ def translate_text_cached(text, source_lang, target_lang):
147
+ """ترجمة النص مع التخزين المؤقت"""
148
+ if source_lang == target_lang:
149
+ return text
150
+
151
+ try:
152
+ translator = GoogleTranslator(source=source_lang, target=target_lang)
153
+ return translator.translate(text)
154
+ except Exception as e:
155
+ logger.error(f"خطأ في الترجمة: {str(e)}")
156
+ return f"خطأ في الترجمة: {str(e)}"
157
+
158
+ def translate_text(text, source_lang, target_lang, progress=gr.Progress()):
159
+ """تحسين الترجمة باستخدام المعالجة المتوا��ية"""
160
+ if source_lang == target_lang:
161
+ return text
162
+
163
+ try:
164
+ progress(0.3, desc="جاري الترجمة...")
165
+
166
+ # تقسيم النص إلى أجزاء أصغر
167
+ chunk_size = 1000
168
+ chunks = [text[i:i+chunk_size] for i in range(0, len(text), chunk_size)]
169
+
170
+ translated_chunks = []
171
+ with ThreadPoolExecutor() as executor:
172
+ futures = []
173
+ for chunk in chunks:
174
+ future = executor.submit(translate_text_cached, chunk, source_lang, target_lang)
175
+ futures.append(future)
176
+
177
+ for i, future in enumerate(futures):
178
+ progress((i + 1) / len(futures), desc=f"ترجمة الجزء {i+1} من {len(futures)}...")
179
+ translated_chunks.append(future.result())
180
+
181
+ return ' '.join(translated_chunks)
182
+
183
+ except Exception as e:
184
+ logger.error(f"خطأ في الترجمة: {str(e)}")
185
+ return f"خطأ في الترجمة: {str(e)}"
186
+
187
+ def process_video(video, source_lang="en", target_lang="ar", progress=gr.Progress()):
188
+ """تحسين معالجة الفيديو"""
189
+ if video is None:
190
+ return {
191
+ "error": "الرجاء رفع ملف فيديو",
192
+ "original": "",
193
+ "translated": "",
194
+ "document": None
195
+ }
196
+
197
+ try:
198
+ progress(0.1, desc="جاري تحميل الفيديو...")
199
+ temp_path = video.name
200
+
201
+ # تحميل نموذج Whisper
202
+ progress(0.3, desc="جاري تحميل نموذج التعرف على الكلام...")
203
+ model = get_whisper_model()
204
+
205
+ # استخراج النص مع التقسيم
206
+ progress(0.5, desc="جاري استخراج النص من الفيديو...")
207
+ result = model.transcribe(
208
+ temp_path,
209
+ language=source_lang,
210
+ fp16=torch.cuda.is_available(), # استخدام FP16 إذا كان متاحاً
211
+ task="transcribe"
212
+ )
213
+
214
+ transcribed_text = ""
215
+ for segment in result["segments"]:
216
+ start_time = format_timestamp(segment["start"])
217
+ text = segment["text"].strip()
218
+ transcribed_text += f"[{start_time}] {text}\n"
219
+
220
+ # ترجمة النص
221
+ progress(0.7, desc="جاري ترجمة النص...")
222
+ translated_text = translate_text(transcribed_text, source_lang, target_lang)
223
+
224
+ # إنشاء المستند
225
+ progress(0.9, desc="جاري إنشاء المستند...")
226
+ doc_path = create_document(transcribed_text, translated_text, source_lang, target_lang)
227
+
228
+ return {
229
+ "error": None,
230
+ "original": transcribed_text,
231
+ "translated": translated_text,
232
+ "document": doc_path
233
+ }
234
+
235
+ except Exception as e:
236
+ logger.error(f"خطأ في معالجة الفيديو: {str(e)}")
237
+ return {
238
+ "error": f"حدث خطأ: {str(e)}",
239
+ "original": "",
240
+ "translated": "",
241
+ "document": None
242
+ }
243
+
244
+ def format_timestamp(seconds):
245
+ """تنسيق الوقت بالثواني إلى الشكل HH:MM:SS"""
246
+ hours = int(seconds // 3600)
247
+ minutes = int((seconds % 3600) // 60)
248
+ seconds = int(seconds % 60)
249
+ return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
250
+
251
+ def create_document(original_text, translated_text, source_lang, target_lang):
252
+ """إنشاء مستند DOCX يحتوي على النص الأصلي والترجمة"""
253
+ doc = Document()
254
+ doc.add_heading(f"النص الأصلي ({SUPPORTED_LANGUAGES.get(source_lang, 'غير معروف')})")
255
+ doc.add_paragraph(original_text)
256
+ doc.add_heading(f"الترجمة ({SUPPORTED_LANGUAGES.get(target_lang, 'غير معروف')})")
257
+ doc.add_paragraph(translated_text)
258
+ temp_path = tempfile.mktemp(suffix='.docx')
259
+ doc.save(temp_path)
260
+ return temp_path
261
+
262
+ # إنشاء واجهة المستخدم
263
+ demo = gr.Interface(
264
+ process_video,
265
+ [
266
+ gr.File(label="تحميل ملف الفيديو"),
267
+ gr.Radio(label="لغة المصدر", choices=list(SUPPORTED_LANGUAGES.keys()), value="en"),
268
+ gr.Radio(label="لغة الهدف", choices=list(SUPPORTED_LANGUAGES.keys()), value="ar"),
269
+ gr.Progress(label="التقدم")
270
+ ],
271
+ [
272
+ gr.Textbox(label="النص الأصلي"),
273
+ gr.Textbox(label="الترجمة"),
274
+ gr.File(label="المستند")
275
+ ],
276
+ title="تحويل الفيديو إلى نص وترجمة",
277
+ description="استخدم هذا الأداة لتحويل الفيديوهات إلى نصوص وترجمتها إلى لغات مختلفة."
278
+ )
279
+
280
+ if __name__ == "__main__":
281
+ demo.launch()