gnosticdev commited on
Commit
ec0a35b
·
1 Parent(s): 66ecd32

Actualización de app.py para guardar videos en carpeta outputs

Browse files
Files changed (1) hide show
  1. app.py +53 -31
app.py CHANGED
@@ -2,11 +2,12 @@ import gradio as gr
2
  from tts_module import get_voices, text_to_speech # Usamos el tts_module.py actualizado
3
  from pexels_api import search_pexels
4
  from moviepy.editor import AudioFileClip, VideoFileClip, CompositeAudioClip, concatenate_audioclips, concatenate_videoclips
5
-
6
  import asyncio
7
  import os
8
  import requests
9
- import tempfile
 
 
10
 
11
  # Forzar instalación de moviepy si no está disponible
12
  def install(package):
@@ -27,7 +28,11 @@ except ImportError:
27
  except ImportError:
28
  raise ImportError("Error crítico: No se pudo instalar moviepy.editor. Verifica las dependencias.")
29
 
30
- # Ajustar música de fondo (repetición automática)
 
 
 
 
31
  def adjust_background_music(video_duration, music_file):
32
  music = AudioFileClip(music_file)
33
  if music.duration < video_duration:
@@ -39,11 +44,10 @@ def adjust_background_music(video_duration, music_file):
39
  music = music.volumex(0.2) # Reducir volumen al 20%
40
  return music
41
 
42
- # Concatenar múltiples videos de Pexels
43
  def concatenate_pexels_videos(text, num_videos=5):
44
  sentences = [sentence.strip() for sentence in text.split(".") if sentence.strip()]
45
  video_links = []
46
-
47
  for sentence in sentences:
48
  try:
49
  links = search_pexels(sentence, num_results=num_videos)
@@ -52,56 +56,43 @@ def concatenate_pexels_videos(text, num_videos=5):
52
  except Exception as e:
53
  print(f"Error al buscar video para la frase '{sentence}': {e}")
54
  continue
55
-
56
  if not video_links:
57
  raise Exception("No se encontraron videos relevantes para el texto proporcionado.")
58
-
59
  video_clips = []
60
  for link in video_links:
61
  video_response = requests.get(link)
62
  with tempfile.NamedTemporaryFile(delete=False, suffix=".mp4") as tmp_video:
63
  tmp_video.write(video_response.content)
64
  video_clips.append(VideoFileClip(tmp_video.name))
65
-
66
  # Concatenar videos
67
  final_clip = concatenate_videoclips(video_clips, method="compose")
68
  return final_clip
69
 
70
- # Combinar audio, video y música con fade out solo en el video y la música
71
  def combine_audio_video(audio_file, video_clip, music_clip=None):
72
  audio_clip = AudioFileClip(audio_file)
73
-
74
- # Duración total: speech + 5 segundos para fade out
75
  total_duration = audio_clip.duration + 5
76
 
77
- # Extender la duración del video si es más corto que el audio + fade out
78
  if video_clip.duration < total_duration:
79
  video_clip = video_clip.loop(duration=total_duration) # Repetir el video si es necesario
 
 
80
 
81
- # Aplicar fade out solo al video
82
- video_clip = video_clip.set_duration(total_duration).fadeout(5)
83
-
84
- # Combinar audio y video
85
- final_clip = video_clip.set_audio(audio_clip)
86
-
87
- # Añadir música de fondo si aplica
88
  if music_clip:
89
- # Extender la música para que coincida con la duración total
90
  if music_clip.duration < total_duration:
91
  repetitions = int(total_duration / music_clip.duration) + 1
92
  music_clips = [music_clip] * repetitions
93
  music_clip = concatenate_audioclips(music_clips)
94
  if music_clip.duration > total_duration:
95
  music_clip = music_clip.subclip(0, total_duration)
 
 
96
 
97
- # Aplicar fade out a la música
98
- music_clip = music_clip.audio_fadeout(5)
99
-
100
- # Combinar audio principal, música y video
101
- final_clip = final_clip.set_audio(CompositeAudioClip([audio_clip, music_clip]))
102
 
