Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -1,21 +1,15 @@
|
|
1 |
import gradio as gr
|
2 |
import whisper
|
3 |
-
from moviepy.editor import VideoFileClip, AudioFileClip,
|
4 |
-
from moviepy.config import change_settings
|
5 |
import tempfile
|
6 |
import os
|
7 |
from pathlib import Path
|
8 |
import numpy as np
|
9 |
-
from PIL import ImageFont
|
10 |
import arabic_reshaper
|
11 |
from bidi.algorithm import get_display
|
12 |
-
import soundfile as sf
|
13 |
from pydub import AudioSegment
|
14 |
|
15 |
-
# تكوين MoviePy لاستخدام ImageMagick
|
16 |
-
if os.name == 'nt': # للويندوز
|
17 |
-
change_settings({"IMAGEMAGICK_BINARY": "magick"})
|
18 |
-
|
19 |
# تحميل نموذج Whisper
|
20 |
model = whisper.load_model("base")
|
21 |
|
@@ -25,8 +19,42 @@ def prepare_arabic_text(text):
|
|
25 |
bidi_text = get_display(reshaped_text)
|
26 |
return bidi_text
|
27 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
def convert_audio_to_wav(audio_path):
|
29 |
-
"""تحويل الملف الصوتي إلى صيغة WAV
|
30 |
audio_path = Path(audio_path)
|
31 |
if audio_path.suffix.lower() != '.wav':
|
32 |
wav_path = audio_path.with_suffix('.wav')
|
@@ -35,20 +63,6 @@ def convert_audio_to_wav(audio_path):
|
|
35 |
return str(wav_path)
|
36 |
return str(audio_path)
|
37 |
|
38 |
-
def create_text_frames(transcription, duration, fps=24):
|
39 |
-
"""إنشاء إطارات النص المتحركة"""
|
40 |
-
words = transcription.split()
|
41 |
-
words_per_frame = max(1, len(words) // int(duration * fps))
|
42 |
-
frames = []
|
43 |
-
|
44 |
-
for i in range(0, len(words), words_per_frame):
|
45 |
-
frame_words = ' '.join(words[i:i + words_per_frame])
|
46 |
-
if any('\u0600' <= c <= '\u06FF' for c in frame_words):
|
47 |
-
frame_words = prepare_arabic_text(frame_words)
|
48 |
-
frames.append(frame_words)
|
49 |
-
|
50 |
-
return frames
|
51 |
-
|
52 |
def create_video_with_text(audio_path, transcription):
|
53 |
"""إنشاء فيديو مع نص متزامن"""
|
54 |
try:
|
@@ -59,39 +73,32 @@ def create_video_with_text(audio_path, transcription):
|
|
59 |
audio_clip = AudioFileClip(wav_path)
|
60 |
duration = audio_clip.duration
|
61 |
|
62 |
-
#
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
background = ColorClip(size=(720, 480), color=(0, 0, 0))
|
67 |
-
|
68 |
-
# إنشاء مقاطع النص
|
69 |
-
text_clips = []
|
70 |
-
frame_duration = duration / len(frames)
|
71 |
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
fontsize=30,
|
77 |
-
color='white',
|
78 |
-
bg_color='black',
|
79 |
-
size=(720, 480),
|
80 |
-
method='caption',
|
81 |
-
font='Arial-Regular' # استخدام اسم خط كامل
|
82 |
-
).set_start(i * frame_duration).set_duration(frame_duration)
|
83 |
-
text_clips.append(txt_clip)
|
84 |
-
except Exception as e:
|
85 |
-
print(f"Error creating text clip for frame {i}: {str(e)}")
|
86 |
-
continue
|
87 |
|
88 |
-
|
89 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
90 |
|
91 |
# دمج جميع المقاطع
|
92 |
-
video = CompositeVideoClip(
|
93 |
-
[background.set_duration(duration)] + text_clips
|
94 |
-
)
|
95 |
video = video.set_audio(audio_clip)
|
96 |
|
97 |
# حفظ الفيديو
|
@@ -109,7 +116,7 @@ def create_video_with_text(audio_path, transcription):
|
|
109 |
return video_path
|
110 |
|
111 |
except Exception as e:
|
112 |
-
print(f"
|
113 |
raise
|
114 |
|
115 |
def process_audio(audio_path):
|
@@ -122,14 +129,19 @@ def process_audio(audio_path):
|
|
122 |
raise FileNotFoundError("الملف غير موجود")
|
123 |
|
124 |
# تحويل الصوت إلى نص
|
|
|
125 |
result = model.transcribe(audio_path)
|
126 |
transcription = result["text"]
|
|
|
127 |
|
128 |
# إنشاء الفيديو
|
|
|
129 |
video_path = create_video_with_text(audio_path, transcription)
|
|
|
130 |
|
131 |
return video_path, transcription
|
132 |
except Exception as e:
|
|
|
133 |
return None, f"حدث خطأ أثناء المعالجة: {str(e)}"
|
134 |
|
135 |
# إنشاء واجهة Gradio
|
|
|
1 |
import gradio as gr
|
2 |
import whisper
|
3 |
+
from moviepy.editor import VideoFileClip, AudioFileClip, ImageClip, CompositeVideoClip
|
|
|
4 |
import tempfile
|
5 |
import os
|
6 |
from pathlib import Path
|
7 |
import numpy as np
|
8 |
+
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 |
|
|
|
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')
|
|
|
63 |
return str(wav_path)
|
64 |
return str(audio_path)
|
65 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
66 |
def create_video_with_text(audio_path, transcription):
|
67 |
"""إنشاء فيديو مع نص متزامن"""
|
68 |
try:
|
|
|
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))
|
|
|
|
|
102 |
video = video.set_audio(audio_clip)
|
103 |
|
104 |
# حفظ الفيديو
|
|
|
116 |
return video_path
|
117 |
|
118 |
except Exception as e:
|
119 |
+
print(f"خطأ في create_video_with_text: {str(e)}")
|
120 |
raise
|
121 |
|
122 |
def process_audio(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
|