Spaces:
Sleeping
Sleeping
Upload 14 files
Browse files- background.png +0 -0
- export_button.png +0 -0
- export_button_hover.png +0 -0
- icons/facebook_icon.png +0 -0
- icons/facebook_icon_hover.png +0 -0
- icons/instagram_icon.png +0 -0
- icons/instagram_icon_hover.png +0 -0
- icons/twitter_icon.png +0 -0
- icons/twitter_icon_hover.png +0 -0
- icons/youtube_icon.png +0 -0
- icons/youtube_icon_hover.png +0 -0
- main.py +353 -0
- save_button.png +0 -0
- save_button_hover.png +0 -0
background.png
ADDED
![]() |
export_button.png
ADDED
![]() |
export_button_hover.png
ADDED
![]() |
icons/facebook_icon.png
ADDED
![]() |
icons/facebook_icon_hover.png
ADDED
![]() |
icons/instagram_icon.png
ADDED
![]() |
icons/instagram_icon_hover.png
ADDED
![]() |
icons/twitter_icon.png
ADDED
![]() |
icons/twitter_icon_hover.png
ADDED
![]() |
icons/youtube_icon.png
ADDED
![]() |
icons/youtube_icon_hover.png
ADDED
![]() |
main.py
ADDED
@@ -0,0 +1,353 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import tkinter as tk
|
3 |
+
from tkinter import ttk, messagebox
|
4 |
+
from PIL import Image, ImageTk
|
5 |
+
import requests
|
6 |
+
from bs4 import BeautifulSoup
|
7 |
+
import google.generativeai as genai
|
8 |
+
import json
|
9 |
+
from io import BytesIO
|
10 |
+
from moviepy.editor import ImageSequenceClip, AudioFileClip, concatenate_videoclips
|
11 |
+
import sys
|
12 |
+
import re
|
13 |
+
# إعدادات FFmpeg
|
14 |
+
root = tk.Tk()
|
15 |
+
root.title("أداة عمل المحتوى من قناة مدرسة الذكاء الاصطناعي")
|
16 |
+
root.geometry("930x820")
|
17 |
+
root.resizable(False, False)
|
18 |
+
|
19 |
+
if getattr(sys, 'frozen', False):
|
20 |
+
base_path = sys._MEIPASS # عند تشغيل ملف EXE
|
21 |
+
ffmpeg_exe = os.path.join(base_path, 'ffmpeg', 'ffmpeg.exe')
|
22 |
+
else:
|
23 |
+
base_path = os.path.dirname(os.path.abspath(__file__)) # عند تشغيل PyCharm
|
24 |
+
ffmpeg_exe = os.path.join(base_path, 'ffmpeg', 'ffmpeg.exe')
|
25 |
+
|
26 |
+
|
27 |
+
background_image_path = os.path.join(base_path, "background.png")
|
28 |
+
background_image = Image.open(background_image_path)
|
29 |
+
background_photo = ImageTk.PhotoImage(background_image)
|
30 |
+
|
31 |
+
canvas = tk.Canvas(root, width=930, height=820)
|
32 |
+
canvas.pack(fill="both", expand=True)
|
33 |
+
canvas.create_image(0, 0, image=background_photo, anchor="nw")
|
34 |
+
|
35 |
+
# إعدادات الأيقونات
|
36 |
+
icons = {
|
37 |
+
"YouTube": ("icons/youtube_icon.png", "icons/youtube_icon_hover.png", "https://youtube.com/@arabianAiSchool/"),
|
38 |
+
"Instagram": ("icons/instagram_icon.png", "icons/instagram_icon_hover.png", "https://www.instagram.com/arabianaischool"),
|
39 |
+
"Twitter": ("icons/twitter_icon.png", "icons/twitter_icon_hover.png", "https://twitter.com/arabianaischool"),
|
40 |
+
"Facebook": ("icons/facebook_icon.png", "icons/facebook_icon_hover.png", "https://www.facebook.com/arabianaischool")
|
41 |
+
}
|
42 |
+
|
43 |
+
icon_positions = [(300, 170), (370, 170), (440, 170), (510, 170)]
|
44 |
+
icon_labels = []
|
45 |
+
|
46 |
+
def on_enter_icon(event, icon_label, hover_photo):
|
47 |
+
icon_label.config(image=hover_photo)
|
48 |
+
|
49 |
+
def on_leave_icon(event, icon_label, photo):
|
50 |
+
icon_label.config(image=photo)
|
51 |
+
|
52 |
+
def open_link(url):
|
53 |
+
import webbrowser
|
54 |
+
webbrowser.open(url)
|
55 |
+
|
56 |
+
for (name, (icon_path, hover_icon_path, url)), (x, y) in zip(icons.items(), icon_positions):
|
57 |
+
icon_image = Image.open(os.path.join(base_path, icon_path))
|
58 |
+
icon_hover_image = Image.open(os.path.join(base_path, hover_icon_path))
|
59 |
+
|
60 |
+
icon_image = icon_image.resize((50, 50), Image.LANCZOS)
|
61 |
+
icon_hover_image = icon_hover_image.resize((50, 50), Image.LANCZOS)
|
62 |
+
|
63 |
+
icon_photo = ImageTk.PhotoImage(icon_image)
|
64 |
+
icon_hover_photo = ImageTk.PhotoImage(icon_hover_image)
|
65 |
+
|
66 |
+
icon_label = tk.Label(root, image=icon_photo, cursor="hand2", bg="#000000")
|
67 |
+
icon_label.image = icon_photo
|
68 |
+
icon_label.place(x=x, y=y)
|
69 |
+
icon_label.bind("<Button-1>", lambda e, url=url: open_link(url))
|
70 |
+
icon_label.bind("<Enter>", lambda e, icon_label=icon_label, hover_photo=icon_hover_photo: on_enter_icon(e, icon_label, hover_photo))
|
71 |
+
icon_label.bind("<Leave>", lambda e, icon_label=icon_label, photo=icon_photo: on_leave_icon(e, icon_label, photo))
|
72 |
+
icon_labels.append(icon_label)
|
73 |
+
|
74 |
+
# الحقول المدخلة
|
75 |
+
gemini_label = tk.Label(root, text="أدخل مفتاح جيميناي:", font=("Arial", 14, "bold"), bg="#000000", fg="#FFFFFF")
|
76 |
+
gemini_label.place(x=660, y=240)
|
77 |
+
gemini_entry = ttk.Entry(root, width=40, font=("Arial", 14))
|
78 |
+
gemini_entry.place(x=200, y=240)
|
79 |
+
|
80 |
+
eleven_label = tk.Label(root, text="أدخل مفتاح الفن لابس", font=("Arial", 14, "bold"), bg="#000000", fg="#FFFFFF")
|
81 |
+
eleven_label.place(x=660, y=280)
|
82 |
+
eleven_entry = ttk.Entry(root, width=40, font=("Arial", 14))
|
83 |
+
eleven_entry.place(x=200, y=280)
|
84 |
+
|
85 |
+
# تمكين النسخ واللصق في حقول الإدخال
|
86 |
+
def paste_into_entry(event, entry):
|
87 |
+
try:
|
88 |
+
entry.insert(tk.INSERT, root.clipboard_get())
|
89 |
+
except tk.TclError:
|
90 |
+
pass
|
91 |
+
|
92 |
+
def create_entry_context_menu(entry):
|
93 |
+
menu = tk.Menu(entry, tearoff=0)
|
94 |
+
menu.add_command(label="قص", command=lambda: entry.event_generate('<<Cut>>'))
|
95 |
+
menu.add_command(label="نسخ", command=lambda: entry.event_generate('<<Copy>>'))
|
96 |
+
menu.add_command(label="لصق", command=lambda: entry.event_generate('<<Paste>>'))
|
97 |
+
|
98 |
+
def show_context_menu(event):
|
99 |
+
menu.tk_popup(event.x_root, event.y_root)
|
100 |
+
return "break"
|
101 |
+
|
102 |
+
entry.bind("<Button-3>", show_context_menu) # للويندوز
|
103 |
+
entry.bind("<Button-2>", show_context_menu) # للماك
|
104 |
+
|
105 |
+
# ربط Ctrl+V بحقول الإدخال
|
106 |
+
gemini_entry.bind('<Control-v>', lambda event: paste_into_entry(event, gemini_entry))
|
107 |
+
eleven_entry.bind('<Control-v>', lambda event: paste_into_entry(event, eleven_entry))
|
108 |
+
|
109 |
+
# إنشاء قوائم منبثقة لحقول الإدخال
|
110 |
+
create_entry_context_menu(gemini_entry)
|
111 |
+
create_entry_context_menu(eleven_entry)
|
112 |
+
|
113 |
+
# قائمة نوع المحتوى مع الأنواع الجديدة
|
114 |
+
content_types = ["رياضي", "ترفيهي", "اخباري", "معلومات عامة", "تحفيزي"]
|
115 |
+
content_type_label = tk.Label(root, text="اختر نوع المحتوى", font=("Arial", 14, "bold"), bg="#000000", fg="#FFFFFF")
|
116 |
+
content_type_label.place(x=660, y=330)
|
117 |
+
content_type_combo = ttk.Combobox(root, values=content_types, font=("Arial", 14))
|
118 |
+
content_type_combo.place(x=400, y=330)
|
119 |
+
content_type_combo.current(0)
|
120 |
+
|
121 |
+
# قسم الجدولة
|
122 |
+
schedule_label = tk.Label(root, text="حدد وقت عمل الفيديو", font=("Arial", 14, "bold"), bg="#000000", fg="#FFFFFF")
|
123 |
+
schedule_label.place(x=660, y=380)
|
124 |
+
hour_label = tk.Label(root, text="ساعة", font=("Arial", 12, "bold"), bg="#000000", fg="#FFFFFF")
|
125 |
+
hour_label.place(x=600, y=380)
|
126 |
+
minute_label = tk.Label(root, text="دقيقة:", font=("Arial", 12, "bold"), bg="#000000", fg="#FFFFFF")
|
127 |
+
minute_label.place(x=400, y=380)
|
128 |
+
hour_entry = ttk.Combobox(root, values=[f"{i:02}" for i in range(24)], width=5, font=("Arial", 12))
|
129 |
+
hour_entry.place(x=490, y=380)
|
130 |
+
minute_entry = ttk.Combobox(root, values=[f"{i:02}" for i in range(60)], width=5, font=("Arial", 12))
|
131 |
+
minute_entry.place(x=280, y=380)
|
132 |
+
|
133 |
+
# تأثيرات الأزرار عند المرور عليها
|
134 |
+
def on_enter_save_button(event):
|
135 |
+
save_button.config(image=save_button_hover_photo)
|
136 |
+
|
137 |
+
def on_leave_save_button(event):
|
138 |
+
save_button.config(image=save_button_photo)
|
139 |
+
|
140 |
+
save_button_image_path = os.path.join(base_path, "save_button.png")
|
141 |
+
save_button_hover_image_path = os.path.join(base_path, "save_button_hover.png")
|
142 |
+
save_button_image = Image.open(save_button_image_path).resize((300, 70), Image.LANCZOS)
|
143 |
+
save_button_hover_image = Image.open(save_button_hover_image_path).resize((300, 70), Image.LANCZOS)
|
144 |
+
save_button_photo = ImageTk.PhotoImage(save_button_image)
|
145 |
+
save_button_hover_photo = ImageTk.PhotoImage(save_button_hover_image)
|
146 |
+
|
147 |
+
save_button = tk.Button(root, image=save_button_photo, command=lambda: print("Settings Saved"), borderwidth=0, bg="#000000")
|
148 |
+
save_button.place(x=340, y=450)
|
149 |
+
save_button.bind("<Enter>", on_enter_save_button)
|
150 |
+
save_button.bind("<Leave>", on_leave_save_button)
|
151 |
+
|
152 |
+
def on_enter_export_button(event):
|
153 |
+
export_button.config(image=export_button_hover_photo)
|
154 |
+
|
155 |
+
def on_leave_export_button(event):
|
156 |
+
export_button.config(image=export_button_photo)
|
157 |
+
|
158 |
+
export_button_image_path = os.path.join(base_path, "export_button.png")
|
159 |
+
export_button_hover_image_path = os.path.join(base_path, "export_button_hover.png")
|
160 |
+
export_button_image = Image.open(export_button_image_path).resize((300, 70), Image.LANCZOS)
|
161 |
+
export_button_hover_image = Image.open(export_button_hover_image_path).resize((300, 70), Image.LANCZOS)
|
162 |
+
export_button_photo = ImageTk.PhotoImage(export_button_image)
|
163 |
+
export_button_hover_photo = ImageTk.PhotoImage(export_button_hover_image)
|
164 |
+
|
165 |
+
export_button = tk.Button(root, image=export_button_photo, command=lambda: create_content(), borderwidth=0, bg="#000000")
|
166 |
+
export_button.place(x=340, y=570)
|
167 |
+
export_button.bind("<Enter>", on_enter_export_button)
|
168 |
+
export_button.bind("<Leave>", on_leave_export_button)
|
169 |
+
|
170 |
+
# وظيفة إنشاء النص بناءً على نوع المحتوى
|
171 |
+
def generate_script_based_on_content_type(api_key, content_type):
|
172 |
+
genai.configure(api_key=api_key)
|
173 |
+
if content_type == "رياضي":
|
174 |
+
prompt = "ااكتب نصًا باللغة العربية لفيديو مدته 60 ثانية لقناة يوتيوب متخصصة في حقائق كرة القدم. يجب أن يكون النص جذابًا ومثيرًا، يركز على قصة أو حقيقة عن لاعب كرة قدم أو مدرب أو حدث مهم في عالم كرة القدم. امزج بين الإثارة والواقعية. اذكر كيف غير هذا الشخص أو الحدث مسار مباراة أو بطولة مهمة بطريقة غير متوقعة. قم بتضمين دعوة للمشاهدين للإعجاب بالفيديو والتعليق والاشتراك في القناة لمزيد من الفيديوهات. اجعل الأسلوب حيويًا وشيقًا، مع التركيز على جذب الانتباه بسرعة. لا تذكر توجيهات مشهدية أو إشارات بصرية محددة في النص"
|
175 |
+
elif content_type == "ترفيهي":
|
176 |
+
prompt = "اكتب نصًا باللغة العربية لفيديو مدته 60 ثانية لقناة يوتيوب ترفيهية..."
|
177 |
+
elif content_type == "اخباري":
|
178 |
+
prompt = "اكتب نصًا باللغة العربية لفيديو مدته 60 ثانية لقناة يوتيوب إخبارية. يجب أن يكون النص دقيقًا ومثيرًا، يركز على خبر حديث أو حدث مهم يجري الآن في العالم أو المنطقة. امزج بين المعلومات والموضوعية. اذكر التفاصيل الأساسية وكيف يؤثر هذا الخبر على الجمهور أو المجتمع بشكل عام. قم بتضمين دعوة للمشاهدين للإعجاب بالفيديو والتعليق والاشتراك في القناة لمزيد من التحديثات الإخبارية. ��جعل الأسلوب واضحًا وجذابًا، مع التركيز على نقل المعلومة بسرعة وفعالية. لا تذكر توجيهات مشهدية أو إشارات بصرية محددة في النص."
|
179 |
+
elif content_type == "معلومات عامة":
|
180 |
+
prompt = "اكتب نصًا باللغة العربية لفيديو مدته 60 ثانية لقناة يوتيوب تقدم معلومات عامة مفيدة. يجب أن يكون النص مفيدًا ومثيرًا للاهتمام، يركز على معلومة أو حقيقة غير معروفة عن موضوع مثل العلوم، التاريخ، الثقافة، أو الطبيعة. امزج بين المعرفة والتشويق. اذكر كيف يمكن لهذه المعلومة أن توسع آفاق المشاهدين أو تغير فهمهم لموضوع معين. قم بتضمين دعوة للمشاهدين للإعجاب بالفيديو والتعليق والاشتراك في القناة لمزيد من المحتوى المثير للاهتمام. اجعل الأسلوب حيويًا وجاذبًا، مع التركيز على تقديم المعلومة بطريقة سهلة الفهم. لا تذكر توجيهات مشهدية أو إشارات بصرية محددة في النص"
|
181 |
+
elif content_type == "تحفيزي":
|
182 |
+
prompt = "اكتب نصًا باللغة العربية لفيديو مدته 60 ثانية لقناة يوتيوب تحفيزية. يجب أن يكون النص ملهمًا ومحفزًا، يركز على قصة نجاح، اقتباس مؤثر، أو رسالة تشجيعية تدفع المشاهدين لتحقيق أهدافهم. امزج بين الإلهام والواقعية. اذكر كيف يمكن للتفاني والإصرار أن يغير حياة الشخص بشكل إيجابي. قم بتضمين دعوة للمشاهدين للإعجاب بالفيديو والتعليق والاشتراك في القناة لمزيد من المحتوى التحفيزي. اجعل الأسلوب مؤثرًا وجاذبًا، مع التركيز على تحفيز المشاهدين لاتخاذ خطوات إيجابية. لا تذكر توجيهات مشهدية أو إشارات بصرية محددة في النص"
|
183 |
+
|
184 |
+
else:
|
185 |
+
prompt = ""
|
186 |
+
|
187 |
+
if not prompt:
|
188 |
+
return ""
|
189 |
+
|
190 |
+
model = genai.GenerativeModel('gemini-pro')
|
191 |
+
chat = model.start_chat(history=[])
|
192 |
+
response = chat.send_message(prompt)
|
193 |
+
return response.text
|
194 |
+
|
195 |
+
# تنظيف النص
|
196 |
+
def clean_script(script):
|
197 |
+
lines = script.split('\n')
|
198 |
+
cleaned_lines = [line for line in lines if not any(word in line.lower() for word in ['مشهد', 'صورة', 'لقطة'])]
|
199 |
+
return '\n'.join(cleaned_lines)
|
200 |
+
|
201 |
+
# إنشاء التعليق الصوتي باستخدام Eleven Labs API
|
202 |
+
def generate_voiceover(script, api_key):
|
203 |
+
try:
|
204 |
+
url = "https://api.elevenlabs.io/v1/text-to-speech/pNInz6obpgDQGcFmaJgB"
|
205 |
+
headers = {
|
206 |
+
"Accept": "audio/mpeg",
|
207 |
+
"Content-Type": "application/json",
|
208 |
+
"xi-api-key": api_key
|
209 |
+
}
|
210 |
+
data = {
|
211 |
+
"text": script,
|
212 |
+
"model_id": "eleven_multilingual_v2",
|
213 |
+
"voice_settings": {
|
214 |
+
"stability": 0.5,
|
215 |
+
"similarity_boost": 0.5
|
216 |
+
}
|
217 |
+
}
|
218 |
+
response = requests.post(url, json=data, headers=headers)
|
219 |
+
response.raise_for_status()
|
220 |
+
output_audio_filename = 'arabic_voiceover.mp3'
|
221 |
+
with open(output_audio_filename, 'wb') as f:
|
222 |
+
for chunk in response.iter_content(chunk_size=1024):
|
223 |
+
if chunk:
|
224 |
+
f.write(chunk)
|
225 |
+
print(f"تم إنشاء الصوت وحفظه كـ {output_audio_filename}")
|
226 |
+
return output_audio_filename
|
227 |
+
except Exception as e:
|
228 |
+
print(f"Error generating voiceover: {e}")
|
229 |
+
return None
|
230 |
+
|
231 |
+
# استخراج المصطلحات الأساسية للصور
|
232 |
+
def extract_arabic_key_terms(script):
|
233 |
+
words = re.findall(r'\b\w+\b', script)
|
234 |
+
return list(set(words))
|
235 |
+
|
236 |
+
# تنزيل صور عالية الجودة من Bing وتعديل حجمها
|
237 |
+
def download_images_from_bing(query, num_images, folder):
|
238 |
+
headers = {
|
239 |
+
"User-Agent": "Mozilla/5.0"
|
240 |
+
}
|
241 |
+
search_url = f"https://www.bing.com/images/search?q={query}&FORM=HDRSC2"
|
242 |
+
response = requests.get(search_url, headers=headers)
|
243 |
+
soup = BeautifulSoup(response.text, 'html.parser')
|
244 |
+
image_elements = soup.find_all('a', {'class': 'iusc'})
|
245 |
+
|
246 |
+
os.makedirs(folder, exist_ok=True)
|
247 |
+
image_count = 0
|
248 |
+
|
249 |
+
for i, img_element in enumerate(image_elements):
|
250 |
+
if image_count >= num_images:
|
251 |
+
break
|
252 |
+
m = img_element.get('m')
|
253 |
+
if m:
|
254 |
+
m = json.loads(m)
|
255 |
+
img_url = m['murl']
|
256 |
+
|
257 |
+
if img_url:
|
258 |
+
try:
|
259 |
+
img_data = requests.get(img_url, headers=headers, timeout=10).content
|
260 |
+
img = Image.open(BytesIO(img_data))
|
261 |
+
img = resize_and_crop_image(img)
|
262 |
+
img_filename = os.path.join(folder, f'image_{image_count + 1}.jpg')
|
263 |
+
img.save(img_filename, format='JPEG', quality=95)
|
264 |
+
image_count += 1
|
265 |
+
print(f"Downloaded {img_filename}")
|
266 |
+
except Exception as e:
|
267 |
+
print(f"Failed to download image {i + 1}: {e}")
|
268 |
+
|
269 |
+
# تعديل حجم الصورة إلى 1080x1920
|
270 |
+
def resize_and_crop_image(img):
|
271 |
+
target_size = (1080, 1920)
|
272 |
+
img_ratio = img.width / img.height
|
273 |
+
target_ratio = target_size[0] / target_size[1]
|
274 |
+
|
275 |
+
if img_ratio > target_ratio:
|
276 |
+
# قص العرض
|
277 |
+
new_width = int(img.height * target_ratio)
|
278 |
+
left = (img.width - new_width) // 2
|
279 |
+
img = img.crop((left, 0, left + new_width, img.height))
|
280 |
+
else:
|
281 |
+
# قص الارتفاع
|
282 |
+
new_height = int(img.width / target_ratio)
|
283 |
+
top = (img.height - new_height) // 2
|
284 |
+
img = img.crop((0, top, img.width, top + new_height))
|
285 |
+
|
286 |
+
img = img.resize(target_size, Image.LANCZOS)
|
287 |
+
return img
|
288 |
+
|
289 |
+
# إنشاء الفيديو مع الترجمة
|
290 |
+
def create_video_from_images_and_audio(image_folder, audio_filename):
|
291 |
+
image_files = sorted([os.path.join(image_folder, img) for img in os.listdir(image_folder) if img.endswith(".jpg")])
|
292 |
+
if not image_files:
|
293 |
+
messagebox.showwarning("تحذير", "لا توجد صور لإنشاء الفيديو.")
|
294 |
+
return
|
295 |
+
|
296 |
+
clips = []
|
297 |
+
duration_per_image = None
|
298 |
+
|
299 |
+
if audio_filename and os.path.exists(audio_filename):
|
300 |
+
audio_clip = AudioFileClip(audio_filename)
|
301 |
+
total_duration = audio_clip.duration
|
302 |
+
duration_per_image = total_duration / len(image_files)
|
303 |
+
else:
|
304 |
+
total_duration = len(image_files) * 3 # نفترض 3 ثواني لكل صورة
|
305 |
+
duration_per_image = 3
|
306 |
+
|
307 |
+
# إنشاء مقاطع الصور
|
308 |
+
for img_path in image_files:
|
309 |
+
img_clip = ImageSequenceClip([img_path], durations=[duration_per_image])
|
310 |
+
clips.append(img_clip)
|
311 |
+
|
312 |
+
video_clip = concatenate_videoclips(clips)
|
313 |
+
|
314 |
+
if audio_filename and os.path.exists(audio_filename):
|
315 |
+
video_clip = video_clip.set_audio(audio_clip)
|
316 |
+
|
317 |
+
# تحديد مسار سطح المكتب
|
318 |
+
desktop_path = os.path.join(os.path.join(os.environ['USERPROFILE']), 'Desktop')
|
319 |
+
output_video_path = os.path.join(desktop_path, "final_video.mp4")
|
320 |
+
|
321 |
+
video_clip.write_videofile(output_video_path, fps=24, codec="libx264", audio_codec="aac")
|
322 |
+
|
323 |
+
def create_content():
|
324 |
+
gemini_api_key = gemini_entry.get()
|
325 |
+
eleven_labs_api_key = eleven_entry.get()
|
326 |
+
content_type = content_type_combo.get()
|
327 |
+
|
328 |
+
script = generate_script_based_on_content_type(gemini_api_key, content_type)
|
329 |
+
if not script:
|
330 |
+
messagebox.showwarning("تحذير", "لا يوجد نص لتوليد المحتوى.")
|
331 |
+
return
|
332 |
+
|
333 |
+
cleaned_script = clean_script(script)
|
334 |
+
|
335 |
+
# إنشاء التعليق الصوتي
|
336 |
+
voiceover_filename = generate_voiceover(cleaned_script, eleven_labs_api_key)
|
337 |
+
|
338 |
+
# استخراج المصطلحات الأساسية
|
339 |
+
key_terms = extract_arabic_key_terms(cleaned_script)
|
340 |
+
|
341 |
+
# تنزيل الصور
|
342 |
+
total_images = 0
|
343 |
+
for term in key_terms:
|
344 |
+
download_images_from_bing(term, num_images=2, folder="visual")
|
345 |
+
total_images += 2 # نفترض صورتين لكل مصطلح
|
346 |
+
|
347 |
+
# إنشاء الفيديو
|
348 |
+
try:
|
349 |
+
create_video_from_images_and_audio("visual", voiceover_filename)
|
350 |
+
messagebox.showinfo("نجاح", "تم إنشاء المحتوى بنجاح!")
|
351 |
+
except Exception as e:
|
352 |
+
messagebox.showerror("خطأ", f"حدث خطأ أثناء إنشاء الفيديو: {e}")
|
353 |
+
root.mainloop()
|
save_button.png
ADDED
![]() |
save_button_hover.png
ADDED
![]() |