Mahmoudmody777 commited on
Commit
0c44bc5
·
verified ·
1 Parent(s): a3fce17

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +137 -72
app.py CHANGED
@@ -9,61 +9,122 @@ from PIL import Image, ImageDraw, ImageFont
9
  import arabic_reshaper
10
  from bidi.algorithm import get_display
11
  from pydub import AudioSegment
 
12
 
13
- # تحميل نموذج Whisper
14
- model = whisper.load_model("base")
15
 
16
- def prepare_arabic_text(text):
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  """تحضير النص العربي للعرض بشكل صحيح"""
18
- reshaped_text = arabic_reshaper.reshape(text)
19
- bidi_text = get_display(reshaped_text)
20
- return bidi_text
 
 
 
 
21
 
22
- def create_text_image(text, size=(720, 480), font_size=30):
 
 
23
  """إنشاء صورة تحتوي على نص"""
24
- # إنشاء صورة جديدة مع خلفية سوداء
25
- img = Image.new('RGB', size, 'black')
 
 
 
 
 
26
  draw = ImageDraw.Draw(img)
27
 
28
  try:
29
- # محاولة تحميل الخط
30
- font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", font_size)
31
- except:
32
- try:
33
- # محاولة بديلة لتحميل الخط
34
- font = ImageFont.truetype("arial.ttf", font_size)
35
- except:
36
- # استخدام الخط الافتراضي إذا فشلت المحاولات السابقة
37
- font = ImageFont.load_default()
38
 
39
- # تحضير النص وحساب أبعاده
40
  if any('\u0600' <= c <= '\u06FF' for c in text):
41
- text = prepare_arabic_text(text)
42
 
43
- # حساب موقع النص في وسط الصورة
44
  text_bbox = draw.textbbox((0, 0), text, font=font)
45
  text_width = text_bbox[2] - text_bbox[0]
46
  text_height = text_bbox[3] - text_bbox[1]
47
 
48
- x = (size[0] - text_width) // 2
49
- y = (size[1] - text_height) // 2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
 
51
  # رسم النص
52
- draw.text((x, y), text, font=font, fill='white')
53
 
54
  return np.array(img)
55
 
56
- def convert_audio_to_wav(audio_path):
57
- """تحويل الملف الصوتي إلى صيغة WAV"""
58
- audio_path = Path(audio_path)
59
- if audio_path.suffix.lower() != '.wav':
60
- wav_path = audio_path.with_suffix('.wav')
61
- audio = AudioSegment.from_file(str(audio_path))
62
- audio.export(str(wav_path), format='wav')
63
- return str(wav_path)
64
- return str(audio_path)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
 
66
- def create_video_with_text(audio_path, transcription):
 
67
  """إنشاء فيديو مع نص متزامن"""
68
  try:
69
  # تحويل الملف الصوتي إلى WAV
@@ -73,29 +134,33 @@ def create_video_with_text(audio_path, transcription):
73
  audio_clip = AudioFileClip(wav_path)
74
  duration = audio_clip.duration
75
 
