gnosticdev commited on
Commit
9ea2009
·
verified ·
1 Parent(s): 941a8dd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +41 -197
app.py CHANGED
@@ -1,149 +1,4 @@
1
- import gradio as gr
2
- from tts_module import get_voices, text_to_speech
3
- from pixabay_api import search_pixabay
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
11
- import json
12
- import time
13
- import requests
14
- import tempfile
15
- import re
16
- import random
17
- from google_drive_upload import authenticate_google_drive, upload_to_google_drive
18
-
19
- # Crear el archivo de credenciales de servicio desde los secretos
20
- service_account_info = json.loads(os.getenv('GOOGLE_SERVICE_ACCOUNT', '{}'))
21
- if service_account_info:
22
- with open('service-account.json', 'w') as f:
23
- json.dump(service_account_info, f)
24
-
25
- # Define la carpeta de salida
26
- output_folder = "outputs"
27
- os.makedirs(output_folder, exist_ok=True)
28
-
29
- # ID de la carpeta de destino en Google Drive
30
- FOLDER_ID = "12S6adpanAXjf71pKKGRRPqpzbJa5XEh3" # Reemplaza con tu ID de carpeta
31
-
32
- def resize_and_blur_video(clip, target_aspect_ratio=16/9):
33
- """Redimensiona y aplica desenfoque al fondo del video para mantener el aspecto 16:9."""
34
- try:
35
- w, h = clip.size
36
- current_aspect_ratio = w / h
37
- if abs(current_aspect_ratio - target_aspect_ratio) < 0.1:
38
- return clip
39
- if current_aspect_ratio < target_aspect_ratio: # Video vertical
40
- target_w = int(h * target_aspect_ratio)
41
- target_h = h
42
- background = clip.resize(width=target_w)
43
- try:
44
- background = background.fx(vfx.blur, sigma=50)
45
- except Exception as e:
46
- print(f"Error al aplicar blur: {e}")
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
- 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
- """Concatena videos de Pixabay basados en palabras clave."""
61
- keyword_list = [keyword.strip() for keyword in keywords.split(",") if keyword.strip()]
62
- if not keyword_list:
63
- keyword_list = ["nature"] # Palabra clave por defecto
64
- video_clips = []
65
- for keyword in keyword_list:
66
- try:
67
- print(f"Buscando videos para la palabra clave '{keyword}'...")
68
- links = search_pixabay(keyword, num_results=num_videos_per_keyword)
69
- if not links:
70
- print(f"No se encontraron videos para '{keyword}', probando con 'nature'")
71
- links = search_pixabay("nature", num_results=num_videos_per_keyword)
72
- if not links:
73
- continue
74
- link = links[0]
75
- video_response = requests.get(link)
76
- if video_response.status_code != 200:
77
- print(f"Error al descargar video desde {link}")
78
- continue
79
- with tempfile.NamedTemporaryFile(delete=False, suffix=".mp4") as tmp_video:
80
- tmp_video.write(video_response.content)
81
- clip = VideoFileClip(tmp_video.name)
82
- processed_clip = resize_and_blur_video(clip)
83
- video_clips.append(processed_clip)
84
- os.unlink(tmp_video.name) # Limpiamos el archivo temporal
85
- except Exception as e:
86
- print(f"Error procesando palabra clave '{keyword}': {e}")
87
- continue
88
- if not video_clips:
89
- # Si no hay videos, creamos un clip negro de 5 segundos
90
- return ColorClip(size=(1920, 1080), color=[0, 0, 0], duration=5)
91
- random.shuffle(video_clips)
92
- return concatenate_videoclips(video_clips, method="compose")
93
-
94
- def adjust_background_music(video_duration, music_file):
95
- """Ajusta la música de fondo para que coincida con la duración del video."""
96
- try:
97
- music = AudioFileClip(music_file)
98
- if music.duration < video_duration:
99
- repetitions = int(video_duration / music.duration) + 1
100
- music_clips = [music] * repetitions
101
- music = concatenate_audioclips(music_clips)
102
- music = music.subclip(0, video_duration)
103
- return music.volumex(0.2)
104
- except Exception as e:
105
- print(f"Error ajustando música: {e}")
106
- return None
107
-
108
- def combine_audio_video(audio_file, video_clip, music_clip=None):
109
- """Combina el audio y el video en un archivo final."""
110
- try:
111
- audio_clip = AudioFileClip(audio_file)
112
- total_duration = audio_clip.duration + 2 # Añadimos 2 segundos extra
113
-
114
- # Aseguramos que el video tenga la duración correcta
115
- video_clip = video_clip.loop(duration=total_duration)
116
- video_clip = video_clip.set_duration(total_duration).fadeout(2)
117
-
118
- # Combinamos el audio principal
119
- final_clip = video_clip.set_audio(audio_clip)
120
- # Añadimos la música de fondo si existe
121
- if music_clip:
122
- music_clip = music_clip.set_duration(total_duration).audio_fadeout(2)
123
- final_clip = final_clip.set_audio(CompositeAudioClip([audio_clip, music_clip]))
124
- # Generamos el nombre del archivo y la ruta
125
- output_filename = f"final_video_{int(time.time())}.mp4"
126
- output_path = os.path.join(output_folder, output_filename)
127
-
128
- # Guardamos el video
129
- final_clip.write_videofile(output_path, codec="libx264", audio_codec="aac", fps=24)
130
-
131
- # Limpiamos los clips
132
- final_clip.close()
133
- video_clip.close()
134
- audio_clip.close()
135
- if music_clip:
136
- music_clip.close()
137
-
138
- return output_path
139
- except Exception as e:
140
- print(f"Error combinando audio y video: {e}")
141
- if 'final_clip' in locals():
142
- final_clip.close()
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
  # Determinamos el texto a usar