103
  # Exportar el video final
104
- output_path = tempfile.NamedTemporaryFile(delete=False, suffix=".mp4").name
105
  final_clip.write_videofile(output_path, codec="libx264", audio_codec="aac", fps=24)
106
  return output_path
107
 
@@ -138,13 +129,44 @@ def process_input(text, txt_file, mp3_file, selected_voice, rate, pitch):
138
  else:
139
  music_clip = None
140
 
141
- # Combinar audio, video y música con fade out solo en el video y la música
142
- final_video = combine_audio_video(audio_file, video_clip, music_clip)
143
- return final_video
 
 
144
 
145
  except Exception as e:
146
  return f"Error durante el procesamiento: {e}", None
147
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
  # Interfaz Gradio
149
  with gr.Blocks() as demo:
150
  gr.Markdown("# Text-to-Video Generator")
@@ -157,9 +179,8 @@ with gr.Blocks() as demo:
157
  voice_dropdown = gr.Dropdown(choices=list(voices.keys()), label="Select Voice")
158
  rate_slider = gr.Slider(minimum=-50, maximum=50, value=0, label="Speech Rate Adjustment (%)", step=1)
159
  pitch_slider = gr.Slider(minimum=-20, maximum=20, value=0, label="Pitch Adjustment (Hz)", step=1)
160
-
161
  with gr.Column():
162
- output_video = gr.Video(label="Generated Video")
163
 
164
  btn = gr.Button("Generate Video")
165
  btn.click(
@@ -168,4 +189,5 @@ with gr.Blocks() as demo:
168
  outputs=output_video
169
  )
170
 
 
171
  demo.launch(server_name="0.0.0.0", server_port=7860, share=True)
 
2
  from tts_module import get_voices, text_to_speech # Usamos el tts_module.py actualizado
3
  from pexels_api import search_pexels
4
  from moviepy.editor import AudioFileClip, VideoFileClip, CompositeAudioClip, concatenate_audioclips, concatenate_videoclips
 
5
  import asyncio
6
  import os
7
  import requests
8
+ import time
9
+ import threading
10
+ from datetime import datetime, timedelta
11
 
12
  # Forzar instalación de moviepy si no está disponible
13
  def install(package):
 
28
  except ImportError:
29
  raise ImportError("Error crítico: No se pudo instalar moviepy.editor. Verifica las dependencias.")
30
 
31
+ # Define la carpeta de salida
32
+ output_folder = "outputs"
33
+ os.makedirs(output_folder, exist_ok=True) # Crea la carpeta si no existe
34
+
35
+ # Función para ajustar música de fondo (repetición automática)
36
  def adjust_background_music(video_duration, music_file):
37
  music = AudioFileClip(music_file)
38
  if music.duration < video_duration:
 
44
  music = music.volumex(0.2) # Reducir volumen al 20%
45
  return music
46
 
47
+ # Función para concatenar múltiples videos de Pexels
48
  def concatenate_pexels_videos(text, num_videos=5):
49
  sentences = [sentence.strip() for sentence in text.split(".") if sentence.strip()]
50
  video_links = []
 
51
  for sentence in sentences:
52
  try:
53
  links = search_pexels(sentence, num_results=num_videos)
 
56
  except Exception as e:
57
  print(f"Error al buscar video para la frase '{sentence}': {e}")
58
  continue
 
59
  if not video_links:
60
  raise Exception("No se encontraron videos relevantes para el texto proporcionado.")
 
61
  video_clips = []
62
  for link in video_links:
63
  video_response = requests.get(link)
64
  with tempfile.NamedTemporaryFile(delete=False, suffix=".mp4") as tmp_video:
65
  tmp_video.write(video_response.content)
66
  video_clips.append(VideoFileClip(tmp_video.name))
 
67
  # Concatenar videos
68
  final_clip = concatenate_videoclips(video_clips, method="compose")
69
  return final_clip
70
 
71
+ # Función para combinar audio, video y música
72
  def combine_audio_video(audio_file, video_clip, music_clip=None):
73
  audio_clip = AudioFileClip(audio_file)
 
 
