smvideo / app.py
Mahmoudmody777's picture
Update app.py
594f284 verified
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()