kader1997 commited on
Commit
cf558fa
·
verified ·
1 Parent(s): 04fb6eb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +40 -61
app.py CHANGED
@@ -2,6 +2,7 @@ import os
2
  os.environ["IMAGE_MAGICK_BINARY"] = "/usr/bin/convert"
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
@@ -12,99 +13,77 @@ model = WhisperModel("large-v3", device="cpu", compute_type="int8")
12
  def process_arabic_text(text):
13
  return reshape(text) + "\n "
14
 
 
 
 
 
 
 
 
 
 
 
15
  def step_1_extract_words(video_path, progress=gr.Progress()):
16
- if not video_path:
17
- return None, "الرجاء رفع فيديو أولاً."
18
-
19
- progress(0, desc="جاري استخراج الكلمات...")
20
  segments, _ = model.transcribe(video_path, word_timestamps=True, language="ar")
21
-
22
- words_data = []
23
- for segment in segments:
24
- for word in segment.words:
25
- words_data.append([word.word.strip(), round(word.start, 2), round(word.end, 2)])
26
-
27
- df = pd.DataFrame(words_data, columns=["الكلمة", "البداية", "النهاية"])
28
- return df, "تم الاستخراج!"
29
 
30
  def step_2_render_video(video_path, df_edited, font_selection, text_color, font_size, progress=gr.Progress()):
31
- if video_path is None or df_edited is None or df_edited.empty:
32
- return None, "بيانات ناقصة."
33
 
34
- # التأكد من مسار الخط: إذا لم يجد الملف المرفوع سيستخدم Arial الافتراضي
35
- actual_font = font_selection if os.path.exists(font_selection) else "Arial-Bold"
 
 
 
36
 
37
- output_path = "output_final.mp4"
38
  video = VideoFileClip(video_path)
39
- w, h = int(video.w), int(video.h)
40
  clips = [video]
41
  words_list = df_edited.values.tolist()
42
  chunk_size = 3
43
 
44
- progress(0.1, desc="جاري معالجة النصوص بالإعدادات الجديدة...")
45
-
46
  for i in range(0, len(words_list), chunk_size):
47
- current_chunk = words_list[i : i + chunk_size]
48
- sentence = " ".join([str(r[0]) for r in current_chunk])
49
  clean_sentence = process_arabic_text(sentence)
50
 
51
- c_start = float(current_chunk[0][1])
52
- c_end = float(current_chunk[-1][2])
53
- duration = max(0.1, c_end - c_start)
54
 
55
- # إنشاء الكليب مع التأكد من تمرير اللون والخط بشكل صريح
56
  txt = TextClip(
57
  text=clean_sentence,
58
  font_size=int(font_size),
59
- color=text_color, # سيأخذ اللون من ColorPicker مباشرة
60
  stroke_color='black',
61
  stroke_width=1.5,
62
  font=actual_font,
63
  method='caption',
64
- size=(int(w * 0.85), None),
65
  text_align='center'
66
- ).with_start(c_start).with_duration(duration).with_position(('center', int(h * 0.65)))
67
 
68
  clips.append(txt)
69
 
70
- final_video = CompositeVideoClip(clips, size=(w, h))
71
-
72
- # تحسين سرعة المعالجة وتقليل المشاكل
73
- final_video.write_videofile(
74
- output_path,
75
- codec="libx264",
76
- audio_codec="aac",
77
- fps=video.fps,
78
- logger='bar',
79
- threads=4 # استخدام تعدد الخيوط لتسريع العملية
80
- )
81
-
82
- return output_path, f"تم الحفظ! اللون: {text_color}، الخط: {actual_font}"
83
 
84
  # --- الواجهة ---
85
  with gr.Blocks() as app:
86
- gr.Markdown("### 🎬 Caption Pro: تخصيص كامل")
87
-
88
  with gr.Row():
89
- v_in = gr.Video()
90
- v_out = gr.Video()
91
-
92
  with gr.Row():
93
- # تأكد من رفع هذه الملفات في Hugging Face (مثلاً Cairo-Bold.ttf)
94
- font_opt = gr.Dropdown(
95
- choices=["arialbd.ttf", "Cairo-Bold.ttf", "Almarai-Bold.ttf"],
96
- value="arialbd.ttf",
97
- label="نوع الخط"
98
- )
99
- color_opt = gr.ColorPicker(value="#FFFF00", label="لون النص")
100
- size_opt = gr.Slider(30, 150, value=70, label="حجم الخط")
101
 
