gnosticdev commited on
Commit
c279930
·
verified ·
1 Parent(s): d5d45b2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +114 -33
app.py CHANGED
@@ -18,22 +18,18 @@ from io import BytesIO
18
  from PIL import Image
19
  import numpy as np
20
 
21
- # Configuración de dimensiones mínimas para las imágenes
22
  MIN_WIDTH = 1920
23
  MIN_HEIGHT = 1080
24
  TARGET_ASPECT_RATIO = 16/9
25
 
26
- # Define output and temp directories
27
  output_folder = "outputs"
28
  temp_dir = "temp_files"
29
  os.makedirs(output_folder, exist_ok=True)
30
  os.makedirs(temp_dir, exist_ok=True)
31
 
32
- # Google Drive folder ID
33
  FOLDER_ID = "12S6adpanAXjf71pKKGRRPqpzbJa5XEh3"
34
 
35
  def load_proxies(proxy_file="proxys.txt"):
36
- """Load proxies from a text file."""
37
  try:
38
  with open(proxy_file, 'r') as f:
39
  proxies = [line.strip() for line in f if line.strip()]
@@ -44,7 +40,6 @@ def load_proxies(proxy_file="proxys.txt"):
44
  return []
45
 
46
  def cleanup_temp_files():
47
- """Delete all temporary files from the temp_files folder."""
48
  for filename in os.listdir(temp_dir):
49
  file_path = os.path.join(temp_dir, filename)
50
  try:
@@ -54,7 +49,6 @@ def cleanup_temp_files():
54
  print(f"Error deleting {file_path}: {e}")
55
 
56
  def search_google_images(query, num_images=1):
57
- """Search for images using Google Custom Search API with size requirements."""
58
  try:
59
  api_key = os.getenv('GOOGLE_API_KEY')
60
  cse_id = os.getenv('GOOGLE_CSE_ID')
@@ -76,16 +70,15 @@ def search_google_images(query, num_images=1):
76
  service._http.http = session
77
  print(f"Trying with proxy: {proxy['http']}")
78
 
79
- # Especificar parámetros de búsqueda para imágenes grandes
80
  result = service.cse().list(
81
  q=query,
82
  cx=cse_id,
83
  searchType="image",
84
- num=num_images * 3, # Buscar más imágenes para filtrar por tamaño
85
  safe='off',
86
- imgSize='huge', # Preferir imágenes grandes
87
- imgType='photo', # Preferir fotos sobre dibujos
88
- rights='cc_publicdomain|cc_attribute|cc_sharealike', # Imágenes con licencia apropiada
89
  ).execute()
90
 
91
  if 'items' in result:
@@ -116,43 +109,30 @@ def search_google_images(query, num_images=1):
116
  return []
117
 
118
  def process_image(image):
119
- """Process and resize image to meet minimum requirements."""
120
  try:
121
- # Obtener dimensiones actuales
122
  width, height = image.size
123
-
124
- # Calcular relación de aspecto actual
125
  current_ratio = width / height
126
 
127
- # Determinar nuevas dimensiones manteniendo relación 16:9
128
  if current_ratio > TARGET_ASPECT_RATIO:
129
- # Imagen más ancha que 16:9
130
  new_width = max(MIN_WIDTH, width)
131
  new_height = int(new_width / TARGET_ASPECT_RATIO)
132
  else:
133
- # Imagen más alta que 16:9
134
  new_height = max(MIN_HEIGHT, height)
135
  new_width = int(new_height * TARGET_ASPECT_RATIO)
136
 
137
- # Redimensionar imagen
138
  image = image.resize((new_width, new_height), Image.Resampling.LANCZOS)
 
139
 
