Spaces:
Running
Running
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)
|