Spaces:
Sleeping
Sleeping
File size: 3,888 Bytes
2b5f0e0 2c93198 d71dcc3 2b5f0e0 41bfaac 2c93198 2b5f0e0 41bfaac d71dcc3 0561398 c5a8cc6 0561398 7d91661 2b5f0e0 cf558fa 0561398 cf558fa 0561398 d71dcc3 3d500a1 0561398 3d500a1 0561398 d71dcc3 0561398 2b5f0e0 62983bd cf558fa 2b5f0e0 cf558fa db158f3 0561398 2b5f0e0 cf558fa 2b5f0e0 d71dcc3 0561398 d6dd11f 0561398 253bd7c 0561398 253bd7c 0561398 04fb6eb d71dcc3 5f6e1b0 0561398 04fb6eb c5a8cc6 0561398 3a28f40 0561398 2b5f0e0 cf558fa 0561398 2b5f0e0 04fb6eb 0561398 2b5f0e0 cf558fa 62983bd 0561398 62983bd 0561398 7d91661 41bfaac 0561398 cf558fa 2c93198 d71dcc3 | 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 | import os
os.environ["IMAGE_MAGICK_BINARY"] = "/usr/bin/convert"
import gradio as gr
import pandas as pd
import re
from faster_whisper import WhisperModel
from moviepy import VideoFileClip, TextClip, CompositeVideoClip
from arabic_reshaper import reshape
# --- الإعدادات ---
model = WhisperModel("large-v3", device="cpu", compute_type="int8")
def process_arabic_text(text):
if not text: return ""
# 1. إعادة تشكيل الحروف العربية لتظهر متصلة وصحيحة (بدون النقاط الإضافية •)
reshaped = reshape(text)
# 2. إضافة سطر فارغ في الأسفل لمنع قص النقاط السفلية للأحرف
return reshaped + "\n "
def clean_color(color_str):
if color_str.startswith('rgba'):
nums = re.findall(r"\d+\.?\d*", color_str)
if len(nums) >= 3:
r, g, b = int(float(nums[0])), int(float(nums[1])), int(float(nums[2]))
return f'rgb({r},{g},{b})'
return color_str
def step_1_extract_words(video_path, progress=gr.Progress()):
if not video_path: return None, "الرجاء رفع فيديو."
segments, _ = model.transcribe(video_path, word_timestamps=True, language="ar")
words_data = []
for segment in segments:
for word in segment.words:
words_data.append([word.word.strip(), round(word.start, 2), round(word.end, 2)])
return pd.DataFrame(words_data, columns=["الكلمة", "البداية", "النهاية"]), "تم استخراج الكلمات!"
def step_2_render_video(video_path, df_edited, font_selection, text_color, font_size, progress=gr.Progress()):
if video_path is None or df_edited is None: return None, "بيانات ناقصة."
safe_color = clean_color(text_color)
actual_font = font_selection if os.path.exists(font_selection) else "DejaVu-Sans-Bold"
output_path = "final_clean_text_video.mp4"
video = VideoFileClip(video_path)
w, h = video.size
clips = [video]
words_list = df_edited.values.tolist()
for row in words_list:
word_text = str(row[0])
t_start = float(row[1])
t_end = float(row[2])
if not word_text.strip(): continue
clean_word = process_arabic_text(word_text)
txt = TextClip(
text=clean_word,
font_size=int(font_size),
color=safe_color,
stroke_color='black',
stroke_width=2.0, # تقليل سمك التحديد قليلاً ليتناسب مع النص الأصغر
font=actual_font,
method='label'
).with_start(t_start).with_duration(max(0.1, t_end - t_start)).with_position(('center', int(h * 0.5)))
clips.append(txt)
final = CompositeVideoClip(clips, size=(w, h))
final.write_videofile(output_path, codec="libx264", audio_codec="aac", fps=video.fps, logger='bar')
return output_path, "تم إنتاج الفيديو بنجاح!"
# --- الواجهة ---
with gr.Blocks() as app:
gr.Markdown("## 🎬 محرر الفيديو: نصوص نظيفة")
with gr.Row():
v_in = gr.Video(); v_out = gr.Video()
with gr.Row():
font_opt = gr.Dropdown(choices=["arialbd.ttf"], value="arialbd.ttf", label="الخط")
color_opt = gr.ColorPicker(value="#FF8C00", label="لون ذهبي برتقالي")
# تم تصغير الحجم الافتراضي من 130 إلى 90
size_opt = gr.Slider(30, 200, value=90, label="حجم النص")
btn_1 = gr.Button("1. تحليل الكلمات"); table = gr.Dataframe(interactive=True)
btn_2 = gr.Button("2. إنتاج الفيديو"); status = gr.Textbox()
btn_1.click(step_1_extract_words, [v_in], [table, status])
btn_2.click(step_2_render_video, [v_in, table, font_opt, color_opt, size_opt], [v_out, status])
app.launch()
|