102
- btn_1 = gr.Button("1. استخراج")
103
- table = gr.Dataframe(headers=[لكلمة", "البداية", "النهاية"], interactive=True)
104
- btn_2 = gr.Button("2. إنتاج الفيديو")
105
- status = gr.Textbox(label="الحالة")
106
 
107
- btn_1.click(step_1_extract_words, inputs=[v_in], outputs=[table, status])
108
- btn_2.click(step_2_render_video, inputs=[v_in, table, font_opt, color_opt, size_opt], outputs=[v_out, status])
109
 
110
  app.launch()
 
2
  os.environ["IMAGE_MAGICK_BINARY"] = "/usr/bin/convert"
3
  import gradio as gr
4
  import pandas as pd
5
+ import re # نحتاجه لتنظيف الألوان
6
  from faster_whisper import WhisperModel
7
  from moviepy import VideoFileClip, TextClip, CompositeVideoClip
8
  from arabic_reshaper import reshape
 
13
  def process_arabic_text(text):
14
  return reshape(text) + "\n "
15
 
16
+ def clean_color(color_str):
17
+ """دالة لتحويل أي صيغة لون غريبة إلى صيغة يفهمها البرنامج"""
18
+ if color_str.startswith('rgba'):
19
+ # استخراج الأرقام فقط وتحويلها لأرقام صحيحة
20
+ nums = re.findall(r"\d+\.?\d*", color_str)
21
+ if len(nums) >= 3:
22
+ r, g, b = int(float(nums[0])), int(float(nums[1])), int(float(nums[2]))
23
+ return f'rgb({r},{g},{b})'
24
+ return color_str
25
+
26
  def step_1_extract_words(video_path, progress=gr.Progress()):
27
+ if not video_path: return None, "الرجاء رفع فيديو."
 
 
 
28
  segments, _ = model.transcribe(video_path, word_timestamps=True, language="ar")
29
+ words_data = [[w.word.strip(), round(w.start, 2), round(w.end, 2)] for s in segments for w in s.words]
30
+ return pd.DataFrame(words_data, columns=["الكلمة", "البداية", "النهاية"]), "تم الاستخراج!"
 
 
 
 
 
 
31
 
32
  def step_2_render_video(video_path, df_edited, font_selection, text_color, font_size, progress=gr.Progress()):
33
+ if video_path is None or df_edited is None: return None, "بيانات ناقصة."
 
34
 
35
+ # تنظيف اللون قبل استخدامه لمنع خطأ ValueError
36
+ safe_color = clean_color(text_color)
37
+
38
+ # التأكد من وجود ملف الخط
39
+ actual_font = font_selection if os.path.exists(font_selection) else "DejaVu-Sans-Bold"
40
 
41
+ output_path = "final_fixed_video.mp4"
42
  video = VideoFileClip(video_path)
43
+ w, h = video.size
44
  clips = [video]
45
  words_list = df_edited.values.tolist()
46
  chunk_size = 3
47
 
 
 
48
  for i in range(0, len(words_list), chunk_size):
49
+ chunk = words_list[i : i + chunk_size]
50
+ sentence = " ".join([str(r[0]) for r in chunk])
51
  clean_sentence = process_arabic_text(sentence)
52
 
53
+ t_start, t_end = float(chunk[0][1]), float(chunk[-1][2])
 
 
54
 
 
55
  txt = TextClip(
56
  text=clean_sentence,
57
  font_size=int(font_size),
58
+ color=safe_color, # اللون النظيف هنا
59
  stroke_color='black',
60
  stroke_width=1.5,
61
  font=actual_font,
62
  method='caption',
63
+ size=(int(w * 0.8), None),
64
  text_align='center'
65
+ ).with_start(t_start).with_duration(max(0.1, t_end - t_start)).with_position(('center', int(h * 0.65)))
66
 
67
  clips.append(txt)
68
 
69
+ final = CompositeVideoClip(clips, size=(w, h))
70
+ final.write_videofile(output_path, codec="libx264", audio_codec="aac", fps=video.fps, logger='bar')
71
+ return output_path, f"تم بنجاح! اللون المستخدم: {safe_color}"
 
 
 
 
 
 
 
 
 
 
72
 
73
  # --- الواجهة ---
74
  with gr.Blocks() as app:
75
+ gr.Markdown("## 🎬 Caption Pro: Stable Version")
 
76
  with gr.Row():
77
+ v_in = gr.Video(); v_out = gr.Video()
 
 
78
  with gr.Row():
79
+ font_opt = gr.Dropdown(choices=["arialbd.ttf", "Cairo-Bold.ttf", "Almarai-Bold.ttf"], value="arialbd.ttf", label="الخط")
80
+ color_opt = gr.ColorPicker(value="#FFFF00", label="اللون")
81
+ size_opt = gr.Slider(30, 150, value=70, label="الحجم")
 
 
 
 
 
82
 
83
+ btn_1 = gr.Button("1. استخراج"); table = gr.Dataframe(interactive=True)
84
+ btn_2 = gr.Button("2. إنتاج الفيديو"); status = gr.Textbox()
 
 
85
 
86
+ btn_1.click(step_1_extract_words, [v_in], [table, status])
87
+ btn_2.click(step_2_render_video, [v_in, table, font_opt, color_opt, size_opt], [v_out, status])
88
 
89
  app.launch()