kader1997 commited on
Commit
41bfaac
·
verified ·
1 Parent(s): 253bd7c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +47 -46
app.py CHANGED
@@ -1,6 +1,5 @@
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
@@ -8,59 +7,56 @@ from moviepy import VideoFileClip, TextClip, CompositeVideoClip
8
  from arabic_reshaper import reshape
9
  from bidi.algorithm import get_display
10
 
11
- # --- الإعدادات الثابتة ---
12
- FONT_PATH = "arialbd.ttf" # تأكد من رفع ملف الخط للمساحة
13
  model = WhisperModel("large-v3", device="cpu", compute_type="int8")
14
 
15
- def process_arabic_text(text, is_active=False):
16
- """تجهيز النص العربي مع إمكانية إضافة تنسيق خاص للكلمة النشطة"""
17
- reshaped_text = reshape(text)
18
- # ملاحظة: MoviePy لا يدعم تلوين جزء من النص داخل TextClip واحد بسهولة عبر التاغات
19
- # لذلك سنعتمد على دمج الكلمات بشكل احترافي
20
- return reshaped_text
21
 
22
  def step_1_extract_words(video_path):
23
  if not video_path:
24
- return None, "الرجاء رفع ملف فيديو أولاً."
25
- print("جاري استخراج الكلمات...")
 
26
  segments, _ = model.transcribe(video_path, word_timestamps=True, language="ar")
27
  words_data = []
28
  for segment in segments:
29
  for word in segment.words:
30
  words_data.append([word.word.strip(), round(word.start, 2), round(word.end, 2)])
31
- df = pd.DataFrame(words_data, columns=["الكلمة", "البداية (ثانية)", "النهاية (ثانية)"])
32
- return df, "تم الاستخراج! يمكنك مراجعة الكلمات الآن."
 
33
 
34
  def step_2_render_video(video_path, df_edited):
35
  if video_path is None or df_edited is None or df_edited.empty:
36
- return None, "تأكد من وجود الفيديو والبيانات."
37
 
38
- output_path = "final_pro_video.mp4"
39
  video = VideoFileClip(video_path)
40
  w, h = int(video.w), int(video.h)
41
  clips = [video]
42
  words_list = df_edited.values.tolist()
43
 
44
- # حجم المجموعة (3 كلمات)
45
- chunk_size = 3
46
 
47
  for i in range(len(words_list)):
