kader1997 commited on
Commit
2b5f0e0
·
verified ·
1 Parent(s): 1e29ce3

Update app.py

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