kader1997 commited on
Commit
7d91661
·
verified ·
1 Parent(s): 3d500a1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +18 -19
app.py CHANGED
@@ -8,13 +8,16 @@ from moviepy import VideoFileClip, TextClip, CompositeVideoClip
8
  from arabic_reshaper import reshape
9
 
10
  # --- الإعدادات ---
11
- # استخدمنا cpu و int8 لضمان العمل على أغلب الأجهزة، يمكن تغييره لـ cuda إذا توفر GPU
12
  model = WhisperModel("large-v3", device="cpu", compute_type="int8")
13
 
14
  def process_arabic_text(text):
15
  if not text: return ""
16
- # معالجة النصوص العربية لتعرض بشكل صحيح (من اليمين لليسار وبدون حروف مقطعة)
17
- return reshape(text)
 
 
 
 
18
 
19
  def clean_color(color_str):
20
  if color_str.startswith('rgba'):
@@ -26,8 +29,6 @@ def clean_color(color_str):
26
 
27
  def step_1_extract_words(video_path, progress=gr.Progress()):
28
  if not video_path: return None, "الرجاء رفع فيديو."
29
-
30
- # تفعيل word_timestamps=True هو السر لاستخراج توقيت كل كلمة
31
  segments, _ = model.transcribe(video_path, word_timestamps=True, language="ar")
32
 
33
  words_data = []
@@ -35,7 +36,7 @@ def step_1_extract_words(video_path, progress=gr.Progress()):
35
  for word in segment.words:
36
  words_data.append([word.word.strip(), round(word.start, 2), round(word.end, 2)])
37
 
38
- return pd.DataFrame(words_data, columns=["الكلمة", "البداية", "النهاية"]), "تم استخراج الكلمات بدقة!"
39
 
40
  def step_2_render_video(video_path, df_edited, font_selection, text_color, font_size, progress=gr.Progress()):
41
  if video_path is None or df_edited is None: return None, "بيانات ناقصة."