140
- # Crear fondo negro del tamaño objetivo
141
- background = Image.new('RGB', (MAX(new_width, MIN_WIDTH), MAX(new_height, MIN_HEIGHT)), 'black')
142
-
143
- # Centrar imagen en el fondo
144
  offset = ((background.width - image.width) // 2,
145
  (background.height - image.height) // 2)
146
  background.paste(image, offset)
147
 
148
  return background
149
-
150
  except Exception as e:
151
  print(f"Error processing image: {e}")
152
  return None
153
 
154
  def download_image(url):
155
- """Download and process image from URL using proxies."""
156
  proxies = load_proxies()
157
  if not proxies:
158
  proxies = [None]
@@ -162,13 +142,11 @@ def download_image(url):
162
  response = requests.get(url, proxies=proxy, timeout=10)
163
  image = Image.open(BytesIO(response.content))
164
 
165
- # Convertir a RGB si es necesario
166
  if image.mode in ('RGBA', 'LA') or (image.mode == 'P' and 'transparency' in image.info):
167
  background = Image.new('RGB', image.size, (0, 0, 0))
168
  background.paste(image, mask=image.split()[-1])
169
  image = background
170
 
171
- # Procesar imagen para cumplir requisitos de tamaño
172
  processed_image = process_image(image)
173
  if processed_image:
174
  return processed_image
@@ -179,18 +157,15 @@ def download_image(url):
179
  return None
180
 
181
  def create_animated_clip(image, duration=5, zoom_factor=1.1):
182
- """Create an animated clip from a still image with a zoom effect."""
183
  img_array = np.array(image)
184
  img_clip = ImageClip(img_array).set_duration(duration)
185
 
186
- # Asegurar que el clip tenga el tamaño correcto
187
  if img_clip.size[0] < MIN_WIDTH or img_clip.size[1] < MIN_HEIGHT:
188
  img_clip = img_clip.resize(width=MIN_WIDTH, height=MIN_HEIGHT)
189
 
190
  return img_clip.resize(lambda t: 1 + (zoom_factor - 1) * t / duration)
191
 
192
  def concatenate_google_images(keywords, clip_duration=5, num_images_per_keyword=1):
193
- """Concatenate Google Images based on keywords."""
194
  keyword_list = [keyword.strip() for keyword in keywords.split(",") if keyword.strip()]
195
  if not keyword_list:
196
  keyword_list = ["nature"]
@@ -216,9 +191,115 @@ def concatenate_google_images(keywords, clip_duration=5, num_images_per_keyword=
216
  random.shuffle(video_clips)
217
  return concatenate_videoclips(video_clips, method="compose")
218
 
219
- [... Resto del código se mantiene igual ...]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
 
221
- # Gradio interface
222
  with gr.Blocks() as demo:
223
  gr.Markdown("# Text-to-Video Generator")
224
  with gr.Row():
@@ -228,7 +309,7 @@ with gr.Blocks() as demo:
228
  mp3_file_input = gr.File(label="Upload background music (.mp3)", file_types=[".mp3"])
229
  keyword_input = gr.Textbox(
230
  label="Enter keywords separated by commas",
231
- value="fear, religion, god, demons, aliens, possession, galaxy, mysterious"
232
  )
233
  voices = asyncio.run(get_voices())
234
  voice_dropdown = gr.Dropdown(choices=list(voices.keys()), label="Select Voice")
 
18
  from PIL import Image
19
  import numpy as np
20
 
 
21
  MIN_WIDTH = 1920
22
  MIN_HEIGHT = 1080
23
  TARGET_ASPECT_RATIO = 16/9
24
 
 
25
  output_folder = "outputs"
26
  temp_dir = "temp_files"
27
  os.makedirs(output_folder, exist_ok=True)
28
  os.makedirs(temp_dir, exist_ok=True)
29
 
 
30
  FOLDER_ID = "12S6adpanAXjf71pKKGRRPqpzbJa5XEh3"
31
 
32
  def load_proxies(proxy_file="proxys.txt"):
 
33
  try:
34
  with open(proxy_file, 'r') as f:
35
  proxies = [line.strip() for line in f if line.strip()]
 
40
  return []
41
 
42
  def cleanup_temp_files():
 
43
  for filename in os.listdir(temp_dir):
44
  file_path = os.path.join(temp_dir, filename)
45
  try:
 
49
  print(f"Error deleting {file_path}: {e}")
50
 
51
  def search_google_images(query, num_images=1):
 
52
  try:
53
  api_key = os.getenv('GOOGLE_API_KEY')
54
  cse_id = os.getenv('GOOGLE_CSE_ID')
 
70
  service._http.http = session
71
  print(f"Trying with proxy: {proxy['http']}")
72
 
 
73
  result = service.cse().list(
74
  q=query,
75
  cx=cse_id,
76
  searchType="image",
77
+ num=num_images * 3,
78
  safe='off',
79
+ imgSize='huge',
80
+ imgType='photo',
81
+ rights='cc_publicdomain|cc_attribute|cc_sharealike'
82
  ).execute()
83
 
84
  if 'items' in result:
 
109
  return []
110
 
111
  def process_image(image):
 
112
  try:
 
113
  width, height = image.size
 
 
114
  current_ratio = width / height
115
 
 
116
  if current_ratio > TARGET_ASPECT_RATIO:
 
117
  new_width = max(MIN_WIDTH, width)
118
  new_height = int(new_width / TARGET_ASPECT_RATIO)
119
  else:
 
120
  new_height = max(MIN_HEIGHT, height)
121
  new_width = int(new_height * TARGET_ASPECT_RATIO)
122
 
 
123
  image = image.resize((new_width, new_height), Image.Resampling.LANCZOS)
124
+ background = Image.new('RGB', (max(new_width, MIN_WIDTH), max(new_height, MIN_HEIGHT)), 'black')
125
 
 
 
 
 
126
  offset = ((background.width - image.width) // 2,
127
  (background.height - image.height) // 2)
128
  background.paste(image, offset)
129
 
130
  return background
 
131
  except Exception as e:
132
  print(f"Error processing image: {e}")
133
  return None
134
 
135
  def download_image(url):
 
136
  proxies = load_proxies()
137
  if not proxies:
138
  proxies = [None]
 
142
  response = requests.get(url, proxies=proxy, timeout=10)
143
  image = Image.open(BytesIO(response.content))
144
 
 
145
  if image.mode in ('RGBA', 'LA') or (image.mode == 'P' and 'transparency' in image.info):
146
  background = Image.new('RGB', image.size, (0, 0, 0))
147
  background.paste(image, mask=image.split()[-1])
148
  image = background
149
 
 
150
  processed_image = process_image(image)
151
  if processed_image:
152
  return processed_image
 
157
  return None
158
 
159
  def create_animated_clip(image, duration=5, zoom_factor=1.1):
 
160
  img_array = np.array(image)
161
  img_clip = ImageClip(img_array).set_duration(duration)
162
 
 
163
  if img_clip.size[0] < MIN_WIDTH or img_clip.size[1] < MIN_HEIGHT:
164
  img_clip = img_clip.resize(width=MIN_WIDTH, height=MIN_HEIGHT)
165
 
166
  return img_clip.resize(lambda t: 1 + (zoom_factor - 1) * t / duration)
167
 
168
  def concatenate_google_images(keywords, clip_duration=5, num_images_per_keyword=1):
 
169
  keyword_list = [keyword.strip() for keyword in keywords.split(",") if keyword.strip()]
170
  if not keyword_list:
171
  keyword_list = ["nature"]
 
191
  random.shuffle(video_clips)
192
  return concatenate_videoclips(video_clips, method="compose")
193
 
194
+ def adjust_background_music(video_duration, music_file):
195
+ try:
196
+ music = AudioFileClip(music_file)
197
+ if music.duration < video_duration:
198
+ repetitions = int(video_duration / music.duration) + 1
199
+ music_clips = [music] * repetitions
200
+ music = concatenate_audioclips(music_clips)
201
+ music = music.subclip(0, video_duration)
202
+ return music.volumex(0.2)
203
+ except Exception as e:
204
+ print(f"Error adjusting music: {e}")
205
+ return None
206
+
207
+ def combine_audio_video(audio_file, video_clip, music_clip=None):
208
+ try:
209
+ audio_clip = AudioFileClip(audio_file)
210
+ total_duration = audio_clip.duration + 2
211
+
212
+ video_clip = video_clip.loop(duration=total_duration)
213
+ video_clip = video_clip.set_duration(total_duration).fadeout(2)
214
+
215
+ final_clip = video_clip.set_audio(audio_clip)
216
+ if music_clip:
217
+ music_clip = music_clip.set_duration(total_duration).audio_fadeout(2)
218
+ final_clip = final_clip.set_audio(CompositeAudioClip([audio_clip, music_clip]))
219
+
220
+ output_filename = f"final_video_{int(time.time())}.mp4"
221
+ output_path = os.path.join(output_folder, output_filename)
222
+
223
+ final_clip.write_videofile(output_path, codec="libx264", audio_codec="aac", fps=24)
224
+
225
+ final_clip.close()
226
+ video_clip.close()
227
+ audio_clip.close()
228
+ if music_clip:
229
+ music_clip.close()
230
+
231
+ return output_path
232
+ except Exception as e:
233
+ print(f"Error combining audio and video: {e}")
234
+ if 'final_clip' in locals():
235
+ final_clip.close()
236
+ return None
237
+
238
+ def upload_to_google_drive(file_path, folder_id):
239
+ try:
240
+ creds = service_account.Credentials.from_service_account_info(
241
+ json.loads(os.getenv('GOOGLE_SERVICE_ACCOUNT')),
242
+ scopes=['https://www.googleapis.com/auth/drive']
243
+ )
244
+ service = build('drive', 'v3', credentials=creds)
245
+
246
+ file_metadata = {
247
+ 'name': os.path.basename(file_path),
248
+ 'parents': [folder_id]
249
+ }
250
+ media = MediaFileUpload(file_path, resumable=True)
251
+ file = service.files().create(body=file_metadata, media_body=media, fields='id').execute()
252
+
253
+ permission = {
254
+ 'type': 'anyone',
255
+ 'role': 'reader'
256
+ }
257
+ service.permissions().create(fileId=file['id'], body=permission).execute()
258
+
259
+ file_id = file['id']
260
+ download_link = f"https://drive.google.com/uc?export=download&id={file_id}"
261
+ return download_link
262
+ except Exception as e:
263
+ print(f"Error uploading to Google Drive: {e}")
264
+ return None
265
+
266
+ def process_input(text, txt_file, mp3_file, selected_voice, rate, pitch, keywords):
267
+ try:
268
+ if text.strip():
269
+ final_text = text
270
+ elif txt_file is not None:
271
+ final_text = txt_file.decode("utf-8")
272
+ else:
273
+ raise ValueError("No text input provided")
274
+
275
+ audio_file = asyncio.run(text_to_speech(final_text, selected_voice, rate, pitch))
276
+ if not audio_file:
277
+ raise ValueError("Failed to generate audio")
278
+
279
+ video_clip = concatenate_google_images(keywords, clip_duration=5, num_images_per_keyword=1)
280
+ if not video_clip:
281
+ raise ValueError("Failed to generate video")
282
+
283
+ music_clip = None
284
+ if mp3_file is not None:
285
+ music_clip = adjust_background_music(video_clip.duration, mp3_file.name)
286
+
287
+ final_video_path = combine_audio_video(audio_file, video_clip, music_clip)
288
+ if not final_video_path:
289
+ raise ValueError("Failed to combine audio and video")
290
+
291
+ download_link = upload_to_google_drive(final_video_path, folder_id=FOLDER_ID)
292
+ if download_link:
293
+ print(f"Video uploaded to Google Drive. Download link: {download_link}")
294
+ return f"[Download video]({download_link})"
295
+ else:
296
+ raise ValueError("Error uploading video to Google Drive")
297
+ except Exception as e:
298
+ print(f"Error during processing: {e}")
299
+ return None
300
+ finally:
301
+ cleanup_temp_files()
302
 
 
303
  with gr.Blocks() as demo:
304
  gr.Markdown("# Text-to-Video Generator")
305
  with gr.Row():
 
309
  mp3_file_input = gr.File(label="Upload background music (.mp3)", file_types=[".mp3"])
310
  keyword_input = gr.Textbox(
311
  label="Enter keywords separated by commas",
312
+ value="fear, religion, god, demons, aliens, possession, galaxy, mysterious, dystopian, astral, warfare, space, space, galaxy, moon, fear, astral, god, evil, mystery, cosmos, stars, paranormal, inexplicable, hidden, enigma, unknown, unusual, intriguing, curious, strange, supernatural, esoteric, arcane, occultism, supernatural, mystery, phenomenon, rare, unusual, enigmatic, sinister, gloomy, dark, shadowy, macabre, eerie, chilling, cursed, fantastic, unreal, unknown, mysterious, enigmatic, inexplicable, unusual, strange, unusual, arcane, esoteric, hidden, shadowy, dark, gloomy, sinister, macabre, eerie, chilling, cursed, fantastic, unreal, paranormal, supernatural, occultism, phenomenon, rare, intriguing, curious"
313
  )
314
  voices = asyncio.run(get_voices())
315
  voice_dropdown = gr.Dropdown(choices=list(voices.keys()), label="Select Voice")