74
  total_duration = audio_clip.duration + 5
75
 
 
76
  if video_clip.duration < total_duration:
77
  video_clip = video_clip.loop(duration=total_duration) # Repetir el video si es necesario
78
+ video_clip = video_clip.set_duration(total_duration).fadeout(5) # Aplicar fade out al video
79
+ final_clip = video_clip.set_audio(audio_clip) # Combinar audio y video
80
 
 
 
 
 
 
 
 
81
  if music_clip:
 
82
  if music_clip.duration < total_duration:
83
  repetitions = int(total_duration / music_clip.duration) + 1
84
  music_clips = [music_clip] * repetitions
85
  music_clip = concatenate_audioclips(music_clips)
86
  if music_clip.duration > total_duration:
87
  music_clip = music_clip.subclip(0, total_duration)
88
+ music_clip = music_clip.audio_fadeout(5) # Aplicar fade out a la música
89
+ final_clip = final_clip.set_audio(CompositeAudioClip([audio_clip, music_clip])) # Combinar audio y música
90
 
91
+ # Generar un nombre único para el video
92
+ output_filename = f"final_video_{int(time.time())}.mp4"
93
+ output_path = os.path.join(output_folder, output_filename)
 
 
94
 
95
  # Exportar el video final
 
96
  final_clip.write_videofile(output_path, codec="libx264", audio_codec="aac", fps=24)
97
  return output_path
98
 
 
129
  else:
130
  music_clip = None
131
 
132
+ # Combinar audio, video y música
133
+ final_video_path = combine_audio_video(audio_file, video_clip, music_clip)
134
+
135
+ # Devolver la ruta del video generado
136
+ return final_video_path
137
 
138
  except Exception as e:
139
  return f"Error durante el procesamiento: {e}", None
140
 
141
+ # Función para limpiar archivos antiguos
142
+ def cleanup_old_files(folder_path, max_age_hours=1):
143
+ now = datetime.now()
144
+ threshold = now - timedelta(hours=max_age_hours)
145
+
146
+ for filename in os.listdir(folder_path):
147
+ file_path = os.path.join(folder_path, filename)
148
+ if os.path.isfile(file_path):
149
+ modification_time = datetime.fromtimestamp(os.path.getmtime(file_path))
150
+ if modification_time < threshold:
151
+ try:
152
+ os.remove(file_path)
153
+ print(f"Eliminado archivo antiguo: {file_path}")
154
+ except Exception as e:
155
+ print(f"Error al eliminar {file_path}: {e}")
156
+
157
+ # Iniciar hilo para limpieza automática
158
+ def start_cleanup_thread(folder_path, interval_seconds=300, max_age_hours=1):
159
+ def cleanup_loop():
160
+ while True:
161
+ cleanup_old_files(folder_path, max_age_hours)
162
+ time.sleep(interval_seconds)
163
+
164
+ cleanup_thread = threading.Thread(target=cleanup_loop, daemon=True)
165
+ cleanup_thread.start()
166
+
167
+ # Iniciar el hilo de limpieza al inicio del script
168
+ start_cleanup_thread(output_folder, interval_seconds=300, max_age_hours=1)
169
+
170
  # Interfaz Gradio
171
  with gr.Blocks() as demo:
172
  gr.Markdown("# Text-to-Video Generator")
 
179
  voice_dropdown = gr.Dropdown(choices=list(voices.keys()), label="Select Voice")
180
  rate_slider = gr.Slider(minimum=-50, maximum=50, value=0, label="Speech Rate Adjustment (%)", step=1)
181
  pitch_slider = gr.Slider(minimum=-20, maximum=20, value=0, label="Pitch Adjustment (Hz)", step=1)
 
182
  with gr.Column():
183
+ output_video = gr.File(label="Download Generated Video") # Usar gr.File para permitir descargas
184
 
185
  btn = gr.Button("Generate Video")
186
  btn.click(
 
189
  outputs=output_video
190
  )
191
 
192
+ # Lanzar la aplicación
193
  demo.launch(server_name="0.0.0.0", server_port=7860, share=True)