kader1997 commited on
Commit
4881671
·
verified ·
1 Parent(s): 051777c

Upload 3 files

Browse files
Files changed (3) hide show
  1. main.py +115 -0
  2. packages.txt +2 -0
  3. requirements.txt +6 -0
main.py ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import json
3
+ import gradio as gr
4
+ import pandas as pd # أضفنا هذا السطر
5
+ from faster_whisper import WhisperModel
6
+ from moviepy import VideoFileClip, TextClip, CompositeVideoClip
7
+ from arabic_reshaper import reshape
8
+ from bidi.algorithm import get_display
9
+
10
+ # --- الإعدادات الثابتة ---
11
+ JSON_DATA = "captions_data.json"
12
+ # في لينكس، نستخدم خطاً متوفراً في النظام أو نرفق ملف خط مع المشروع
13
+ FONT_PATH = "Arial" # أو اتركها فارغة وسيقوم ImageMagick باختيار الخط الافتراضي
14
+ # تحميل النموذج
15
+ model = WhisperModel("small", device="cpu", compute_type="int8")
16
+
17
+
18
+ def process_arabic_text(text):
19
+ reshaped_text = reshape(text)
20
+ bidi_text = get_display(reshaped_text)
21
+ return bidi_text + "\n "
22
+
23
+
24
+ def step_1_extract_words(video_path):
25
+ if not video_path:
26
+ return None, "الرجاء رفع ملف فيديو أولاً."
27
+
28
+ print("جاري استخراج الكلمات...")
29
+ segments, _ = model.transcribe(video_path, word_timestamps=True, language="ar")
30
+
31
+ words_data = []
32
+ for segment in segments:
33
+ for word in segment.words:
34
+ words_data.append([word.word.strip(), round(word.start, 2), round(word.end, 2)])
35
+
36
+ # تحويل لـ DataFrame ليعمل مع Gradio بشكل صحيح
37
+ df = pd.DataFrame(words_data, columns=["الكلمة", "البداية (ثانية)", "النهاية (ثانية)"])
38
+ return df, "تم الاستخراج! عدل الكلمات في الجدول ثم اضغط 'إنتاج الفيديو'."
39
+
40
+
41
+ def step_2_render_video(video_path, df_edited):
42
+ # إصلاح الخطأ: التحقق من وجود البيانات في DataFrame
43
+ if video_path is None or df_edited is None or df_edited.empty:
44
+ return None, "تأكد من وجود الفيديو والبيانات في الجدول."
45
+
46
+ output_path = "final_captioned_video.mp4"
47
+ video = VideoFileClip(video_path)
48
+ w, h = int(video.w), int(video.h)
49
+
50
+ clips = [video]
51
+
52
+ # تحويل DataFrame إلى قائمة صفوف لمعالجتها
53
+ words_list = df_edited.values.tolist()
54
+
55
+ print(f"جاري دمج {len(words_list)} كلمة...")
56
+
57
+ for row in words_list:
58
+ word_text = str(row[0])
59
+ start_t = float(row[1])
60
+ end_t = float(row[2])
61
+
62
+ clean_text = process_arabic_text(word_text)
63
+
64
+ # إنشاء النص مع إطار أسود (التعديل النهائي لإصدار 2.0)
65
+ # إنشاء النص بدون خلفية (Transparent Background)
66
+ txt_clip = TextClip(
67
+ text=clean_text,
68
+ font_size=85, # زيادة الحجم قليلاً لتعويض حذف الخلفية
69
+ color='yellow',
70
+ font=FONT_PATH,
71
+ stroke_color='black', # الحدود السوداء ضرورية جداً هنا لرؤية النص
72
+ stroke_width=2, # جعل الحدود أسمك لزيادة التباين
73
+ method='caption',
74
+ size=(int(w * 0.8), None), # ترك مساحة عرض كافية
75
+ text_align='center'
76
+ )
77
+
78
+ txt_clip = (txt_clip
79
+ .with_start(start_t)
80
+ .with_duration(max(0.1, end_t - start_t)) # ضمان مدة زمنية موجبة
81
+ .with_position(('center', int(h * 0.7))))
82
+
83
+ clips.append(txt_clip)
84
+
85
+ final_video = CompositeVideoClip(clips, size=(w, h))
86
+ final_video.write_videofile(output_path, codec="libx264", audio_codec="aac", fps=video.fps, logger='bar')
87
+
88
+ return output_path, "مبروك! تم إنتاج الفيديو بنجاح."
89
+
90
+
91
+ # --- بناء الواجهة ---
92
+ with gr.Blocks(title="Caption Pro") as app:
93
+ gr.Markdown("# 🎬 محرر الكابشن العربي الاحترافي")
94
+
95
+ with gr.Row():
96
+ video_in = gr.Video(label="فيديو المدخلات")
97
+ video_out = gr.Video(label="الفيديو النهائي")
98
+
99
+ status = gr.Textbox(label="الحالة", interactive=False)
100
+
101
+ # استخدام Dataframe من Gradio
102
+ table = gr.Dataframe(
103
+ headers=["الكلمة", "البداية (ثانية)", "النهاية (ثانية)"],
104
+ datatype=["str", "number", "number"],
105
+ interactive=True
106
+ )
107
+
108
+ btn_extract = gr.Button("1. استخراج الكلمات", variant="primary")
109
+ btn_render = gr.Button("2. إنتاج الفيديو النهائي", variant="secondary")
110
+
111
+ btn_extract.click(step_1_extract_words, inputs=[video_in], outputs=[table, status])
112
+ btn_render.click(step_2_render_video, inputs=[video_in, table], outputs=[video_out, status])
113
+
114
+ if __name__ == "__main__":
115
+ app.launch()
packages.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ imagemagick
2
+ ffmpeg
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ faster-whisper
2
+ moviepy
3
+ arabic-reshaper
4
+ python-bidi
5
+ gradio
6
+ pandas