File size: 7,411 Bytes
db1e44f
fa7bb31
3661e51
5e20b77
 
fa7bb31
 
3661e51
5e20b77
 
fa7bb31
57d8c78
625e33f
 
c5c002d
625e33f
 
 
 
 
0c44bc5
625e33f
fa7bb31
0c44bc5
 
 
 
 
 
 
5e20b77
625e33f
3661e51
625e33f
 
3661e51
 
625e33f
3661e51
625e33f
 
 
0c44bc5
 
625e33f
 
0c44bc5
3661e51
625e33f
 
3661e51
625e33f
 
3661e51
 
 
625e33f
 
3661e51
 
625e33f
3661e51
 
 
625e33f
 
 
 
 
 
 
 
 
fa7bb31
594f284
fa7bb31
6e25931
 
 
 
 
 
 
 
625e33f
 
 
 
6e25931
3661e51
 
 
625e33f
6e25931
625e33f
 
 
 
3661e51
594f284
3661e51
 
625e33f
3661e51
 
 
625e33f
 
 
 
6e25931
 
594f284
6e25931
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3661e51
6e25931
5e20b77
594f284
625e33f
 
 
 
 
 
 
 
 
 
 
 
 
 
594f284
 
 
625e33f
 
594f284
625e33f
 
 
 
 
 
c5c002d
b110f2d
c5c002d
ad7a29e
625e33f
0c44bc5
625e33f
 
 
 
594f284
 
 
 
 
625e33f
 
 
 
 
5e20b77
625e33f
 
c5c002d
 
625e33f
 
 
 
 
 
 
 
 
 
 
594f284
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
import gradio as gr
import whisper
from moviepy.editor import VideoFileClip, AudioFileClip, ImageClip, CompositeVideoClip
import tempfile
import os
from pathlib import Path
import numpy as np
from PIL import Image, ImageDraw, ImageFont
import arabic_reshaper
from bidi.algorithm import get_display
from pydub import AudioSegment

# تحميل نموذج Whisper
model = whisper.load_model("base")  # نموذج أفضل للغة العربية

# تحديد الخطوط المتاحة
FONTS = {
    "الخط المثنى": "fonts/Al-Mothnna.ttf",
    "خط بين": "fonts/bein-normal.ttf"
}

def prepare_arabic_text(text):
    """تحضير النص العربي للعرض بشكل صحيح"""
    try:
        reshaped_text = arabic_reshaper.reshape(text)
        bidi_text = get_display(reshaped_text)
        return bidi_text
    except Exception as e:
        print(f"خطأ في معالجة النص العربي: {str(e)}")
        return text

def create_text_image(text, font_name, size=(720, 480), font_size=30):
    """إنشاء صورة تحتوي على نص"""
    # إنشاء صورة جديدة مع خلفية سوداء
    img = Image.new('RGB', size, 'black')
    draw = ImageDraw.Draw(img)
    
    # تحميل الخط المحدد
    try:
        font_path = FONTS[font_name]
        if not os.path.exists(font_path):
            raise FileNotFoundError(f"الخط غير موجود: {font_path}")
        font = ImageFont.truetype(font_path, font_size)
    except Exception as e:
        print(f"خطأ في تحميل الخط: {str(e)}")
        # استخدام الخط الافتراضي في حالة الفشل
        font = ImageFont.load_default()

    # تحضير النص العربي
    prepared_text = prepare_arabic_text(text)
    
    # حساب موقع النص في وسط الصورة
    text_bbox = draw.textbbox((0, 0), prepared_text, font=font)
    text_width = text_bbox[2] - text_bbox[0]
    text_height = text_bbox[3] - text_bbox[1]
    
    x = (size[0] - text_width) // 2
    y = (size[1] - text_height) // 2
    
    # رسم النص
    draw.text((x, y), prepared_text, font=font, fill='white')
    
    return np.array(img)

def convert_audio_to_wav(audio_path):
    """تحويل الملف الصوتي إلى صيغة WAV"""
    audio_path = Path(audio_path)
    if audio_path.suffix.lower() != '.wav':
        wav_path = audio_path.with_suffix('.wav')
        audio = AudioSegment.from_file(str(audio_path))
        audio.export(str(wav_path), format='wav')
        return str(wav_path)
    return str(audio_path)