76
- # تقسيم النص إلى أجزاء
77
- words = transcription.split()
78
- total_frames = int(duration * 24) # 24 FPS
79
- words_per_frame = max(1, len(words) // total_frames)
 
 
 
80
 
81
  # إنشاء قائمة المقاطع
82
  clips = []
83
  current_time = 0
84
- frame_duration = duration / (len(words) / words_per_frame)
85
 
86
- for i in range(0, len(words), words_per_frame):
87
- # تجميع الكلمات لهذا الإطار
88
- frame_words = ' '.join(words[i:i + words_per_frame])
89
-
90
  # إنشاء صورة للنص
91
- text_image = create_text_image(frame_words)
 
 
 
 
 
92
 
93
  # تحويل الصورة إلى مقطع
94
- text_clip = ImageClip(text_image).set_duration(frame_duration)
95
 
96
  # إضافة المقطع مع توقيته
97
  clips.append(text_clip.set_start(current_time))
98
- current_time += frame_duration
99
 
100
  # دمج جميع المقاطع
101
  video = CompositeVideoClip(clips, size=(720, 480))
@@ -119,43 +184,43 @@ def create_video_with_text(audio_path, transcription):
119
  print(f"خطأ في create_video_with_text: {str(e)}")
120
  raise
121
 
122
- def process_audio(audio_path):
123
- """معالجة الملف الصوتي وإنشاء الفيديو"""
124
- try:
125
- if not isinstance(audio_path, str):
126
- raise ValueError("يجب أن يكون المدخل مسار ملف صوتي")
127
-
128
- if not os.path.exists(audio_path):
129
- raise FileNotFoundError("الملف غير موجود")
130
-
131
- # تحويل الصوت إلى نص
132
- print("جاري تحويل الصوت إلى نص...")
133
- result = model.transcribe(audio_path)
134
- transcription = result["text"]
135
- print("تم استخراج النص بنجاح")
136
-
137
- # إنشاء الفيديو
138
- print("جاري إنشاء الفيديو...")
139
- video_path = create_video_with_text(audio_path, transcription)
140
- print("تم إنشاء الفيديو بنجاح")
141
-
142
- return video_path, transcription
143
- except Exception as e:
144
- print(f"خطأ في process_audio: {str(e)}")
145
- return None, f"حدث خطأ أثناء المعالجة: {str(e)}"
146
 
147
  # إنشاء واجهة Gradio
 
 
148
  iface = gr.Interface(
149
  fn=process_audio,
150
  inputs=[
151
- gr.Audio(type="filepath", label="قم بتحميل ملف صوتي (MP3 أو WAV)")
 
 
 
 
 
 
152
  ],
153
  outputs=[
154
  gr.Video(label="الفيديو المنشأ"),
155
  gr.Textbox(label="النص المستخرج")
156
  ],
157
  title="محول الصوت إلى فيديو مع النص",
158
- description="قم بتحميل ملف صوتي لإنشاء فيديو مع نص متزامن. يدعم اللغتين العربية والإنجليزية.",
 
 
 
 
 
 
 
159
  examples=[],
160
  cache_examples=False
161
  )
 
9
  import arabic_reshaper
10
  from bidi.algorithm import get_display
11
  from pydub import AudioSegment
12
+ import glob
13
 
14
+ # تحميل نموذج Whisper - استخدام النموذج المتوسط لدقة أفضل في اللغة العربية
15
+ model = whisper.load_model("medium")
16
 
17
+ def get_available_fonts():
18
+ """الحصول على قائمة الخطوط المتاحة من مجلد fonts"""
19
+ fonts_dir = "fonts"
20
+ if not os.path.exists(fonts_dir):
21
+ os.makedirs(fonts_dir)
22
+
23
+ font_files = glob.glob(os.path.join(fonts_dir, "*.ttf")) + \
24
+ glob.glob(os.path.join(fonts_dir, "*.TTF")) + \
25
+ glob.glob(os.path.join(fonts_dir, "*.otf")) + \
26
+ glob.glob(os.path.join(fonts_dir, "*.OTF"))
27
+
28
+ return [os.path.basename(f) for f in font_files]
29
+
30
+ def prepare_arabic_text(text, font_path):
31
  """تحضير النص العربي للعرض بشكل صحيح"""
32
+ try:
33
+ reshaped_text = arabic_reshaper.reshape(text)
34
+ bidi_text = get_display(reshaped_text)
35
+ return bidi_text
36
+ except Exception as e:
37
+ print(f"خطأ في معالجة النص العربي: {str(e)}")
38
+ return text
39
 
40
+ def create_text_image(text, size=(720, 480), font_path="fonts/bein-normal.ttf",
41
+ font_size=30, text_color='white', background_color='black',
42
+ background_image=None, text_position='center'):
43
  """إنشاء صورة تحتوي على نص"""
44
+ # استخدام الصورة الخلفية إذا كانت موجودة
45
+ if background_image:
46
+ img = Image.open(background_image).convert('RGB')
47
+ img = img.resize(size)
48
+ else:
49
+ img = Image.new('RGB', size, background_color)
50
+
51
  draw = ImageDraw.Draw(img)
52
 
53
  try:
54
+ # محاولة تحميل الخط المحدد
55
+ font = ImageFont.truetype(font_path, font_size)
56
+ except Exception as e:
57
+ print(f"خطأ في تحميل الخط {font_path}: {str(e)}")
58
+ # استخدام الخط الافتراضي
59
+ font = ImageFont.load_default()
 
 
 
60
 
61
+ # تحضير النص
62
  if any('\u0600' <= c <= '\u06FF' for c in text):
63
+ text = prepare_arabic_text(text, font_path)
64
 
65
+ # حساب أبعاد النص
66
  text_bbox = draw.textbbox((0, 0), text, font=font)
67
  text_width = text_bbox[2] - text_bbox[0]
68
  text_height = text_bbox[3] - text_bbox[1]
69
 
70
+ # تحديد موقع النص
71
+ if text_position == 'center':
72
+ x = (size[0] - text_width) // 2
73
+ y = (size[1] - text_height) // 2
74
+ elif text_position == 'bottom':
75
+ x = (size[0] - text_width) // 2
76
+ y = size[1] - text_height - 20
77
+ elif text_position == 'top':
78
+ x = (size[0] - text_width) // 2
79
+ y = 20
80
+
81
+ # إضافة خلفية شبه شفافة للنص
82
+ padding = 10
83
+ background_box = [
84
+ x - padding,
85
+ y - padding,
86
+ x + text_width + padding,
87
+ y + text_height + padding
88
+ ]
89
+ draw.rectangle(background_box, fill=(0, 0, 0, 128))
90
 
91
  # رسم النص
92
+ draw.text((x, y), text, font=font, fill=text_color)
93
 
94
  return np.array(img)
95
 
96
+ def process_audio(audio_path, font_name="bein-normal.ttf", background_image=None,
97
+ text_position='center', editable_text=None):
98
+ """معالجة الملف الصوتي وإنشاء الفيديو"""
99
+ try:
100
+ if not isinstance(audio_path, str):
101
+ raise ValueError("يجب أن يكون المدخل مسار ملف صوتي")
102
+
103
+ if not os.path.exists(audio_path):
104
+ raise FileNotFoundError("الملف غير موجود")
105
+
106
+ # تحويل الصوت إلى نص
107
+ print("جاري تحويل الصوت إلى نص...")
108
+ result = model.transcribe(audio_path, language='ar') # تحديد اللغة العربية
109
+
110
+ # استخدام النص المعدل إذا تم توفيره
111
+ transcription = editable_text if editable_text else result["text"]
112
+ print("تم استخراج النص بنجاح")
113
+
114
+ # إنشاء الفيديو
115
+ print("جاري إنشاء الفيديو...")
116
+ font_path = os.path.join("fonts", font_name)
117
+ video_path = create_video_with_text(audio_path, transcription, font_path,
118
+ background_image, text_position)
119
+ print("تم إنشاء الفيديو بنجاح")
120
+
121
+ return video_path, transcription
122
+ except Exception as e:
123
+ print(f"خطأ في process_audio: {str(e)}")
124
+ return None, f"حدث خطأ أثناء المعالجة: {str(e)}"
125
 
126
+ def create_video_with_text(audio_path, transcription, font_path, background_image=None,
127
+ text_position='center'):
128
  """إنشاء فيديو مع نص متزامن"""
129
  try:
130
  # تحويل الملف الصوتي إلى WAV
 
134
  audio_clip = AudioFileClip(wav_path)
135
  duration = audio_clip.duration
136
 
137
+ # تقسيم النص إلى جمل
138
+ sentences = [s.strip() for s in transcription.split('.') if s.strip()]
139
+ if not sentences:
140
+ sentences = [transcription]
141
+
142
+ # حساب مدة كل جملة
143
+ sentence_duration = duration / len(sentences)
144
 
145
  # إنشاء قائمة المقاطع
146
  clips = []
147
  current_time = 0
 
148
 
149
+ for sentence in sentences:
 
 
 
150
  # إنشاء صورة للنص
151
+ text_image = create_text_image(
152
+ sentence,
153
+ font_path=font_path,
154
+ background_image=background_image,
155
+ text_position=text_position
156
+ )
157
 
158
  # تحويل الصورة إلى مقطع
159
+ text_clip = ImageClip(text_image).set_duration(sentence_duration)
160
 
161
  # إضافة المقطع مع توقيته
162
  clips.append(text_clip.set_start(current_time))
163
+ current_time += sentence_duration
164
 
165
  # دمج جميع المقاطع
166
  video = CompositeVideoClip(clips, size=(720, 480))
 
184
  print(f"خطأ في create_video_with_text: {str(e)}")
185
  raise
186
 
187
+ def convert_audio_to_wav(audio_path):
188
+ """تحويل الملف الصوتي إلى صيغة WAV"""
189
+ audio_path = Path(audio_path)
190
+ if audio_path.suffix.lower() != '.wav':
191
+ wav_path = audio_path.with_suffix('.wav')
192
+ audio = AudioSegment.from_file(str(audio_path))
193
+ audio.export(str(wav_path), format='wav')
194
+ return str(wav_path)
195
+ return str(audio_path)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
196
 
197
  # إنشاء واجهة Gradio
198
+ available_fonts = get_available_fonts()
199
+
200
  iface = gr.Interface(
201
  fn=process_audio,
202
  inputs=[
203
+ gr.Audio(type="filepath", label="قم بتحميل ملف صوتي (MP3 أو WAV)"),
204
+ gr.Dropdown(choices=available_fonts, value=available_fonts[0] if available_fonts else None,
205
+ label="اختر الخط"),
206
+ gr.Image(label="صورة الخلفية (اختياري)", type="filepath"),
207
+ gr.Radio(["top", "center", "bottom"], value="center",
208
+ label="موقع النص", info="اختر موقع النص في الفيديو"),
209
+ gr.Textbox(label="تعديل النص (اختياري)", placeholder="اترك فارغاً لاستخدام النص المستخرج تلقائياً")
210
  ],
211
  outputs=[
212
  gr.Video(label="الفيديو المنشأ"),
213
  gr.Textbox(label="النص المستخرج")
214
  ],
215
  title="محول الصوت إلى فيديو مع النص",
216
+ description="""
217
+ قم بتحميل ملف صوتي لإنشاء فيديو مع نص متزامن.
218
+ - يدعم اللغة العربية بشكل كامل
219
+ - يمكنك اختيار الخط المناسب
220
+ - يمكنك إضافة صورة خلفية
221
+ - يمكنك تحديد موقع النص
222
+ - يمكنك تعديل النص المستخرج
223
+ """,
224
  examples=[],
225
  cache_examples=False
226
  )