@@ -43,14 +44,13 @@ def step_2_render_video(video_path, df_edited, font_selection, text_color, font_
43
  safe_color = clean_color(text_color)
44
  actual_font = font_selection if os.path.exists(font_selection) else "DejaVu-Sans-Bold"
45
 
46
- output_path = "final_word_by_word.mp4"
47
  video = VideoFileClip(video_path)
48
  w, h = video.size
49
  clips = [video]
50
 
51
  words_list = df_edited.values.tolist()
52
 
53
- # تحويل كل صف في الجدول (كلمة) إلى Clip مستقل يظهر في وقته
54
  for row in words_list:
55
  word_text = str(row[0])
56
  t_start = float(row[1])
@@ -58,38 +58,37 @@ def step_2_render_video(video_path, df_edited, font_selection, text_color, font_
58
 
59
  if not word_text.strip(): continue
60
 
 
61
  clean_word = process_arabic_text(word_text)
62
 
63
- # إنشاء كليب للكلمة الواحدة
64
  txt = TextClip(
65
  text=clean_word,
66
  font_size=int(font_size),
67
  color=safe_color,
68
  stroke_color='black',
69
- stroke_width=2,
70
  font=actual_font,
71
- method='label', # 'label' أفضل للكلمات المنفردة للحفاظ على جودتها
72
- ).with_start(t_start).with_duration(max(0.1, t_end - t_start)).with_position(('center', int(h * 0.5))) # وضعها في منتصف الشاشة تقريباً
73
 
74
  clips.append(txt)
75
 
76
- # دمج كل الكلمات فوق الفيديو الأصلي
77
  final = CompositeVideoClip(clips, size=(w, h))
78
  final.write_videofile(output_path, codec="libx264", audio_codec="aac", fps=video.fps, logger='bar')
79
- return output_path, "تم إنتاج الفيديو بنظام كلمة بكلمة!"
80
 
81
  # --- الواجهة ---
82
  with gr.Blocks() as app:
83
- gr.Markdown("## 🎬 Word-by-Word Captioner (Like Pro Apps)")
84
  with gr.Row():
85
  v_in = gr.Video(); v_out = gr.Video()
86
  with gr.Row():
87
  font_opt = gr.Dropdown(choices=["arialbd.ttf"], value="arialbd.ttf", label="الخط")
88
- color_opt = gr.ColorPicker(value="#00FF00", label="لون الكلمة (مثلاً أخضر)")
89
- size_opt = gr.Slider(50, 250, value=120, label="حجم الكلمة")
90
 
91
- btn_1 = gr.Button("1. تحليل الكلمات المنطوقة"); table = gr.Dataframe(interactive=True)
92
- btn_2 = gr.Button("2. إنشاء الفيديو النهائي"); status = gr.Textbox()
93
 
94
  btn_1.click(step_1_extract_words, [v_in], [table, status])
95
  btn_2.click(step_2_render_video, [v_in, table, font_opt, color_opt, size_opt], [v_out, status])
 
8
  from arabic_reshaper import reshape
9
 
10
  # --- الإعدادات ---
 
11
  model = WhisperModel("large-v3", device="cpu", compute_type="int8")
12
 
13
  def process_arabic_text(text):
14
  if not text: return ""
15
+ # 1. إضافة الشكل الجمالي (النقاط)
16
+ decorated_text = f"• {text} •"
17
+ # 2. إعادة تشكيل الحروف العربية لتظهر متصلة وصحيحة
18
+ reshaped = reshape(decorated_text)
19
+ # 3. إضافة سطر فارغ في الأسفل لمنع قص النقاط السفلية (مثل الياء والباء)
20
+ return reshaped + "\n "
21
 
22
  def clean_color(color_str):
23
  if color_str.startswith('rgba'):
 
29
 
30
  def step_1_extract_words(video_path, progress=gr.Progress()):
31
  if not video_path: return None, "الرجاء رفع فيديو."
 
 
32
  segments, _ = model.transcribe(video_path, word_timestamps=True, language="ar")
33
 
34
  words_data = []
 
36
  for word in segment.words:
37
  words_data.append([word.word.strip(), round(word.start, 2), round(word.end, 2)])
38
 
39
+ return pd.DataFrame(words_data, columns=["الكلمة", "البداية", "النهاية"]), "تم استخراج الكلمات!"
40
 
41
  def step_2_render_video(video_path, df_edited, font_selection, text_color, font_size, progress=gr.Progress()):
42
  if video_path is None or df_edited is None: return None, "بيانات ناقصة."
 
44
  safe_color = clean_color(text_color)
45
  actual_font = font_selection if os.path.exists(font_selection) else "DejaVu-Sans-Bold"
46
 
47
+ output_path = "final_fixed_dots_video.mp4"
48
  video = VideoFileClip(video_path)
49
  w, h = video.size
50
  clips = [video]
51
 
52
  words_list = df_edited.values.tolist()
53
 
 
54
  for row in words_list:
55
  word_text = str(row[0])
56
  t_start = float(row[1])
 
58
 
59
  if not word_text.strip(): continue
60
 
61
+ # النص هنا يحتوي الآن على السطر الفارغ الإضافي
62
  clean_word = process_arabic_text(word_text)
63
 
 
64
  txt = TextClip(
65
  text=clean_word,
66
  font_size=int(font_size),
67
  color=safe_color,
68
  stroke_color='black',
69
+ stroke_width=2.5,
70
  font=actual_font,
71
+ method='label' # 'label' تحافظ على حجم الكلمة وتتأثر بالسطر الجديد المضاف
72
+ ).with_start(t_start).with_duration(max(0.1, t_end - t_start)).with_position(('center', int(h * 0.5)))
73
 
74
  clips.append(txt)
75
 
 
76
  final = CompositeVideoClip(clips, size=(w, h))
77
  final.write_videofile(output_path, codec="libx264", audio_codec="aac", fps=video.fps, logger='bar')
78
+ return output_path, "تم الحفظ بنجاح مع ضمان ظهور النقاط السفلية!"
79
 
80
  # --- الواجهة ---
81
  with gr.Blocks() as app:
82
+ gr.Markdown("## 🎬 محرر الفيديو: حل مشكلة النقاط السفلية")
83
  with gr.Row():
84
  v_in = gr.Video(); v_out = gr.Video()
85
  with gr.Row():
86
  font_opt = gr.Dropdown(choices=["arialbd.ttf"], value="arialbd.ttf", label="الخط")
87
+ color_opt = gr.ColorPicker(value="#FF8C00", label="لون ذهبي برتقالي")
88
+ size_opt = gr.Slider(50, 250, value=130, label="حجم الكلمة")
89
 
90
+ btn_1 = gr.Button("1. تحليل الكلمات"); table = gr.Dataframe(interactive=True)
91
+ btn_2 = gr.Button("2. إنتاج الفيديو"); status = gr.Textbox()
92
 
93
  btn_1.click(step_1_extract_words, [v_in], [table, status])
94
  btn_2.click(step_2_render_video, [v_in, table, font_opt, color_opt, size_opt], [v_out, status])