def create_video_with_text(audio_path, transcription, font_name, video_size):
    """إنشاء فيديو مع نص متزامن"""
    try:
        # تحويل الملف الصوتي إلى WAV
        wav_path = convert_audio_to_wav(audio_path)
        
        # تحميل الملف الصوتي
        audio_clip = AudioFileClip(wav_path)
        duration = audio_clip.duration
        
        # تقسيم النص إلى أجزاء
        words = transcription.split()
        total_frames = int(duration * 24)  # 24 FPS
        words_per_frame = max(1, len(words) // total_frames)
        
        # إنشاء قائمة المقاطع
        clips = []
        current_time = 0
        frame_duration = duration / (len(words) / words_per_frame)
        
        for i in range(0, len(words), words_per_frame):
            # تجميع الكلمات لهذا الإطار
            frame_words = ' '.join(words[i:i + words_per_frame])
            
            # إنشاء صورة للنص
            text_image = create_text_image(frame_words, font_name, size=video_size)
            
            # تحويل الصورة إلى مقطع
            text_clip = ImageClip(text_image).set_duration(frame_duration)
            
            # إضافة المقطع مع توقيته
            clips.append(text_clip.set_start(current_time))
            current_time += frame_duration
        
        if not clips:
            raise ValueError("لم يتم إنشاء أي مقاطع")
        
        # دمج جميع المقاطع
        video = CompositeVideoClip(clips, size=video_size)
        video = video.set_audio(audio_clip)
        
        # حفظ الفيديو
        temp_output = tempfile.NamedTemporaryFile(delete=False, suffix='.mp4')
        video_path = temp_output.name
        
        video.write_videofile(
            video_path,
            fps=24,
            codec='libx264',
            audio_codec='aac',
            verbose=False
        )
        
        return video_path
        
    except Exception as e:
        print(f"خطأ في create_video_with_text: {str(e)}")
        raise

def process_audio(audio_path, selected_font, video_orientation):
    """معالجة الملف الصوتي وإنشاء الفيديو"""
    try:
        if not isinstance(audio_path, str):
            raise ValueError("يجب أن يكون المدخل مسار ملف صوتي")
            
        if not os.path.exists(audio_path):
            raise FileNotFoundError("الملف غير موجود")
        
        # تحويل الصوت إلى نص
        print("جاري تحويل الصوت إلى نص...")
        result = model.transcribe(audio_path, language="ar")  # تحديد اللغة العربية
        transcription = result["text"]
        print("تم استخراج النص بنجاح")
        
        # تحديد حجم الفيديو بناءً على الاختيار
        video_size = (1280, 720) if video_orientation == 'أفقي' else (720, 1280)
        
        # إنشاء الفيديو
        print("جاري إنشاء الفيديو...")
        video_path = create_video_with_text(audio_path, transcription, selected_font, video_size)
        print("تم إنشاء الفيديو بنجاح")
        
        return video_path, transcription
    except Exception as e:
        print(f"خطأ في process_audio: {str(e)}")
        return None, f"حدث خطأ أثناء المعالجة: {str(e)}"

# إنشاء واجهة Gradio
iface = gr.Interface(
    fn=process_audio,
    inputs=[
        gr.Audio(type="filepath", label="قم بتحميل ملف صوتي (MP3 أو WAV)"),
        gr.Dropdown(
            choices=list(FONTS.keys()),
            value=list(FONTS.keys())[0],
            label="اختر الخط"
        ),
        gr.Dropdown(
            choices=["أفقي", "عمودي"],
            value="أفقي",
            label="اختيار اتجاه الفيديو"
        )
    ],
    outputs=[
        gr.Video(label="الفيديو المنشأ"),
        gr.Textbox(label="النص المستخرج")
    ],
    title="محول الصوت إلى فيديو مع النص",
    description="قم بتحميل ملف صوتي لإنشاء فيديو مع نص متزامن باللغة العربية.",
)

if __name__ == "__main__":
    # التحقق من وجود مجلد الخطوط
    if not os.path.exists("fonts"):
        print("تحذير: مجلد الخطوط غير موجود")
        os.makedirs("fonts")
        
    # التحقق من وجود الخطوط
    for font_name, font_path in FONTS.items():
        if not os.path.exists(font_path):
            print(f"تحذير: الخط {font_name} غير موجود في {font_path}")
            
    iface.launch()