gnosticdev commited on
Commit
e2aa189
verified
1 Parent(s): 9c62553

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +43 -85
app.py CHANGED
@@ -1,38 +1,38 @@
1
  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
  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):
14
- import subprocess
15
- import sys
16
- subprocess.check_call([sys.executable, "-m", "pip", "install", package])
17
-
18
- try:
19
- # Intentar importar moviepy.editor
20
- from moviepy.editor import AudioFileClip, VideoFileClip, CompositeAudioClip, concatenate_audioclips, concatenate_videoclips
21
- print("MoviePy.editor est谩 instalado correctamente.")
22
- except ImportError:
23
- print("Instalando MoviePy...")
24
- install("moviepy==1.0.3") # Forzar instalaci贸n de la versi贸n compatible
25
- try:
26
- from moviepy.editor import AudioFileClip, VideoFileClip, CompositeAudioClip, concatenate_audioclips, concatenate_videoclips
27
- print("MoviePy.editor instalado con 茅xito despu茅s de la reinstalaci贸n.")
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:
@@ -41,10 +41,10 @@ def adjust_background_music(video_duration, music_file):
41
  music = concatenate_audioclips(music_clips)
42
  if music.duration > video_duration:
43
  music = music.subclip(0, 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 = []
@@ -52,7 +52,7 @@ def concatenate_pexels_videos(text, num_videos=5):
52
  try:
53
  links = search_pexels(sentence, num_results=num_videos)
54
  if links:
55
- video_links.append(links[0]) # Usamos el primer video encontrado para cada frase
56
  except Exception as e:
57
  print(f"Error al buscar video para la frase '{sentence}': {e}")
58
  continue
@@ -64,20 +64,17 @@ def concatenate_pexels_videos(text, num_videos=5):
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
@@ -85,14 +82,10 @@ def combine_audio_video(audio_file, video_clip, music_clip=None):
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
 
@@ -104,72 +97,34 @@ def process_input(text, txt_file, mp3_file, selected_voice, rate, pitch):
104
  elif txt_file is not None:
105
  final_text = txt_file.decode("utf-8")
106
  else:
107
- return None # Devolver None si no hay entrada v谩lida
108
 
109
- # Obtener voces disponibles
110
  voices = asyncio.run(get_voices())
111
  if selected_voice not in voices:
112
  return f"La voz '{selected_voice}' no es v谩lida. Por favor, seleccione una de las siguientes voces: {', '.join(voices.keys())}"
113
 
114
- # Generar audio con edge_tts
115
  try:
116
  audio_file = asyncio.run(text_to_speech(final_text, selected_voice, rate, pitch))
117
  except Exception as e:
118
  return f"Error con la voz seleccionada: {e}"
119
 
120
- # Concatenar m煤ltiples videos de Pexels basados en el texto
121
  try:
122
  video_clip = concatenate_pexels_videos(final_text, num_videos=5)
123
  except Exception as e:
124
  return f"Error al buscar videos en Pexels: {e}"
125
 
126
- # Ajustar m煤sica de fondo
127
  if mp3_file is not None:
128
  music_clip = adjust_background_music(video_clip.duration, mp3_file.name)
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 solo la ruta del video generado
136
  return final_video_path
137
 
138
  except Exception as e:
139
  return f"Error durante el procesamiento: {e}"
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
- # Leer el puerto asignado por Hugging Face o usar 7860 como valor predeterminado
171
- port = int(os.getenv("PORT", 7860))
172
-
173
  # Interfaz Gradio
174
  with gr.Blocks() as demo:
175
  gr.Markdown("# Text-to-Video Generator")
@@ -178,12 +133,12 @@ with gr.Blocks() as demo:
178
  text_input = gr.Textbox(label="Write your text here", lines=5)
179
  txt_file_input = gr.File(label="Or upload a .txt file", file_types=[".txt"])
180
  mp3_file_input = gr.File(label="Upload background music (.mp3)", file_types=[".mp3"])
181
- voices = asyncio.run(get_voices()) # Obtener voces disponibles
182
  voice_dropdown = gr.Dropdown(choices=list(voices.keys()), label="Select Voice")
183
  rate_slider = gr.Slider(minimum=-50, maximum=50, value=0, label="Speech Rate Adjustment (%)", step=1)
184
  pitch_slider = gr.Slider(minimum=-20, maximum=20, value=0, label="Pitch Adjustment (Hz)", step=1)
185
  with gr.Column():
186
- output_video = gr.File(label="Download Generated Video") # Usar gr.File para permitir descargas
187
 
188
  btn = gr.Button("Generate Video")
189
  btn.click(
@@ -192,5 +147,8 @@ with gr.Blocks() as demo:
192
  outputs=output_video
193
  )
194
 
195
- # Lanzar la aplicaci贸n usando el puerto asignado por Hugging Face
 
 
 
196
  demo.launch(server_name="0.0.0.0", server_port=port, share=True)
 
1
  import gradio as gr
2
+ from tts_module import get_voices, text_to_speech
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 time
8
+ import requests
9
+ from googleapiclient.discovery import build
10
+ from googleapiclient.http import MediaFileUpload
11
+ import tempfile
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
+ # Define la carpeta de salida temporal
14
  output_folder = "outputs"
15
+ os.makedirs(output_folder, exist_ok=True)
16
 
17
+ # Sube el archivo al Google Drive usando una variable de entorno para la API Key
18
+ def upload_to_google_drive(file_path):
19
+ try:
20
+ api_key = os.getenv("GOOGLE_API_KEY") # Lee la API Key desde las variables de entorno
21
+ if not api_key:
22
+ print("Error: GOOGLE_API_KEY no est谩 definida en las variables de entorno.")
23
+ return None
24
+
25
+ service = build("drive", "v3", developerKey=api_key)
26
+ file_metadata = {"name": os.path.basename(file_path)}
27
+ media = MediaFileUpload(file_path, resumable=True)
28
+ file = service.files().create(body=file_metadata, media_body=media, fields="id").execute()
29
+ print(f"Archivo subido exitosamente con ID: {file.get('id')}")
30
+ return file.get("id")
31
+ except Exception as e:
32
+ print(f"Error al subir archivo a Google Drive: {e}")
33
+ return None
34
+
35
+ # Ajustar m煤sica de fondo
36
  def adjust_background_music(video_duration, music_file):
37
  music = AudioFileClip(music_file)
38
  if music.duration < video_duration:
 
41
  music = concatenate_audioclips(music_clips)
42
  if music.duration > video_duration:
43
  music = music.subclip(0, video_duration)
44
+ music = music.volumex(0.2)
45
  return music
46
 
47
+ # 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 = []
 
52
  try:
53
  links = search_pexels(sentence, num_results=num_videos)
54
  if links:
55
+ video_links.append(links[0])
56
  except Exception as e:
57
  print(f"Error al buscar video para la frase '{sentence}': {e}")
58
  continue
 
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
  final_clip = concatenate_videoclips(video_clips, method="compose")
68
  return final_clip
69
 
70
+ # Combinar audio, video y m煤sica
71
  def combine_audio_video(audio_file, video_clip, music_clip=None):
72
  audio_clip = AudioFileClip(audio_file)
73
  total_duration = audio_clip.duration + 5
 
74
  if video_clip.duration < total_duration:
75
+ video_clip = video_clip.loop(duration=total_duration)
76
+ video_clip = video_clip.set_duration(total_duration).fadeout(5)
77
+ final_clip = video_clip.set_audio(audio_clip)
 
78
  if music_clip:
79
  if music_clip.duration < total_duration:
80
  repetitions = int(total_duration / music_clip.duration) + 1
 
82
  music_clip = concatenate_audioclips(music_clips)
83
  if music_clip.duration > total_duration:
84
  music_clip = music_clip.subclip(0, total_duration)
85
+ music_clip = music_clip.audio_fadeout(5)
86
+ final_clip = final_clip.set_audio(CompositeAudioClip([audio_clip, music_clip]))
 
 
87
  output_filename = f"final_video_{int(time.time())}.mp4"
88
  output_path = os.path.join(output_folder, output_filename)
 
 
89
  final_clip.write_videofile(output_path, codec="libx264", audio_codec="aac", fps=24)
90
  return output_path
91
 
 
97
  elif txt_file is not None:
98
  final_text = txt_file.decode("utf-8")
99
  else:
100
+ return "No input provided"
101
 
 
102
  voices = asyncio.run(get_voices())
103
  if selected_voice not in voices:
104
  return f"La voz '{selected_voice}' no es v谩lida. Por favor, seleccione una de las siguientes voces: {', '.join(voices.keys())}"
105
 
 
106
  try:
107
  audio_file = asyncio.run(text_to_speech(final_text, selected_voice, rate, pitch))
108
  except Exception as e:
109
  return f"Error con la voz seleccionada: {e}"
110
 
 
111
  try:
112
  video_clip = concatenate_pexels_videos(final_text, num_videos=5)
113
  except Exception as e:
114
  return f"Error al buscar videos en Pexels: {e}"
115
 
 
116
  if mp3_file is not None:
117
  music_clip = adjust_background_music(video_clip.duration, mp3_file.name)
118
  else:
119
  music_clip = None
120
 
 
121
  final_video_path = combine_audio_video(audio_file, video_clip, music_clip)
122
+ upload_to_google_drive(final_video_path) # Sube el video final a Google Drive
 
123
  return final_video_path
124
 
125
  except Exception as e:
126
  return f"Error durante el procesamiento: {e}"
127
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  # Interfaz Gradio
129
  with gr.Blocks() as demo:
130
  gr.Markdown("# Text-to-Video Generator")
 
133
  text_input = gr.Textbox(label="Write your text here", lines=5)
134
  txt_file_input = gr.File(label="Or upload a .txt file", file_types=[".txt"])
135
  mp3_file_input = gr.File(label="Upload background music (.mp3)", file_types=[".mp3"])
136
+ voices = asyncio.run(get_voices())
137
  voice_dropdown = gr.Dropdown(choices=list(voices.keys()), label="Select Voice")
138
  rate_slider = gr.Slider(minimum=-50, maximum=50, value=0, label="Speech Rate Adjustment (%)", step=1)
139
  pitch_slider = gr.Slider(minimum=-20, maximum=20, value=0, label="Pitch Adjustment (Hz)", step=1)
140
  with gr.Column():
141
+ output_video = gr.File(label="Download Generated Video")
142
 
143
  btn = gr.Button("Generate Video")
144
  btn.click(
 
147
  outputs=output_video
148
  )
149
 
150
+ # Leer el puerto asignado por Hugging Face o usar 7860 como valor predeterminado
151
+ port = int(os.getenv("PORT", 7860))
152
+
153
+ # Lanzar la aplicaci贸n
154
  demo.launch(server_name="0.0.0.0", server_port=port, share=True)