Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
@@ -9,7 +9,7 @@ import gradio as gr
|
|
9 |
import torch
|
10 |
from transformers import GPT2Tokenizer, GPT2LMHeadModel
|
11 |
from keybert import KeyBERT
|
12 |
-
# CORRECCIÓN CRÍTICA DEFINITIVA
|
13 |
from moviepy.editor import VideoFileClip, concatenate_videoclips, AudioFileClip, CompositeAudioClip, concatenate_audioclips, AudioClip
|
14 |
import re
|
15 |
import math
|
@@ -176,7 +176,7 @@ def generate_script(prompt, max_length=150):
|
|
176 |
return prompt.strip()
|
177 |
|
178 |
# Función TTS con voz especificada
|
179 |
-
async def text_to_speech(text, output_path, voice):
|
180 |
logger.info(f"Convirtiendo texto a voz | Caracteres: {len(text)} | Voz: {voice} | Salida: {output_path}")
|
181 |
if not text or not text.strip():
|
182 |
logger.warning("Texto vacío para TTS")
|
@@ -708,10 +708,9 @@ def crear_video(prompt_type, input_text, musica_file=None):
|
|
708 |
|
709 |
|
710 |
if musica_audio_looped:
|
711 |
-
# Usar la música loopeada y el audio TTS original para la composición
|
712 |
composite_audio = CompositeAudioClip([
|
713 |
-
musica_audio_looped.volumex(0.2),
|
714 |
-
audio_tts_original.volumex(1.0)
|
715 |
])
|
716 |
|
717 |
if composite_audio.duration is None or composite_audio.duration <= 0:
|
@@ -722,7 +721,7 @@ def crear_video(prompt_type, input_text, musica_file=None):
|
|
722 |
else:
|
723 |
logger.info("Mezcla de audio completada (voz + música).")
|
724 |
final_audio = composite_audio
|
725 |
-
musica_audio = musica_audio_looped
|
726 |
|
727 |
except Exception as e:
|
728 |
logger.warning(f"Error procesando música de fondo: {str(e)}", exc_info=True)
|
@@ -797,7 +796,7 @@ def crear_video(prompt_type, input_text, musica_file=None):
|
|
797 |
except Exception as e:
|
798 |
logger.warning(f"Error cerrando segmento de video en finally: {str(e)}")
|
799 |
|
800 |
-
if musica_audio is not None:
|
801 |
try:
|
802 |
musica_audio.close()
|
803 |
except Exception as e:
|
@@ -848,12 +847,12 @@ def crear_video(prompt_type, input_text, musica_file=None):
|
|
848 |
logger.info(f"Directorio temporal intermedio {temp_dir_intermediate} persistirá para que Gradio lea el video final.")
|
849 |
|
850 |
|
851 |
-
# CAMBIO CRÍTICO: run_app
|
852 |
def run_app(prompt_type, prompt_ia, prompt_manual, musica_file):
|
853 |
logger.info("="*80)
|
854 |
logger.info("SOLICITUD RECIBIDA EN INTERFAZ")
|
855 |
|
856 |
-
# La lógica para elegir el texto de entrada YA ESTÁ AQUÍ
|
857 |
input_text = prompt_ia if prompt_type == "Generar Guion con IA" else prompt_manual
|
858 |
|
859 |
output_video = None
|
@@ -914,26 +913,24 @@ with gr.Blocks(title="Generador de Videos con IA", theme=gr.themes.Soft(), css="
|
|
914 |
value="Generar Guion con IA"
|
915 |
)
|
916 |
|
917 |
-
#
|
918 |
-
|
919 |
-
|
920 |
-
|
921 |
-
|
922 |
-
|
923 |
-
|
924 |
-
|
925 |
-
|
926 |
-
|
927 |
-
|
928 |
-
|
929 |
-
|
930 |
-
|
931 |
-
|
932 |
-
|
933 |
-
|
934 |
-
|
935 |
-
visible=False # Oculto por defecto
|
936 |
-
)
|
937 |
|
938 |
musica_input = gr.Audio(
|
939 |
label="Música de fondo (opcional)",
|
@@ -963,13 +960,13 @@ with gr.Blocks(title="Generador de Videos con IA", theme=gr.themes.Soft(), css="
|
|
963 |
value="Esperando entrada..."
|
964 |
)
|
965 |
|
966 |
-
#
|
967 |
-
# Ahora usamos las Columnas para controlar la visibilidad
|
968 |
prompt_type.change(
|
969 |
lambda x: (gr.update(visible=x == "Generar Guion con IA"),
|
970 |
gr.update(visible=x == "Usar Mi Guion")),
|
971 |
inputs=prompt_type,
|
972 |
-
|
|
|
973 |
)
|
974 |
|
975 |
# Evento click del botón de generar video
|
@@ -977,19 +974,18 @@ with gr.Blocks(title="Generador de Videos con IA", theme=gr.themes.Soft(), css="
|
|
977 |
# Acción 1 (síncrona): Resetear salidas y establecer estado a procesando
|
978 |
lambda: (None, None, gr.update(value="⏳ Procesando... Esto puede tomar 2-5 minutos o más para videos largos.", interactive=False)),
|
979 |
outputs=[video_output, file_output, status_output],
|
980 |
-
queue=True,
|
981 |
).then(
|
982 |
# Acción 2 (asíncrona): Llamar a la función principal de procesamiento
|
983 |
run_app,
|
984 |
# CAMBIO CRÍTICO: Pasar los 4 argumentos definidos por run_app
|
985 |
inputs=[prompt_type, prompt_ia, prompt_manual, musica_input],
|
986 |
-
outputs=[video_output, file_output, status_output]
|
987 |
).then(
|
988 |
# Acción 3 (síncrona): Hacer visible el enlace de descarga si se retornó un archivo
|
989 |
-
# Verificar si file_output tiene un valor (el path)
|
990 |
lambda video_path, file_path: gr.update(visible=file_path is not None),
|
991 |
-
inputs=[video_output, file_output],
|
992 |
-
outputs=[file_output]
|
993 |
)
|
994 |
|
995 |
|
@@ -1024,8 +1020,6 @@ if __name__ == "__main__":
|
|
1024 |
|
1025 |
logger.info("Iniciando aplicación Gradio...")
|
1026 |
try:
|
1027 |
-
# Gradio Queue maneja tareas largas, no es necesario un ajuste global de timeout aquí.
|
1028 |
-
# El timeout se gestiona por solicitud o por el límite del worker de la cola.
|
1029 |
app.launch(server_name="0.0.0.0", server_port=7860, share=False)
|
1030 |
except Exception as e:
|
1031 |
logger.critical(f"No se pudo iniciar la app: {str(e)}", exc_info=True)
|
|
|
9 |
import torch
|
10 |
from transformers import GPT2Tokenizer, GPT2LMHeadModel
|
11 |
from keybert import KeyBERT
|
12 |
+
# CORRECCIÓN CRÍTICA DEFINITIVA: Eliminar 'concatenate_videoclip' (singular) de la importación
|
13 |
from moviepy.editor import VideoFileClip, concatenate_videoclips, AudioFileClip, CompositeAudioClip, concatenate_audioclips, AudioClip
|
14 |
import re
|
15 |
import math
|
|
|
176 |
return prompt.strip()
|
177 |
|
178 |
# Función TTS con voz especificada
|
179 |
+
async def text_to_speech(text, output_path, voice):
|
180 |
logger.info(f"Convirtiendo texto a voz | Caracteres: {len(text)} | Voz: {voice} | Salida: {output_path}")
|
181 |
if not text or not text.strip():
|
182 |
logger.warning("Texto vacío para TTS")
|
|
|
708 |
|
709 |
|
710 |
if musica_audio_looped:
|
|
|
711 |
composite_audio = CompositeAudioClip([
|
712 |
+
musica_audio_looped.volumex(0.2),
|
713 |
+
audio_tts_original.volumex(1.0)
|
714 |
])
|
715 |
|
716 |
if composite_audio.duration is None or composite_audio.duration <= 0:
|
|
|
721 |
else:
|
722 |
logger.info("Mezcla de audio completada (voz + música).")
|
723 |
final_audio = composite_audio
|
724 |
+
musica_audio = musica_audio_looped
|
725 |
|
726 |
except Exception as e:
|
727 |
logger.warning(f"Error procesando música de fondo: {str(e)}", exc_info=True)
|
|
|
796 |
except Exception as e:
|
797 |
logger.warning(f"Error cerrando segmento de video en finally: {str(e)}")
|
798 |
|
799 |
+
if musica_audio is not None:
|
800 |
try:
|
801 |
musica_audio.close()
|
802 |
except Exception as e:
|
|
|
847 |
logger.info(f"Directorio temporal intermedio {temp_dir_intermediate} persistirá para que Gradio lea el video final.")
|
848 |
|
849 |
|
850 |
+
# CAMBIO CRÍTICO: run_app define 4 argumentos
|
851 |
def run_app(prompt_type, prompt_ia, prompt_manual, musica_file):
|
852 |
logger.info("="*80)
|
853 |
logger.info("SOLICITUD RECIBIDA EN INTERFAZ")
|
854 |
|
855 |
+
# La lógica para elegir el texto de entrada YA ESTÁ AQUÍ y funciona con ambos inputs pasados
|
856 |
input_text = prompt_ia if prompt_type == "Generar Guion con IA" else prompt_manual
|
857 |
|
858 |
output_video = None
|
|
|
913 |
value="Generar Guion con IA"
|
914 |
)
|
915 |
|
916 |
+
# Contenedores para los campos de texto para controlar la visibilidad
|
917 |
+
with gr.Column(visible=True) as ia_guion_column:
|
918 |
+
prompt_ia = gr.Textbox(
|
919 |
+
label="Tema para IA",
|
920 |
+
lines=2,
|
921 |
+
placeholder="Ej: Un paisaje natural con montañas y ríos al amanecer...",
|
922 |
+
max_lines=4,
|
923 |
+
value=""
|
924 |
+
)
|
925 |
+
|
926 |
+
with gr.Column(visible=False) as manual_guion_column:
|
927 |
+
prompt_manual = gr.Textbox(
|
928 |
+
label="Tu Guion Completo",
|
929 |
+
lines=5,
|
930 |
+
placeholder="Ej: En este video exploraremos los misterios del océano...",
|
931 |
+
max_lines=10,
|
932 |
+
value=""
|
933 |
+
)
|
|
|
|
|
934 |
|
935 |
musica_input = gr.Audio(
|
936 |
label="Música de fondo (opcional)",
|
|
|
960 |
value="Esperando entrada..."
|
961 |
)
|
962 |
|
963 |
+
# CAMBIO CRÍTICO: Controlar la visibilidad de las COLUMNAS contenedoras
|
|
|
964 |
prompt_type.change(
|
965 |
lambda x: (gr.update(visible=x == "Generar Guion con IA"),
|
966 |
gr.update(visible=x == "Usar Mi Guion")),
|
967 |
inputs=prompt_type,
|
968 |
+
# Apuntar a los componentes Column padre
|
969 |
+
outputs=[ia_guion_column, manual_guion_column]
|
970 |
)
|
971 |
|
972 |
# Evento click del botón de generar video
|
|
|
974 |
# Acción 1 (síncrona): Resetear salidas y establecer estado a procesando
|
975 |
lambda: (None, None, gr.update(value="⏳ Procesando... Esto puede tomar 2-5 minutos o más para videos largos.", interactive=False)),
|
976 |
outputs=[video_output, file_output, status_output],
|
977 |
+
queue=True,
|
978 |
).then(
|
979 |
# Acción 2 (asíncrona): Llamar a la función principal de procesamiento
|
980 |
run_app,
|
981 |
# CAMBIO CRÍTICO: Pasar los 4 argumentos definidos por run_app
|
982 |
inputs=[prompt_type, prompt_ia, prompt_manual, musica_input],
|
983 |
+
outputs=[video_output, file_output, status_output]
|
984 |
).then(
|
985 |
# Acción 3 (síncrona): Hacer visible el enlace de descarga si se retornó un archivo
|
|
|
986 |
lambda video_path, file_path: gr.update(visible=file_path is not None),
|
987 |
+
inputs=[video_output, file_output],
|
988 |
+
outputs=[file_output]
|
989 |
)
|
990 |
|
991 |
|
|
|
1020 |
|
1021 |
logger.info("Iniciando aplicación Gradio...")
|
1022 |
try:
|
|
|
|
|
1023 |
app.launch(server_name="0.0.0.0", server_port=7860, share=False)
|
1024 |
except Exception as e:
|
1025 |
logger.critical(f"No se pudo iniciar la app: {str(e)}", exc_info=True)
|