gnosticdev commited on
Commit
2d46d59
·
verified ·
1 Parent(s): a3cb7cc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +93 -85
app.py CHANGED
@@ -21,7 +21,7 @@ import numpy as np
21
 
22
  MIN_WIDTH = 1920
23
  MIN_HEIGHT = 1080
24
- TARGET_ASPECT_RATIO = 16/9
25
 
26
  output_folder = "outputs"
27
  temp_dir = "temp_files"
@@ -30,74 +30,67 @@ os.makedirs(temp_dir, exist_ok=True)
30
 
31
  FOLDER_ID = "12S6adpanAXjf71pKKGRRPqpzbJa5XEh3"
32
 
 
33
  def load_proxies(proxy_file="proxys.txt"):
34
  try:
35
  with open(proxy_file, 'r') as f:
36
  proxies = [line.strip() for line in f if line.strip()]
37
  print(f"Loaded {len(proxies)} proxies from file")
38
- return [requests_proxy.ProxyInfo(proxy=f"http://{proxy}") for proxy in proxies]
39
  except Exception as e:
40
  print(f"Error loading proxies: {e}")
41
  return []
42
 
 
43
  def search_google_images(query, num_images=1):
44
  try:
45
  api_key = os.getenv('GOOGLE_API_KEY')
46
  cse_id = os.getenv('GOOGLE_CSE_ID')
47
  proxies = load_proxies()
48
-
49
  print(f"Buscando imágenes para: {query}")
50
-
51
- if not proxies:
52
- print("No proxies available, trying without proxy")
53
- with requests.Session() as session:
54
- result = session.get(
55
- f"https://www.googleapis.com/customsearch/v1",
56
- params={
57
- "q": query,
58
- "cx": cse_id,
59
- "searchType": "image",
60
- "num": num_images * 3,
61
- "safe": 'off',
62
- "imgSize": 'LARGE',
63
- "imgType": 'imgTypeUndefined',
64
- "rights": 'cc_publicdomain|cc_attribute|cc_sharealike',
65
- "key": api_key
66
- }
67
- ).json()
68
- else:
69
- with requests_proxy.ProxyManager(proxies) as proxy_manager:
70
- result = proxy_manager.get(
71
- f"https://www.googleapis.com/customsearch/v1",
72
- params={
73
- "q": query,
74
- "cx": cse_id,
75
- "searchType": "image",
76
- "num": num_images * 3,
77
- "safe": 'off',
78
- "imgSize": 'LARGE',
79
- "imgType": 'imgTypeUndefined',
80
- "rights": 'cc_publicdomain|cc_attribute|cc_sharealike',
81
- "key": api_key
82
- }
83
- ).json()
84
  else:
85
- with requests_proxy.ProxyManager(proxies) as proxy_manager:
86
- result = proxy_manager.get(
87
- f"https://www.googleapis.com/customsearch/v1",
88
- params={
89
- "q": query,
90
- "cx": cse_id,
91
- "searchType": "image",
92
- "num": num_images * 3,
93
- "safe": 'off',
94
- "imgSize": 'HUGE',
95
- "imgType": 'photo',
96
- "rights": 'cc_publicdomain|cc_attribute|cc_sharealike',
97
- "key": api_key
98
- }
99
- ).json()
100
-
101
  if 'items' in result:
102
  image_urls = []
103
  for item in result.get('items', []):
@@ -108,80 +101,81 @@ def search_google_images(query, num_images=1):
108
  image_urls.append(item['link'])
109
  if len(image_urls) >= num_images:
110
  break
111
-
112
  print(f"Encontradas {len(image_urls)} imágenes de tamaño adecuado")
113
  return image_urls
114
-
115
  print("No se encontraron imágenes después de probar todos los proxies")
116
  return []
117
-
118
  except Exception as e:
119
  print(f"Error general en la búsqueda de imágenes: {str(e)}")
120
  return []
121
 
122
-
123
  def process_image(image):
124
  try:
125
  width, height = image.size
126
  current_ratio = width / height
127
-
128
  if current_ratio > TARGET_ASPECT_RATIO:
129
  new_width = max(MIN_WIDTH, width)
130
  new_height = int(new_width / TARGET_ASPECT_RATIO)
131
  else:
132
  new_height = max(MIN_HEIGHT, height)
133
  new_width = int(new_height * TARGET_ASPECT_RATIO)
134
-
135
  image = image.resize((new_width, new_height), Image.Resampling.LANCZOS)
