Spaces:
Building
Building
Update app.py
Browse files
app.py
CHANGED
@@ -14,17 +14,19 @@ from googleapiclient.http import MediaFileUpload
|
|
14 |
import tempfile
|
15 |
import re
|
16 |
import random
|
|
|
17 |
|
|
|
18 |
output_folder = "outputs"
|
19 |
os.makedirs(output_folder, exist_ok=True)
|
20 |
|
21 |
def clean_text_for_search(text):
|
|
|
22 |
text = re.sub(r'[^\w\s]', '', text).strip()
|
23 |
return text
|
24 |
|
25 |
-
from PIL import Image
|
26 |
-
|
27 |
def resize_and_blur_video(clip, target_aspect_ratio=16/9):
|
|
|
28 |
try:
|
29 |
w, h = clip.size
|
30 |
current_aspect_ratio = w / h
|
@@ -36,27 +38,27 @@ def resize_and_blur_video(clip, target_aspect_ratio=16/9):
|
|
36 |
target_w = int(h * target_aspect_ratio)
|
37 |
target_h = h
|
38 |
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
background = background.fx(vfx.blur, sigma=50) # Aplicar desenfoque
|
45 |
|
46 |
-
|
47 |
-
x_center = (target_w - foreground.w)
|
48 |
return CompositeVideoClip(
|
49 |
[background, foreground.set_position((x_center, 0))],
|
50 |
size=(target_w, target_h)
|
51 |
)
|
52 |
else: # Video horizontal
|
53 |
-
return clip.resize(width=int(h * target_aspect_ratio), height=h
|
54 |
|
55 |
except Exception as e:
|
56 |
print(f"Error en resize_and_blur_video: {e}")
|
57 |
return clip
|
58 |
|
59 |
def concatenate_pixabay_videos(keywords, num_videos_per_keyword=1):
|
|
|
60 |
keyword_list = [keyword.strip() for keyword in keywords.split(",") if keyword.strip()]
|
61 |
if not keyword_list:
|
62 |
raise Exception("No se proporcionaron palabras clave v谩lidas.")
|
@@ -65,12 +67,15 @@ def concatenate_pixabay_videos(keywords, num_videos_per_keyword=1):
|
|
65 |
|
66 |
for keyword in keyword_list:
|
67 |
try:
|
|
|
68 |
links = search_pixabay(keyword, num_results=num_videos_per_keyword)
|
69 |
if not links:
|
70 |
-
print(f"No se encontraron videos para la palabra clave '{keyword}'.")
|
71 |
-
|
|
|
|
|
72 |
|
73 |
-
link = links[0]
|
74 |
video_response = requests.get(link)
|
75 |
if video_response.status_code != 200:
|
76 |
print(f"Error al descargar video desde {link}: C贸digo de estado {video_response.status_code}")
|
@@ -93,6 +98,7 @@ def concatenate_pixabay_videos(keywords, num_videos_per_keyword=1):
|
|
93 |
return concatenate_videoclips(video_clips, method="compose")
|
94 |
|
95 |
def adjust_background_music(video_duration, music_file):
|
|
|
96 |
try:
|
97 |
music = AudioFileClip(music_file)
|
98 |
if music.duration < video_duration:
|
@@ -108,6 +114,7 @@ def adjust_background_music(video_duration, music_file):
|
|
108 |
return None
|
109 |
|
110 |
def combine_audio_video(audio_file, video_clip, music_clip=None):
|
|
|
111 |
try:
|
112 |
audio_clip = AudioFileClip(audio_file)
|
113 |
total_duration = audio_clip.duration + 5
|
@@ -136,27 +143,28 @@ def combine_audio_video(audio_file, video_clip, music_clip=None):
|
|
136 |
return None
|
137 |
|
138 |
def process_input(text, txt_file, mp3_file, selected_voice, rate, pitch, keywords):
|
|
|
139 |
try:
|
140 |
if text.strip():
|
141 |
final_text = text
|
142 |
elif txt_file is not None:
|
143 |
final_text = txt_file.decode("utf-8")
|
144 |
else:
|
145 |
-
return
|
146 |
|
147 |
voices = asyncio.run(get_voices())
|
148 |
if selected_voice not in voices:
|
149 |
-
return
|
150 |
|
151 |
try:
|
152 |
audio_file = asyncio.run(text_to_speech(final_text, selected_voice, rate, pitch))
|
153 |
except Exception as e:
|
154 |
-
return
|
155 |
|
156 |
try:
|
157 |
video_clip = concatenate_pixabay_videos(keywords, num_videos_per_keyword=1)
|
158 |
except Exception as e:
|
159 |
-
return
|
160 |
|
161 |
if mp3_file is not None:
|
162 |
music_clip = adjust_background_music(video_clip.duration, mp3_file.name)
|
@@ -164,29 +172,13 @@ def process_input(text, txt_file, mp3_file, selected_voice, rate, pitch, keyword
|
|
164 |
music_clip = None
|
165 |
|
166 |
final_video_path = combine_audio_video(audio_file, video_clip, music_clip)
|
167 |
-
upload_to_google_drive(final_video_path)
|
168 |
return final_video_path
|
169 |
|
170 |
except Exception as e:
|
171 |
-
return
|
172 |
-
|
173 |
-
def upload_to_google_drive(file_path):
|
174 |
-
try:
|
175 |
-
api_key = os.getenv("GOOGLE_API_KEY")
|
176 |
-
if not api_key:
|
177 |
-
print("Error: GOOGLE_API_KEY no est谩 definida en las variables de entorno.")
|
178 |
-
return None
|
179 |
-
|
180 |
-
service = build("drive", "v3", developerKey=api_key)
|
181 |
-
file_metadata = {"name": os.path.basename(file_path)}
|
182 |
-
media = MediaFileUpload(file_path, resumable=True)
|
183 |
-
file = service.files().create(body=file_metadata, media_body=media, fields="id").execute()
|
184 |
-
print(f"Archivo subido exitosamente con ID: {file.get('id')}")
|
185 |
-
return file.get("id")
|
186 |
-
except Exception as e:
|
187 |
-
print(f"Error subiendo a Google Drive: {e}")
|
188 |
-
return None
|
189 |
|
|
|
190 |
with gr.Blocks() as demo:
|
191 |
gr.Markdown("# Text-to-Video Generator")
|
192 |
with gr.Row():
|
@@ -209,5 +201,8 @@ with gr.Blocks() as demo:
|
|
209 |
outputs=output_video
|
210 |
)
|
211 |
|
|
|
212 |
port = int(os.getenv("PORT", 7860))
|
|
|
|
|
213 |
demo.launch(server_name="0.0.0.0", server_port=port, share=True)
|
|
|
14 |
import tempfile
|
15 |
import re
|
16 |
import random
|
17 |
+
from google_drive_upload import upload_to_google_drive # Importa la nueva funci贸n
|
18 |
|
19 |
+
# Define la carpeta de salida temporal
|
20 |
output_folder = "outputs"
|
21 |
os.makedirs(output_folder, exist_ok=True)
|
22 |
|
23 |
def clean_text_for_search(text):
|
24 |
+
"""Limpia el texto para hacer b煤squedas v谩lidas en Pixabay"""
|
25 |
text = re.sub(r'[^\w\s]', '', text).strip()
|
26 |
return text
|
27 |
|
|
|
|
|
28 |
def resize_and_blur_video(clip, target_aspect_ratio=16/9):
|
29 |
+
"""Redimensiona y aplica desenfoque al fondo del video para mantener el aspecto 16:9."""
|
30 |
try:
|
31 |
w, h = clip.size
|
32 |
current_aspect_ratio = w / h
|
|
|
38 |
target_w = int(h * target_aspect_ratio)
|
39 |
target_h = h
|
40 |
|
41 |
+
background = clip.resize(width=target_w)
|
42 |
+
try:
|
43 |
+
background = background.fx(vfx.blur, sigma=50)
|
44 |
+
except Exception as e:
|
45 |
+
print(f"Error al aplicar blur: {e}")
|
|
|
46 |
|
47 |
+
foreground = clip.resize(height=target_h)
|
48 |
+
x_center = (target_w - foreground.w) / 2
|
49 |
return CompositeVideoClip(
|
50 |
[background, foreground.set_position((x_center, 0))],
|
51 |
size=(target_w, target_h)
|
52 |
)
|
53 |
else: # Video horizontal
|
54 |
+
return clip.resize(width=int(h * target_aspect_ratio), height=h)
|
55 |
|
56 |
except Exception as e:
|
57 |
print(f"Error en resize_and_blur_video: {e}")
|
58 |
return clip
|
59 |
|
60 |
def concatenate_pixabay_videos(keywords, num_videos_per_keyword=1):
|
61 |
+
"""Concatena videos de Pixabay basados en palabras clave."""
|
62 |
keyword_list = [keyword.strip() for keyword in keywords.split(",") if keyword.strip()]
|
63 |
if not keyword_list:
|
64 |
raise Exception("No se proporcionaron palabras clave v谩lidas.")
|
|
|
67 |
|
68 |
for keyword in keyword_list:
|
69 |
try:
|
70 |
+
print(f"Buscando videos para la palabra clave '{keyword}'...")
|
71 |
links = search_pixabay(keyword, num_results=num_videos_per_keyword)
|
72 |
if not links:
|
73 |
+
print(f"No se encontraron videos para la palabra clave '{keyword}'. Usando palabra clave predeterminada 'nature'.")
|
74 |
+
links = search_pixabay("nature", num_results=num_videos_per_keyword) # Palabra clave predeterminada
|
75 |
+
if not links:
|
76 |
+
continue
|
77 |
|
78 |
+
link = links[0] # Usamos solo el primer video encontrado
|
79 |
video_response = requests.get(link)
|
80 |
if video_response.status_code != 200:
|
81 |
print(f"Error al descargar video desde {link}: C贸digo de estado {video_response.status_code}")
|
|
|
98 |
return concatenate_videoclips(video_clips, method="compose")
|
99 |
|
100 |
def adjust_background_music(video_duration, music_file):
|
101 |
+
"""Ajusta la m煤sica de fondo para que coincida con la duraci贸n del video."""
|
102 |
try:
|
103 |
music = AudioFileClip(music_file)
|
104 |
if music.duration < video_duration:
|
|
|
114 |
return None
|
115 |
|
116 |
def combine_audio_video(audio_file, video_clip, music_clip=None):
|
117 |
+
"""Combina el audio y el video en un archivo final."""
|
118 |
try:
|
119 |
audio_clip = AudioFileClip(audio_file)
|
120 |
total_duration = audio_clip.duration + 5
|
|
|
143 |
return None
|
144 |
|
145 |
def process_input(text, txt_file, mp3_file, selected_voice, rate, pitch, keywords):
|
146 |
+
"""Procesa la entrada del usuario y genera el video final."""
|
147 |
try:
|
148 |
if text.strip():
|
149 |
final_text = text
|
150 |
elif txt_file is not None:
|
151 |
final_text = txt_file.decode("utf-8")
|
152 |
else:
|
153 |
+
return "No input provided"
|
154 |
|
155 |
voices = asyncio.run(get_voices())
|
156 |
if selected_voice not in voices:
|
157 |
+
return f"La voz '{selected_voice}' no es v谩lida. Por favor, seleccione una de las siguientes voces: {', '.join(voices.keys())}"
|
158 |
|
159 |
try:
|
160 |
audio_file = asyncio.run(text_to_speech(final_text, selected_voice, rate, pitch))
|
161 |
except Exception as e:
|
162 |
+
return f"Error generando audio: {e}"
|
163 |
|
164 |
try:
|
165 |
video_clip = concatenate_pixabay_videos(keywords, num_videos_per_keyword=1)
|
166 |
except Exception as e:
|
167 |
+
return f"Error concatenando videos: {e}"
|
168 |
|
169 |
if mp3_file is not None:
|
170 |
music_clip = adjust_background_music(video_clip.duration, mp3_file.name)
|
|
|
172 |
music_clip = None
|
173 |
|
174 |
final_video_path = combine_audio_video(audio_file, video_clip, music_clip)
|
175 |
+
upload_to_google_drive(final_video_path) # Sube a Google Drive usando OAuth2
|
176 |
return final_video_path
|
177 |
|
178 |
except Exception as e:
|
179 |
+
return f"Error durante el procesamiento: {e}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
180 |
|
181 |
+
# Interfaz Gradio
|
182 |
with gr.Blocks() as demo:
|
183 |
gr.Markdown("# Text-to-Video Generator")
|
184 |
with gr.Row():
|
|
|
201 |
outputs=output_video
|
202 |
)
|
203 |
|
204 |
+
# Leer el puerto asignado por Hugging Face
|
205 |
port = int(os.getenv("PORT", 7860))
|
206 |
+
|
207 |
+
# Lanzar la aplicaci贸n
|
208 |
demo.launch(server_name="0.0.0.0", server_port=port, share=True)
|