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()