149
  if text.strip():
@@ -152,62 +7,51 @@ def process_input(text, txt_file, mp3_file, selected_voice, rate, pitch, keyword
152
  final_text = txt_file.decode("utf-8")
153
  else:
154
  raise ValueError("No text input provided")
155
- # Generamos el audio
156
- audio_file = asyncio.run(text_to_speech(final_text, selected_voice, rate, pitch))
157
- if not audio_file:
158
- raise ValueError("Failed to generate audio")
159
- # Generamos el video
160
- video_clip = concatenate_pixabay_videos(keywords, num_videos_per_keyword=1)
161
- if not video_clip:
162
- raise ValueError("Failed to generate video")
163
- # Procesamos la música de fondo si existe
164
- music_clip = None
165
- if mp3_file is not None:
166
- music_clip = adjust_background_music(video_clip.duration, mp3_file.name)
167
- # Combinamos todo
168
- final_video_path = combine_audio_video(audio_file, video_clip, music_clip)
169
- if not final_video_path:
170
- raise ValueError("Failed to combine audio and video")
171
- # Subimos a Google Drive
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  video_id = upload_to_google_drive(final_video_path, folder_id=FOLDER_ID)
173
  if video_id:
174
  print(f"Video subido a Google Drive con ID: {video_id}")
175
  else:
176
  print("Error subiendo el video a Google Drive")
177
-
178
  return final_video_path
 
179
  except Exception as e:
180
  print(f"Error durante el procesamiento: {e}")
181
- return None
182
-
183
- # Interfaz Gradio
184
- with gr.Blocks() as demo:
185
- gr.Markdown("# Text-to-Video Generator")
186
- with gr.Row():
187
- with gr.Column():
188
- text_input = gr.Textbox(label="Write your text here", lines=5)
189
- txt_file_input = gr.File(label="Or upload a .txt file", file_types=[".txt"])
190
- mp3_file_input = gr.File(label="Upload background music (.mp3)", file_types=[".mp3"])
191
- keyword_input = gr.Textbox(
192
- label="Enter keywords separated by commas (e.g., universe, galaxy, forest, cat)",
193
- value="nature"
194
- )
195
- voices = asyncio.run(get_voices())
196
- voice_dropdown = gr.Dropdown(choices=list(voices.keys()), label="Select Voice")
197
- rate_slider = gr.Slider(minimum=-50, maximum=50, value=0, label="Speech Rate Adjustment (%)", step=1)
198
- pitch_slider = gr.Slider(minimum=-20, maximum=20, value=0, label="Pitch Adjustment (Hz)", step=1)
199
- with gr.Column():
200
- output_video = gr.File(label="Generated Video") # En lugar de gr.Video
201
-
202
- btn = gr.Button("Generate Video")
203
- btn.click(
204
- process_input,
205
- inputs=[text_input, txt_file_input, mp3_file_input, voice_dropdown, rate_slider, pitch_slider, keyword_input],
206
- outputs=output_video
207
- )
208
-
209
- # Leer el puerto asignado por Hugging Face
210
- port = int(os.getenv("PORT", 7860))
211
-
212
- # Lanzar la aplicación
213
- demo.launch(server_name="0.0.0.0", server_port=port, share=True, show_error=True)
 
1
+ def process_input_with_resume(text, txt_file, mp3_file, selected_voice, rate, pitch, keywords):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  try:
3
  # Determinamos el texto a usar
4
  if text.strip():
 
7
  final_text = txt_file.decode("utf-8")
8
  else:
9
  raise ValueError("No text input provided")
10
+
11
+ # Dividimos el texto en segmentos
12
+ segments = split_text_into_segments(final_text, max_segment_length=30)
13
+ video_clips = []
14
+
15
+ for i, segment in enumerate(segments):
16
+ segment_file = os.path.join(output_folder, f"segment_{i}.mp4")
17
+ if os.path.exists(segment_file): # Verifica si el segmento ya existe
18
+ print(f"Segmento {i} ya procesado, saltando...")
19
+ video_clips.append(VideoFileClip(segment_file))
20
+ continue
21
+
22
+ print(f"Procesando segmento {i + 1}/{len(segments)}...")
23
+ audio_segment = asyncio.run(text_to_speech(segment, selected_voice, rate, pitch))
24
+ if not audio_segment:
25
+ raise ValueError(f"Failed to generate audio for segment {i + 1}")
26
+
27
+ video_clip = concatenate_pixabay_videos(keywords, num_videos_per_keyword=1)
28
+ if not video_clip:
29
+ raise ValueError(f"Failed to generate video for segment {i + 1}")
30
+
31
+ music_clip = adjust_background_music(video_clip.duration, mp3_file.name) if mp3_file else None
32
+ video_segment_path = combine_audio_video(audio_segment, video_clip, music_clip)
33
+
34
+ # Guardamos el segmento
35
+ os.rename(video_segment_path, segment_file)
36
+ video_clips.append(VideoFileClip(segment_file))
37
+
38
+ # Subimos el segmento a Google Drive (opcional)
39
+ upload_to_google_drive(segment_file, folder_id=FOLDER_ID)
40
+
41
+ # Combinamos todos los segmentos en un solo video
42
+ final_video_clip = concatenate_videoclips(video_clips, method="compose")
43
+ final_video_path = os.path.join(output_folder, f"final_video_{int(time.time())}.mp4")
44
+ final_video_clip.write_videofile(final_video_path, codec="libx264", audio_codec="aac", fps=24)
45
+
46
+ # Subimos el video final a Google Drive
47
  video_id = upload_to_google_drive(final_video_path, folder_id=FOLDER_ID)
48
  if video_id:
49
  print(f"Video subido a Google Drive con ID: {video_id}")
50
  else:
51
  print("Error subiendo el video a Google Drive")
52
+
53
  return final_video_path
54
+
55
  except Exception as e:
56
  print(f"Error durante el procesamiento: {e}")
57
+ return None