136
  background = Image.new('RGB', (max(new_width, MIN_WIDTH), max(new_height, MIN_HEIGHT)), 'black')
137
-
138
- offset = ((background.width - image.width) // 2,
139
- (background.height - image.height) // 2)
140
  background.paste(image, offset)
141
-
142
  return background
143
  except Exception as e:
144
  print(f"Error processing image: {e}")
145
  return None
146
 
 
147
  def download_image(url):
148
  proxies = load_proxies()
149
  if not proxies:
150
  proxies = [None]
151
-
152
  for proxy in proxies:
153
  try:
154
  response = requests.get(url, proxies=proxy, timeout=10)
155
  image = Image.open(BytesIO(response.content))
156
-
157
  if image.mode in ('RGBA', 'LA') or (image.mode == 'P' and 'transparency' in image.info):
158
  background = Image.new('RGB', image.size, (0, 0, 0))
159
  background.paste(image, mask=image.split()[-1])
160
  image = background
161
-
162
  processed_image = process_image(image)
163
  if processed_image:
164
  return processed_image
165
-
166
  except Exception as e:
167
  print(f"Error downloading image with proxy {proxy}: {e}")
168
  continue
169
  return None
170
 
 
171
  def create_animated_clip(image, duration=5, zoom_factor=1.1):
172
  img_array = np.array(image)
173
  img_clip = ImageClip(img_array).set_duration(duration)
174
-
175
  if img_clip.size[0] < MIN_WIDTH or img_clip.size[1] < MIN_HEIGHT:
176
  img_clip = img_clip.resize(width=MIN_WIDTH, height=MIN_HEIGHT)
177
-
178
  return img_clip.resize(lambda t: 1 + (zoom_factor - 1) * t / duration)
179
 
 
180
  def concatenate_google_images(keywords, clip_duration=5, num_images_per_keyword=1):
181
  keyword_list = [keyword.strip() for keyword in keywords.split(",") if keyword.strip()]
182
  if not keyword_list:
183
  keyword_list = ["nature"]
184
-
185
  video_clips = []
186
  for keyword in keyword_list:
187
  try:
@@ -196,13 +190,14 @@ def concatenate_google_images(keywords, clip_duration=5, num_images_per_keyword=
196
  except Exception as e:
197
  print(f"Error processing keyword '{keyword}': {e}")
198
  continue
199
-
200
  if not video_clips:
201
  return ColorClip(size=(MIN_WIDTH, MIN_HEIGHT), color=[0, 0, 0], duration=5)
202
-
203
  random.shuffle(video_clips)
204
  return concatenate_videoclips(video_clips, method="compose")
205
 
 
206
  def adjust_background_music(video_duration, music_file):
207
  try:
208
  music = AudioFileClip(music_file)
@@ -216,30 +211,31 @@ def adjust_background_music(video_duration, music_file):
216
  print(f"Error adjusting music: {e}")
217
  return None
218
 
 
219
  def combine_audio_video(audio_file, video_clip, music_clip=None):
220
  try:
221
  audio_clip = AudioFileClip(audio_file)
222
  total_duration = audio_clip.duration + 2
223
-
224
  video_clip = video_clip.loop(duration=total_duration)
225
  video_clip = video_clip.set_duration(total_duration).fadeout(2)
226
-
227
  final_clip = video_clip.set_audio(audio_clip)
228
  if music_clip:
229
  music_clip = music_clip.set_duration(total_duration).audio_fadeout(2)
230
  final_clip = final_clip.set_audio(CompositeAudioClip([audio_clip, music_clip]))
231
-
232
  output_filename = f"final_video_{int(time.time())}.mp4"
233
  output_path = os.path.join(output_folder, output_filename)
234
-
235
  final_clip.write_videofile(output_path, codec="libx264", audio_codec="aac", fps=24)
236
-
237
  final_clip.close()
238
  video_clip.close()
239
  audio_clip.close()
240
  if music_clip:
241
  music_clip.close()
242
-
243
  return output_path
244
  except Exception as e:
245
  print(f"Error combining audio and video: {e}")
@@ -247,6 +243,7 @@ def combine_audio_video(audio_file, video_clip, music_clip=None):
247
  final_clip.close()
248
  return None
249
 
 
250
  def upload_to_google_drive(file_path, folder_id):
251
  try:
252
  creds = service_account.Credentials.from_service_account_info(
@@ -275,6 +272,17 @@ def upload_to_google_drive(file_path, folder_id):
275
  print(f"Error uploading to Google Drive: {e}")
276
  return None
277
 
 
 
 
 
 
 
 
 
 
 
 
278
  def process_input(text, txt_file, mp3_file, selected_voice, rate, pitch, keywords):
279
  try:
280
  if text.strip():
@@ -283,26 +291,25 @@ def process_input(text, txt_file, mp3_file, selected_voice, rate, pitch, keyword
283
  final_text = txt_file.decode("utf-8")
284
  else:
285
  raise ValueError("No text input provided")
286
-
287
  audio_file = asyncio.run(text_to_speech(final_text, selected_voice, rate, pitch))
288
  if not audio_file:
289
  raise ValueError("Failed to generate audio")
290
-
291
  video_clip = concatenate_google_images(keywords, clip_duration=5, num_images_per_keyword=1)
292
  if not video_clip:
293
  raise ValueError("Failed to generate video")
294
-
295
  music_clip = None
296
  if mp3_file is not None:
297
  music_clip = adjust_background_music(video_clip.duration, mp3_file.name)
298
-
299
  final_video_path = combine_audio_video(audio_file, video_clip, music_clip)
300
  if not final_video_path:
301
  raise ValueError("Failed to combine audio and video")
302
-
303
  download_link = upload_to_google_drive(final_video_path, folder_id=FOLDER_ID)
304
  if download_link:
305
- print(f"Video uploaded to Google Drive. Download link: {download_link}")
306
  return f"[Download video]({download_link})"
307
  else:
308
  raise ValueError("Error uploading video to Google Drive")
@@ -312,6 +319,7 @@ def process_input(text, txt_file, mp3_file, selected_voice, rate, pitch, keyword
312
  finally:
313
  cleanup_temp_files()
314
 
 
315
  with gr.Blocks() as demo:
316
  gr.Markdown("# Text-to-Video Generator")
317
  with gr.Row():
@@ -321,7 +329,7 @@ with gr.Blocks() as demo:
321
  mp3_file_input = gr.File(label="Upload background music (.mp3)", file_types=[".mp3"])
322
  keyword_input = gr.Textbox(
323
  label="Enter keywords separated by commas",
324
- 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"
325
  )
326
  voices = asyncio.run(get_voices())
327
  voice_dropdown = gr.Dropdown(choices=list(voices.keys()), label="Select Voice")
 
21
 
22
  MIN_WIDTH = 1920
23
  MIN_HEIGHT = 1080
24
+ TARGET_ASPECT_RATIO = 16 / 9
25
 
26
  output_folder = "outputs"
27
  temp_dir = "temp_files"
 
30
 
31
  FOLDER_ID = "12S6adpanAXjf71pKKGRRPqpzbJa5XEh3"
32
 
33
+ # Función para cargar proxies desde un archivo
34
  def load_proxies(proxy_file="proxys.txt"):
35
  try:
36
  with open(proxy_file, 'r') as f:
37
  proxies = [line.strip() for line in f if line.strip()]
38
  print(f"Loaded {len(proxies)} proxies from file")
39
+ return [{"http": f"http://{proxy}", "https": f"http://{proxy}"} for proxy in proxies]
40
  except Exception as e:
41
  print(f"Error loading proxies: {e}")
42
  return []
43
 
44
+ # Función para buscar imágenes en Google Custom Search API
45
  def search_google_images(query, num_images=1):
46
  try:
47
  api_key = os.getenv('GOOGLE_API_KEY')
48
  cse_id = os.getenv('GOOGLE_CSE_ID')
49
  proxies = load_proxies()
50
+
51
  print(f"Buscando imágenes para: {query}")
52
+
53
+ # Intenta con proxies si están disponibles
54
+ if proxies:
55
+ for proxy in proxies:
56
+ try:
57
+ print(f"Trying with proxy: {proxy['http']}")
58
+ result = requests.get(
59
+ "https://www.googleapis.com/customsearch/v1",
60
+ params={
61
+ "q": query,
62
+ "cx": cse_id,
63
+ "searchType": "image",
64
+ "num": num_images * 3,
65
+ "safe": "off",
66
+ "imgSize": "LARGE",
67
+ "rights": "cc_publicdomain|cc_attribute|cc_sharealike",
68
+ "key": api_key
69
+ },
70
+ proxies=proxy,
71
+ timeout=10
72
+ ).json()
73
+ break # Sale del bucle si la solicitud es exitosa
74
+ except Exception as e:
75
+ print(f"Error using proxy {proxy['http']}: {e}")
76
+ continue
 
 
 
 
 
 
 
 
 
77
  else:
78
+ print("No proxies available, trying without proxy")
79
+ result = requests.get(
80
+ "https://www.googleapis.com/customsearch/v1",
81
+ params={
82
+ "q": query,
83
+ "cx": cse_id,
84
+ "searchType": "image",
85
+ "num": num_images * 3,
86
+ "safe": "off",
87
+ "imgSize": "LARGE",
88
+ "rights": "cc_publicdomain|cc_attribute|cc_sharealike",
89
+ "key": api_key
90
+ },
91
+ timeout=10
92
+ ).json()
93
+
94
  if 'items' in result:
95
  image_urls = []
96
  for item in result.get('items', []):
 
101
  image_urls.append(item['link'])
102
  if len(image_urls) >= num_images:
103
  break
104
+
105
  print(f"Encontradas {len(image_urls)} imágenes de tamaño adecuado")
106
  return image_urls
107
+
108
  print("No se encontraron imágenes después de probar todos los proxies")
109
  return []
110
+
111
  except Exception as e:
112
  print(f"Error general en la búsqueda de imágenes: {str(e)}")
113
  return []
114
 
115
+ # Procesa una imagen para ajustar su tamaño
116
  def process_image(image):
117
  try:
118
  width, height = image.size
119
  current_ratio = width / height
120
+
121
  if current_ratio > TARGET_ASPECT_RATIO:
122
  new_width = max(MIN_WIDTH, width)
123
  new_height = int(new_width / TARGET_ASPECT_RATIO)
124
  else:
125
  new_height = max(MIN_HEIGHT, height)
126
  new_width = int(new_height * TARGET_ASPECT_RATIO)
127
+
128
  image = image.resize((new_width, new_height), Image.Resampling.LANCZOS)
129
  background = Image.new('RGB', (max(new_width, MIN_WIDTH), max(new_height, MIN_HEIGHT)), 'black')
130
+
131
+ offset = ((background.width - image.width) // 2, (background.height - image.height) // 2)
 
132
  background.paste(image, offset)
133
+
134
  return background
135
  except Exception as e:
136
  print(f"Error processing image: {e}")
137
  return None
138
 
139
+ # Descarga una imagen desde una URL
140
  def download_image(url):
141
  proxies = load_proxies()
142
  if not proxies:
143
  proxies = [None]
144
+
145
  for proxy in proxies:
146
  try:
147
  response = requests.get(url, proxies=proxy, timeout=10)
148
  image = Image.open(BytesIO(response.content))
149
+
150
  if image.mode in ('RGBA', 'LA') or (image.mode == 'P' and 'transparency' in image.info):
151
  background = Image.new('RGB', image.size, (0, 0, 0))
152
  background.paste(image, mask=image.split()[-1])
153
  image = background
154
+
155
  processed_image = process_image(image)
156
  if processed_image:
157
  return processed_image
 
158
  except Exception as e:
159
  print(f"Error downloading image with proxy {proxy}: {e}")
160
  continue
161
  return None
162
 
163
+ # Crea un clip animado a partir de una imagen
164
  def create_animated_clip(image, duration=5, zoom_factor=1.1):
165
  img_array = np.array(image)
166
  img_clip = ImageClip(img_array).set_duration(duration)
167
+
168
  if img_clip.size[0] < MIN_WIDTH or img_clip.size[1] < MIN_HEIGHT:
169
  img_clip = img_clip.resize(width=MIN_WIDTH, height=MIN_HEIGHT)
170
+
171
  return img_clip.resize(lambda t: 1 + (zoom_factor - 1) * t / duration)
172
 
173
+ # Concatena clips de video basados en palabras clave
174
  def concatenate_google_images(keywords, clip_duration=5, num_images_per_keyword=1):
175
  keyword_list = [keyword.strip() for keyword in keywords.split(",") if keyword.strip()]
176
  if not keyword_list:
177
  keyword_list = ["nature"]
178
+
179
  video_clips = []
180
  for keyword in keyword_list:
181
  try:
 
190
  except Exception as e:
191
  print(f"Error processing keyword '{keyword}': {e}")
192
  continue
193
+
194
  if not video_clips:
195
  return ColorClip(size=(MIN_WIDTH, MIN_HEIGHT), color=[0, 0, 0], duration=5)
196
+
197
  random.shuffle(video_clips)
198
  return concatenate_videoclips(video_clips, method="compose")
199
 
200
+ # Ajusta la música de fondo para que coincida con la duración del video
201
  def adjust_background_music(video_duration, music_file):
202
  try:
203
  music = AudioFileClip(music_file)
 
211
  print(f"Error adjusting music: {e}")
212
  return None
213
 
214
+ # Combina audio y video en un solo archivo
215
  def combine_audio_video(audio_file, video_clip, music_clip=None):
216
  try:
217
  audio_clip = AudioFileClip(audio_file)
218
  total_duration = audio_clip.duration + 2
219
+
220
  video_clip = video_clip.loop(duration=total_duration)
221
  video_clip = video_clip.set_duration(total_duration).fadeout(2)
222
+
223
  final_clip = video_clip.set_audio(audio_clip)
224
  if music_clip:
225
  music_clip = music_clip.set_duration(total_duration).audio_fadeout(2)
226
  final_clip = final_clip.set_audio(CompositeAudioClip([audio_clip, music_clip]))
227
+
228
  output_filename = f"final_video_{int(time.time())}.mp4"
229
  output_path = os.path.join(output_folder, output_filename)
230
+
231
  final_clip.write_videofile(output_path, codec="libx264", audio_codec="aac", fps=24)
232
+
233
  final_clip.close()
234
  video_clip.close()
235
  audio_clip.close()
236
  if music_clip:
237
  music_clip.close()
238
+
239
  return output_path
240
  except Exception as e:
241
  print(f"Error combining audio and video: {e}")
 
243
  final_clip.close()
244
  return None
245
 
246
+ # Sube un archivo al Google Drive
247
  def upload_to_google_drive(file_path, folder_id):
248
  try:
249
  creds = service_account.Credentials.from_service_account_info(
 
272
  print(f"Error uploading to Google Drive: {e}")
273
  return None
274
 
275
+ # Limpia archivos temporales
276
+ def cleanup_temp_files():
277
+ try:
278
+ if os.path.exists(temp_dir) and os.path.isdir(temp_dir):
279
+ shutil.rmtree(temp_dir)
280
+ os.makedirs(temp_dir, exist_ok=True)
281
+ print("Temporal files cleaned up successfully.")
282
+ except Exception as e:
283
+ print(f"Error cleaning up temporary files: {e}")
284
+
285
+ # Procesa la entrada del usuario y genera el video
286
  def process_input(text, txt_file, mp3_file, selected_voice, rate, pitch, keywords):
287
  try:
288
  if text.strip():
 
291
  final_text = txt_file.decode("utf-8")
292
  else:
293
  raise ValueError("No text input provided")
294
+
295
  audio_file = asyncio.run(text_to_speech(final_text, selected_voice, rate, pitch))
296
  if not audio_file:
297
  raise ValueError("Failed to generate audio")
298
+
299
  video_clip = concatenate_google_images(keywords, clip_duration=5, num_images_per_keyword=1)
300
  if not video_clip:
301
  raise ValueError("Failed to generate video")
302
+
303
  music_clip = None
304
  if mp3_file is not None:
305
  music_clip = adjust_background_music(video_clip.duration, mp3_file.name)
306
+
307
  final_video_path = combine_audio_video(audio_file, video_clip, music_clip)
308
  if not final_video_path:
309
  raise ValueError("Failed to combine audio and video")
310
+
311
  download_link = upload_to_google_drive(final_video_path, folder_id=FOLDER_ID)
312
  if download_link:
 
313
  return f"[Download video]({download_link})"
314
  else:
315
  raise ValueError("Error uploading video to Google Drive")
 
319
  finally:
320
  cleanup_temp_files()
321
 
322
+ # Interfaz Gradio
323
  with gr.Blocks() as demo:
324
  gr.Markdown("# Text-to-Video Generator")
325
  with gr.Row():
 
329
  mp3_file_input = gr.File(label="Upload background music (.mp3)", file_types=[".mp3"])
330
  keyword_input = gr.Textbox(
331
  label="Enter keywords separated by commas",
332
+ value="nature, landscape, city, people"
333
  )
334
  voices = asyncio.run(get_voices())
335
  voice_dropdown = gr.Dropdown(choices=list(voices.keys()), label="Select Voice")