48
- # تحديد بداية ونهاية المجموعة الحالية (3 كلمات)
49
  start_chunk = (i // chunk_size) * chunk_size
50
  end_chunk = min(start_chunk + chunk_size, len(words_list))
51
  current_chunk = words_list[start_chunk:end_chunk]
52
 
53
- # 1. إنشاء الجملة الكاملة (باللون الأصفر) لتعمل كخلفية
54
- full_sentence = " ".join([r[0] for r in current_chunk])
55
- clean_sentence = reshape(full_sentence) # بدون قلب لأن السيرفر يدعم RTL
56
 
57
- # توقيت ظهور المجموعة (من بداية أول كلمة لنهاية آخر كلمة في المجموعة)
58
- chunk_start_time = float(current_chunk[0][1])
59
- chunk_end_time = float(current_chunk[-1][2])
60
 
61
- # طبقة الجملة كاملة (أصفر)
62
- bg_txt = TextClip(
63
- text=clean_sentence + "\n ",
64
  font_size=80,
65
  color='yellow',
66
  stroke_color='black',
@@ -69,14 +65,13 @@ def step_2_render_video(video_path, df_edited):
69
  font=FONT_PATH,
70
  size=(int(w * 0.9), None),
71
  text_align='center'
72
- ).with_start(chunk_start_time).with_duration(chunk_end_time - chunk_start_time).with_position(('center', int(h * 0.75)))
73
-
74
- # 2. طبقة الكلمة النشطة (أبيض) تظهر فقط في وقتها
75
- # ملاحظة: لجعلها احترافية 100% سنغير لون الجملة للأبيض بالكامل في وقت الكلمة الحالية
76
- active_txt = TextClip(
77
- text=clean_sentence + "\n ",
78
  font_size=80,
79
- color='white', # الكلمة النشطة تضيء الجملة بالأبيض
80
  stroke_color='black',
81
  stroke_width=2,
82
  method='caption',
@@ -85,23 +80,29 @@ def step_2_render_video(video_path, df_edited):
85
  text_align='center'
86
  ).with_start(float(words_list[i][1])).with_duration(max(0.1, float(words_list[i][2]) - float(words_list[i][1]))).with_position(('center', int(h * 0.75)))
87
 
88
- clips.append(bg_txt)
89
- clips.append(active_txt)
90
 
91
  final_video = CompositeVideoClip(clips, size=(w, h))
92
  final_video.write_videofile(output_path, codec="libx264", audio_codec="aac", fps=video.fps)
93
- return output_path, "مبروك! تم إنتاج الفيديو بنمط المحترفين."
94
 
95
- # --- الواجهة (نفس واجهتك السابقة) ---
96
- with gr.Blocks(title="Caption Pro V2") as app:
97
- gr.Markdown("# 🎬 محرر الكابشن: جمل 3 كلمات")
 
98
  with gr.Row():
99
- video_in = gr.Video()
100
- video_out = gr.Video()
 
 
101
  table = gr.Dataframe(headers=["الكلمة", "البداية", "النهاية"], interactive=True)
102
- btn_ex = gr.Button("1. استخراج")
103
- btn_re = gr.Button("2. إنتاج")
104
- btn_ex.click(step_1_extract_words, inputs=[video_in], outputs=[table, video_in])
105
- btn_re.click(step_2_render_video, inputs=[video_in, table], outputs=[video_out, video_in])
 
 
 
106
 
107
  app.launch()
 
1
  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
 
7
  from arabic_reshaper import reshape
8
  from bidi.algorithm import get_display
9
 
10
+ # --- الإعدادات ---
11
+ FONT_PATH = "arialbd.ttf" # تأكد من رفع هذا الملف في Hugging Face
12
  model = WhisperModel("large-v3", device="cpu", compute_type="int8")
13
 
14
+ def process_arabic_text(text):
15
+ return reshape(text) + "\n "
 
 
 
 
16
 
17
  def step_1_extract_words(video_path):
18
  if not video_path:
19
+ return None, "الرجاء رفع فيديو أولاً."
20
+
21
+ # استخراج الكلمات بدقة large-v3
22
  segments, _ = model.transcribe(video_path, word_timestamps=True, language="ar")
23
  words_data = []
24
  for segment in segments:
25
  for word in segment.words:
26
  words_data.append([word.word.strip(), round(word.start, 2), round(word.end, 2)])
27
+
28
+ df = pd.DataFrame(words_data, columns=["الكلمة", "البداية", "النهاية"])
29
+ return df, "تم الاستخراج بنجاح! راجع الجدول ثم اضغط إنتاج."
30
 
31
  def step_2_render_video(video_path, df_edited):
32
  if video_path is None or df_edited is None or df_edited.empty:
33
+ return None, "بيانات ناقصة."
34
 
35
+ output_path = "output_pro.mp4"
36
  video = VideoFileClip(video_path)
37
  w, h = int(video.w), int(video.h)
38
  clips = [video]
39
  words_list = df_edited.values.tolist()
40
 
41
+ chunk_size = 3 # عدد الكلمات في المجموعة
 
42
 
43
  for i in range(len(words_list)):
44
+ # تحديد المجموعة (الجملة)
45
  start_chunk = (i // chunk_size) * chunk_size
46
  end_chunk = min(start_chunk + chunk_size, len(words_list))
47
  current_chunk = words_list[start_chunk:end_chunk]
48
 
49
+ # بناء الجملة
50
+ sentence = " ".join([str(r[0]) for r in current_chunk])
51
+ clean_sentence = process_arabic_text(sentence)
52
 
53
+ # توقيت المجموعة الكاملة
54
+ c_start = float(current_chunk[0][1])
55
+ c_end = float(current_chunk[-1][2])
56
 
57
+ # 1. طبقة الجملة اللون الأصفر) - تظهر طوال مدة المجموعة
58
+ bg_clip = TextClip(
59
+ text=clean_sentence,
60
  font_size=80,
61
  color='yellow',
62
  stroke_color='black',
 
65
  font=FONT_PATH,
66
  size=(int(w * 0.9), None),
67
  text_align='center'
68
+ ).with_start(c_start).with_duration(c_end - c_start).with_position(('center', int(h * 0.75)))
69
+
70
+ # 2. طبقة "الكلمة النشطة" (باللون الأبيض) - تضيء فوق الجملة في وقتها المحدد
71
+ active_clip = TextClip(
72
+ text=clean_sentence,
 
73
  font_size=80,
74
+ color='white',
75
  stroke_color='black',
76
  stroke_width=2,
77
  method='caption',
 
80
  text_align='center'
81
  ).with_start(float(words_list[i][1])).with_duration(max(0.1, float(words_list[i][2]) - float(words_list[i][1]))).with_position(('center', int(h * 0.75)))
82
 
83
+ clips.append(bg_clip)
84
+ clips.append(active_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)
88
+ return output_path, "تم إنتاج الفيديو بنمط احترافي!"
89
 
90
+ # --- بناء الواجهة (تصحيح ربط المخرجات) ---
91
+ with gr.Blocks() as app:
92
+ gr.Markdown("# 🎬 Caption Pro - 3 Words Style")
93
+
94
  with gr.Row():
95
+ video_in = gr.Video(label="Input")
96
+ video_out = gr.Video(label="Output")
97
+
98
+ status = gr.Textbox(label="Status")
99
  table = gr.Dataframe(headers=["الكلمة", "البداية", "النهاية"], interactive=True)
100
+
101
+ btn_ex = gr.Button("1. استخراج الكلمات", variant="primary")
102
+ btn_re = gr.Button("2. إنتاج الفيديو", variant="secondary")
103
+
104
+ # تصحيح الربط هنا: outputs تتبع ترتيب القيم الراجعة من الدالة
105
+ btn_ex.click(step_1_extract_words, inputs=[video_in], outputs=[table, status])
106
+ btn_re.click(step_2_render_video, inputs=[video_in, table], outputs=[video_out, status])
107
 
108
  app.launch()