gnosticdev commited on
Commit
1caaaa3
verified
1 Parent(s): a38818d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +33 -75
app.py CHANGED
@@ -4,7 +4,7 @@ from pixabay_api import search_pixabay
4
  from moviepy.editor import (
5
  AudioFileClip, VideoFileClip, CompositeAudioClip,
6
  concatenate_audioclips, concatenate_videoclips, vfx, CompositeVideoClip,
7
- ColorClip, ImageClip
8
  )
9
  import asyncio
10
  import os
@@ -16,8 +16,6 @@ import re
16
  import random
17
  from google_drive_upload import authenticate_google_drive, upload_to_google_drive
18
  from io import BytesIO
19
- from PIL import Image
20
- import numpy as np
21
 
22
  # Crear el archivo de credenciales de servicio desde los secretos
23
  service_account_info = json.loads(os.getenv('GOOGLE_SERVICE_ACCOUNT', '{}'))
@@ -30,62 +28,44 @@ output_folder = "outputs"
30
  os.makedirs(output_folder, exist_ok=True)
31
 
32
  # ID de la carpeta de destino en Google Drive
33
- FOLDER_ID = "12S6adpanAXjf71pKKGRRPqpzbJa5XEh3" # Reemplaza con tu ID real
34
 
35
-
36
- def resize_and_add_background(clip, target_width=1920, target_height=1080, background_url="https://wallpaperaccess.com/full/231401.jpg"):
37
- """
38
- Redimensiona el video al tama帽o 1080p (16:9) y a帽ade una imagen de fondo descargada desde una URL.
39
- """
40
  try:
41
  w, h = clip.size
42
  current_aspect_ratio = w / h
43
  target_aspect_ratio = target_width / target_height
44
 
45
- # Descargar la imagen de fondo desde la URL
46
- response = requests.get(background_url)
47
- if response.status_code != 200:
48
- print("Error al descargar la imagen de fondo, usando un fondo negro.")
49
- background = (
50
- ImageClip(
51
- np.zeros((target_height, target_width, 3), dtype=np.uint8),
52
- duration=clip.duration,
53
- )
54
- .set_duration(clip.duration)
55
- .resize((target_width, target_height))
56
- )
57
- else:
58
- image_data = Image.open(BytesIO(response.content))
59
- image_array = np.array(image_data)
60
- background = (
61
- ImageClip(image_array)
62
- .set_duration(clip.duration)
63
- .resize((target_width, target_height))
64
- )
65
-
66
- # Si el video ya tiene una relaci贸n de aspecto cercana a 16:9, solo redimensionarlo
67
  if abs(current_aspect_ratio - target_aspect_ratio) < 0.1:
68
- resized_clip = clip.resize((target_width, target_height))
69
- else:
70
- # Redimensionar el video manteniendo su proporci贸n y centrarlo sobre el fondo
71
- if current_aspect_ratio < target_aspect_ratio: # Video vertical
72
- new_height = target_height
73
- new_width = int(new_height * current_aspect_ratio)
74
- x_center = (target_width - new_width) / 2
75
- resized_clip = clip.resize(width=new_width).set_position((x_center, 0))
76
- else: # Video horizontal
77
- new_width = target_width
78
- new_height = int(new_width / current_aspect_ratio)
79
- y_center = (target_height - new_height) / 2
80
- resized_clip = clip.resize(height=new_height).set_position((0, y_center))
81
 
82
- # Combinar el fondo con el video redimensionado
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  return CompositeVideoClip([background, resized_clip], size=(target_width, target_height))
84
  except Exception as e:
85
- print(f"Error en resize_and_add_background: {e}")
86
  return clip
87
 
88
-
89
  def concatenate_pixabay_videos(keywords, num_videos_per_keyword=1):
90
  """Concatena videos de Pixabay basados en palabras clave."""
91
  keyword_list = [keyword.strip() for keyword in keywords.split(",") if keyword.strip()]
@@ -109,7 +89,7 @@ def concatenate_pixabay_videos(keywords, num_videos_per_keyword=1):
109
  with tempfile.NamedTemporaryFile(delete=False, suffix=".mp4") as tmp_video:
110
  tmp_video.write(video_response.content)
111
  clip = VideoFileClip(tmp_video.name)
112
- processed_clip = resize_and_add_background(clip)
113
  video_clips.append(processed_clip)
114
  os.unlink(tmp_video.name) # Limpiamos el archivo temporal
115
  except Exception as e:
@@ -121,7 +101,6 @@ def concatenate_pixabay_videos(keywords, num_videos_per_keyword=1):
121
  random.shuffle(video_clips)
122
  return concatenate_videoclips(video_clips, method="compose")
123
 
124
-
125
  def adjust_background_music(video_duration, music_file):
126
  """Ajusta la m煤sica de fondo para que coincida con la duraci贸n del video."""
127
  try:
@@ -136,7 +115,6 @@ def adjust_background_music(video_duration, music_file):
136
  print(f"Error ajustando m煤sica: {e}")
137
  return None
138
 
139
-
140
  def combine_audio_video(audio_file, video_clip, music_clip=None):
141
  """Combina el audio y el video en un archivo final."""
142
  try:
@@ -174,7 +152,6 @@ def combine_audio_video(audio_file, video_clip, music_clip=None):
174
  final_clip.close()
175
  return None
176
 
177
-
178
  def process_input(text, txt_file, mp3_file, selected_voice, rate, pitch, keywords):
179
  """Procesa la entrada del usuario y genera el video final."""
180
  try:
@@ -185,41 +162,33 @@ def process_input(text, txt_file, mp3_file, selected_voice, rate, pitch, keyword
185
  final_text = txt_file.decode("utf-8")
186
  else:
187
  raise ValueError("No text input provided")
188
-
189
  # Generamos el audio
190
  audio_file = asyncio.run(text_to_speech(final_text, selected_voice, rate, pitch))
191
  if not audio_file:
192
  raise ValueError("Failed to generate audio")
193
-
194
  # Generamos el video
195
  video_clip = concatenate_pixabay_videos(keywords, num_videos_per_keyword=1)
196
  if not video_clip:
197
  raise ValueError("Failed to generate video")
198
-
199
  # Procesamos la m煤sica de fondo si existe
200
  music_clip = None
201
  if mp3_file is not None:
202
  music_clip = adjust_background_music(video_clip.duration, mp3_file.name)
203
-
204
  # Combinamos todo
205
  final_video_path = combine_audio_video(audio_file, video_clip, music_clip)
206
  if not final_video_path:
207
  raise ValueError("Failed to combine audio and video")
208
-
209
  # Subimos a Google Drive
210
  video_id = upload_to_google_drive(final_video_path, folder_id=FOLDER_ID)
211
  if video_id:
212
  print(f"Video subido a Google Drive con ID: {video_id}")
213
- download_link = f"https://drive.google.com/file/d/{video_id}/view?usp=sharing"
214
- return download_link # Devuelve el enlace compartido
215
  else:
216
  print("Error subiendo el video a Google Drive")
217
- return "Error al subir el video"
218
-
219
  except Exception as e:
220
  print(f"Error durante el procesamiento: {e}")
221
- return f"Error durante el procesamiento: {e}"
222
-
223
 
224
  # Interfaz Gradio
225
  with gr.Blocks() as demo:
@@ -231,15 +200,14 @@ with gr.Blocks() as demo:
231
  mp3_file_input = gr.File(label="Upload background music (.mp3)", file_types=[".mp3"])
232
  keyword_input = gr.Textbox(
233
  label="Enter keywords separated by commas (e.g., universe, galaxy, forest, cat)",
234
- value="space, espacio,galaxy,moon,fear,astral,god,evil,mistery,cosmos,stars"
235
  )
236
  voices = asyncio.run(get_voices())
237
  voice_dropdown = gr.Dropdown(choices=list(voices.keys()), label="Select Voice")
238
  rate_slider = gr.Slider(minimum=-50, maximum=50, value=0, label="Speech Rate Adjustment (%)", step=1)
239
  pitch_slider = gr.Slider(minimum=-20, maximum=20, value=0, label="Pitch Adjustment (Hz)", step=1)
240
-
241
  with gr.Column():
242
- output_video = gr.HTML(value="<p></p>") # Usamos HTML para mostrar el bot贸n
243
 
244
  btn = gr.Button("Generate Video")
245
  btn.click(
@@ -248,16 +216,6 @@ with gr.Blocks() as demo:
248
  outputs=output_video
249
  )
250
 
251
- # Funci贸n para actualizar el HTML con el bot贸n de descarga
252
- def update_html(download_link):
253
- if "Error" in download_link:
254
- return gr.HTML.update(value=f"<p>{download_link}</p>")
255
- return gr.HTML.update(value=f'<a href="{download_link}" target="_blank"><button>Descargar</button></a>')
256
-
257
- btn.click(process_input, inputs=[text_input, txt_file_input, mp3_file_input, voice_dropdown, rate_slider, pitch_slider, keyword_input], outputs=output_video).then(
258
- update_html, inputs=output_video, outputs=output_video
259
- )
260
-
261
  # Leer el puerto asignado por Hugging Face
262
  port = int(os.getenv("PORT", 7860))
263
 
 
4
  from moviepy.editor import (
5
  AudioFileClip, VideoFileClip, CompositeAudioClip,
6
  concatenate_audioclips, concatenate_videoclips, vfx, CompositeVideoClip,
7
+ ColorClip
8
  )
9
  import asyncio
10
  import os
 
16
  import random
17
  from google_drive_upload import authenticate_google_drive, upload_to_google_drive
18
  from io import BytesIO
 
 
19
 
20
  # Crear el archivo de credenciales de servicio desde los secretos
21
  service_account_info = json.loads(os.getenv('GOOGLE_SERVICE_ACCOUNT', '{}'))
 
28
  os.makedirs(output_folder, exist_ok=True)
29
 
30
  # ID de la carpeta de destino en Google Drive
31
+ FOLDER_ID = "12S6adpanAXjf71pKKGRRPqpzbJa5XEh3" # Reemplaza con tu ID de carpeta
32
 
33
+ def resize_and_blur_video(clip, target_width=1920, target_height=1080):
34
+ """Redimensiona el video al tama帽o 1080p (16:9) y aplica desenfoque si es necesario."""
 
 
 
35
  try:
36
  w, h = clip.size
37
  current_aspect_ratio = w / h
38
  target_aspect_ratio = target_width / target_height
39
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  if abs(current_aspect_ratio - target_aspect_ratio) < 0.1:
41
+ # Si la relaci贸n de aspecto ya es cercana a 16:9, solo redimensionamos
42
+ return clip.resize((target_width, target_height))
 
 
 
 
 
 
 
 
 
 
 
43
 
44
+ # Crear un fondo borroso con las dimensiones objetivo
45
+ background = ColorClip(size=(target_width, target_height), color=[0, 0, 0]).set_duration(clip.duration)
46
+ try:
47
+ background = background.fx(vfx.blur, sigma=50)
48
+ except Exception as e:
49
+ print(f"Error al aplicar blur: {e}")
50
+
51
+ # Redimensionar el video original para mantener su proporci贸n
52
+ if current_aspect_ratio < target_aspect_ratio: # Video vertical
53
+ new_height = target_height
54
+ new_width = int(new_height * current_aspect_ratio)
55
+ x_center = (target_width - new_width) / 2
56
+ resized_clip = clip.resize(width=new_width).set_position((x_center, 0))
57
+ else: # Video horizontal
58
+ new_width = target_width
59
+ new_height = int(new_width / current_aspect_ratio)
60
+ y_center = (target_height - new_height) / 2
61
+ resized_clip = clip.resize(height=new_height).set_position((0, y_center))
62
+
63
+ # Combinar el fondo borroso con el video redimensionado
64
  return CompositeVideoClip([background, resized_clip], size=(target_width, target_height))
65
  except Exception as e:
66
+ print(f"Error en resize_and_blur_video: {e}")
67
  return clip
68
 
 
69
  def concatenate_pixabay_videos(keywords, num_videos_per_keyword=1):
70
  """Concatena videos de Pixabay basados en palabras clave."""
71
  keyword_list = [keyword.strip() for keyword in keywords.split(",") if keyword.strip()]
 
89
  with tempfile.NamedTemporaryFile(delete=False, suffix=".mp4") as tmp_video:
90
  tmp_video.write(video_response.content)
91
  clip = VideoFileClip(tmp_video.name)
92
+ processed_clip = resize_and_blur_video(clip)
93
  video_clips.append(processed_clip)
94
  os.unlink(tmp_video.name) # Limpiamos el archivo temporal
95
  except Exception as e:
 
101
  random.shuffle(video_clips)
102
  return concatenate_videoclips(video_clips, method="compose")
103
 
 
104
  def adjust_background_music(video_duration, music_file):
105
  """Ajusta la m煤sica de fondo para que coincida con la duraci贸n del video."""
106
  try:
 
115
  print(f"Error ajustando m煤sica: {e}")
116
  return None
117
 
 
118
  def combine_audio_video(audio_file, video_clip, music_clip=None):
119
  """Combina el audio y el video en un archivo final."""
120
  try:
 
152
  final_clip.close()
153
  return None
154
 
 
155
  def process_input(text, txt_file, mp3_file, selected_voice, rate, pitch, keywords):
156
  """Procesa la entrada del usuario y genera el video final."""
157
  try:
 
162
  final_text = txt_file.decode("utf-8")
163
  else:
164
  raise ValueError("No text input provided")
 
165
  # Generamos el audio
166
  audio_file = asyncio.run(text_to_speech(final_text, selected_voice, rate, pitch))
167
  if not audio_file:
168
  raise ValueError("Failed to generate audio")
 
169
  # Generamos el video
170
  video_clip = concatenate_pixabay_videos(keywords, num_videos_per_keyword=1)
171
  if not video_clip:
172
  raise ValueError("Failed to generate video")
 
173
  # Procesamos la m煤sica de fondo si existe
174
  music_clip = None
175
  if mp3_file is not None:
176
  music_clip = adjust_background_music(video_clip.duration, mp3_file.name)
 
177
  # Combinamos todo
178
  final_video_path = combine_audio_video(audio_file, video_clip, music_clip)
179
  if not final_video_path:
180
  raise ValueError("Failed to combine audio and video")
 
181
  # Subimos a Google Drive
182
  video_id = upload_to_google_drive(final_video_path, folder_id=FOLDER_ID)
183
  if video_id:
184
  print(f"Video subido a Google Drive con ID: {video_id}")
 
 
185
  else:
186
  print("Error subiendo el video a Google Drive")
187
+
188
+ return final_video_path
189
  except Exception as e:
190
  print(f"Error durante el procesamiento: {e}")
191
+ return None
 
192
 
193
  # Interfaz Gradio
194
  with gr.Blocks() as demo:
 
200
  mp3_file_input = gr.File(label="Upload background music (.mp3)", file_types=[".mp3"])
201
  keyword_input = gr.Textbox(
202
  label="Enter keywords separated by commas (e.g., universe, galaxy, forest, cat)",
203
+ value="space, espacio,galaxy,moon,fear,astral,god, evil, mistery, cosmos, stars"
204
  )
205
  voices = asyncio.run(get_voices())
206
  voice_dropdown = gr.Dropdown(choices=list(voices.keys()), label="Select Voice")
207
  rate_slider = gr.Slider(minimum=-50, maximum=50, value=0, label="Speech Rate Adjustment (%)", step=1)
208
  pitch_slider = gr.Slider(minimum=-20, maximum=20, value=0, label="Pitch Adjustment (Hz)", step=1)
 
209
  with gr.Column():
210
+ output_video = gr.File(label="Generated Video") # En lugar de gr.Video
211
 
212
  btn = gr.Button("Generate Video")
213
  btn.click(
 
216
  outputs=output_video
217
  )
218
 
 
 
 
 
 
 
 
 
 
 
219
  # Leer el puerto asignado por Hugging Face
220
  port = int(os.getenv("PORT", 7860))
221