Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -764,7 +764,7 @@ def crear_video(prompt_type, input_text, musica_file=None):
|
|
| 764 |
|
| 765 |
total_time = (datetime.now() - start_time).total_seconds()
|
| 766 |
logger.info(f"PROCESO DE VIDEO FINALIZADO | Output: {output_path} | Tiempo total: {total_time:.2f}s")
|
| 767 |
-
|
| 768 |
|
| 769 |
except ValueError as ve:
|
| 770 |
logger.error(f"ERROR CONTROLADO en crear_video: {str(ve)}")
|
|
@@ -840,39 +840,44 @@ def crear_video(prompt_type, input_text, musica_file=None):
|
|
| 840 |
def run_app(prompt_type, prompt_ia, prompt_manual, musica_file):
|
| 841 |
logger.info("="*80)
|
| 842 |
logger.info("SOLICITUD RECIBIDA EN INTERFAZ")
|
| 843 |
-
|
| 844 |
input_text = prompt_ia if prompt_type == "Generar Guion con IA" else prompt_manual
|
| 845 |
-
|
| 846 |
output_video = None
|
| 847 |
-
output_file = gr.update(value=None, visible=False)
|
| 848 |
status_msg = gr.update(value="⏳ Procesando...", interactive=False)
|
| 849 |
-
|
| 850 |
if not input_text or not input_text.strip():
|
| 851 |
logger.warning("Texto de entrada vacío.")
|
| 852 |
status_msg = gr.update(value="⚠️ Por favor, ingresa texto para el guion o el tema.", interactive=False)
|
| 853 |
return output_video, output_file, status_msg
|
| 854 |
-
|
| 855 |
logger.info(f"Tipo de entrada: {prompt_type}")
|
| 856 |
logger.debug(f"Texto de entrada: '{input_text[:100]}...'")
|
|
|
|
| 857 |
if musica_file:
|
| 858 |
logger.info(f"Archivo de música recibido: {musica_file}")
|
| 859 |
else:
|
| 860 |
logger.info("No se proporcionó archivo de música.")
|
| 861 |
-
|
| 862 |
try:
|
| 863 |
logger.info("Llamando a crear_video...")
|
| 864 |
video_path = crear_video(prompt_type, input_text, musica_file)
|
| 865 |
-
|
| 866 |
if video_path and os.path.exists(video_path):
|
| 867 |
logger.info(f"crear_video retornó path: {video_path}")
|
| 868 |
logger.info(f"Tamaño del archivo de video retornado: {os.path.getsize(video_path)} bytes")
|
|
|
|
|
|
|
| 869 |
output_video = video_path
|
| 870 |
-
output_file = gr.update(value=video_path, visible=True)
|
| 871 |
status_msg = gr.update(value="✅ Video generado exitosamente.", interactive=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 872 |
else:
|
| 873 |
logger.error(f"crear_video no retornó un path válido o el archivo no existe: {video_path}")
|
| 874 |
status_msg = gr.update(value="❌ Error: La generación del video falló o el archivo no se creó correctamente.", interactive=False)
|
| 875 |
-
|
| 876 |
except ValueError as ve:
|
| 877 |
logger.warning(f"Error de validación durante la creación del video: {str(ve)}")
|
| 878 |
status_msg = gr.update(value=f"⚠️ Error de validación: {str(ve)}", interactive=False)
|
|
@@ -881,111 +886,4 @@ def run_app(prompt_type, prompt_ia, prompt_manual, musica_file):
|
|
| 881 |
status_msg = gr.update(value=f"❌ Error inesperado: {str(e)}", interactive=False)
|
| 882 |
finally:
|
| 883 |
logger.info("Fin del handler run_app.")
|
| 884 |
-
return output_video, output_file, status_msg
|
| 885 |
-
|
| 886 |
-
with gr.Blocks(title="Generador de Videos con IA", theme=gr.themes.Soft(), css="""
|
| 887 |
-
.gradio-container {max-width: 800px; margin: auto;}
|
| 888 |
-
h1 {text-align: center;}
|
| 889 |
-
""") as app:
|
| 890 |
-
|
| 891 |
-
gr.Markdown("# 🎬 Generador Automático de Videos con IA")
|
| 892 |
-
gr.Markdown("Genera videos cortos a partir de un tema o guion, usando imágenes de archivo de Pexels y voz generada.")
|
| 893 |
-
|
| 894 |
-
with gr.Row():
|
| 895 |
-
with gr.Column():
|
| 896 |
-
prompt_type = gr.Radio(
|
| 897 |
-
["Generar Guion con IA", "Usar Mi Guion"],
|
| 898 |
-
label="Método de Entrada",
|
| 899 |
-
value="Generar Guion con IA"
|
| 900 |
-
)
|
| 901 |
-
|
| 902 |
-
with gr.Column(visible=True) as ia_guion_column:
|
| 903 |
-
prompt_ia = gr.Textbox(
|
| 904 |
-
label="Tema para IA",
|
| 905 |
-
lines=2,
|
| 906 |
-
placeholder="Ej: Un paisaje natural con montañas y ríos al amanecer, mostrando la belleza de la naturaleza...",
|
| 907 |
-
max_lines=4,
|
| 908 |
-
value=""
|
| 909 |
-
)
|
| 910 |
-
|
| 911 |
-
with gr.Column(visible=False) as manual_guion_column:
|
| 912 |
-
prompt_manual = gr.Textbox(
|
| 913 |
-
label="Tu Guion Completo",
|
| 914 |
-
lines=5,
|
| 915 |
-
placeholder="Ej: En este video exploraremos los misterios del océano. Veremos la vida marina fascinante y los arrecifes de coral vibrantes. ¡Acompáñanos en esta aventura subacuática!",
|
| 916 |
-
max_lines=10,
|
| 917 |
-
value=""
|
| 918 |
-
)
|
| 919 |
-
|
| 920 |
-
musica_input = gr.Audio(
|
| 921 |
-
label="Música de fondo (opcional)",
|
| 922 |
-
type="filepath",
|
| 923 |
-
interactive=True,
|
| 924 |
-
value=None
|
| 925 |
-
)
|
| 926 |
-
|
| 927 |
-
generate_btn = gr.Button("✨ Generar Video", variant="primary")
|
| 928 |
-
|
| 929 |
-
with gr.Column():
|
| 930 |
-
video_output = gr.Video(
|
| 931 |
-
label="Previsualización del Video Generado",
|
| 932 |
-
interactive=False,
|
| 933 |
-
height=400
|
| 934 |
-
)
|
| 935 |
-
file_output = gr.File(
|
| 936 |
-
label="Descargar Archivo de Video",
|
| 937 |
-
interactive=False,
|
| 938 |
-
visible=False
|
| 939 |
-
)
|
| 940 |
-
status_output = gr.Textbox(
|
| 941 |
-
label="Estado",
|
| 942 |
-
interactive=False,
|
| 943 |
-
show_label=False,
|
| 944 |
-
placeholder="Esperando acción...",
|
| 945 |
-
value="Esperando entrada..."
|
| 946 |
-
)
|
| 947 |
-
|
| 948 |
-
prompt_type.change(
|
| 949 |
-
lambda x: (gr.update(visible=x == "Generar Guion con IA"),
|
| 950 |
-
gr.update(visible=x == "Usar Mi Guion")),
|
| 951 |
-
inputs=prompt_type,
|
| 952 |
-
outputs=[ia_guion_column, manual_guion_column]
|
| 953 |
-
)
|
| 954 |
-
|
| 955 |
-
generate_btn.click(
|
| 956 |
-
lambda: (None, None, gr.update(value="⏳ Procesando... Esto puede tomar varios minutos.", interactive=False)),
|
| 957 |
-
outputs=[video_output, file_output, status_output],
|
| 958 |
-
queue=True,
|
| 959 |
-
).then(
|
| 960 |
-
run_app,
|
| 961 |
-
inputs=[prompt_type, prompt_ia, prompt_manual, musica_input],
|
| 962 |
-
outputs=[video_output, file_output, status_output]
|
| 963 |
-
)
|
| 964 |
-
|
| 965 |
-
gr.Markdown("### Instrucciones:")
|
| 966 |
-
gr.Markdown("""
|
| 967 |
-
1. **Clave API de Pexels:** Asegúrate de haber configurado la variable de entorno `PEXELS_API_KEY` con tu clave.
|
| 968 |
-
""")
|
| 969 |
-
gr.Markdown("---")
|
| 970 |
-
gr.Markdown("Desarrollado por [Tu Nombre/Empresa/Alias - Opcional]")
|
| 971 |
-
|
| 972 |
-
if __name__ == "__main__":
|
| 973 |
-
logger.info("Verificando dependencias críticas...")
|
| 974 |
-
try:
|
| 975 |
-
from moviepy.editor import ColorClip
|
| 976 |
-
try:
|
| 977 |
-
temp_clip = ColorClip((100,100), color=(255,0,0), duration=0.1)
|
| 978 |
-
temp_clip.close()
|
| 979 |
-
logger.info("Clips base de MoviePy (como ColorClip) creados y cerrados exitosamente. FFmpeg parece accesible.")
|
| 980 |
-
except Exception as e:
|
| 981 |
-
logger.critical(f"Fallo al crear clip base de MoviePy. A menudo indica problemas con FFmpeg/ImageMagick. Error: {e}", exc_info=True)
|
| 982 |
-
|
| 983 |
-
except Exception as e:
|
| 984 |
-
logger.critical(f"Fallo al importar MoviePy. Asegúrate de que está instalado. Error: {e}", exc_info=True)
|
| 985 |
-
|
| 986 |
-
logger.info("Iniciando aplicación Gradio...")
|
| 987 |
-
try:
|
| 988 |
-
app.launch(server_name="0.0.0.0", server_port=7860, share=False)
|
| 989 |
-
except Exception as e:
|
| 990 |
-
logger.critical(f"No se pudo iniciar la app: {str(e)}", exc_info=True)
|
| 991 |
-
raise
|
|
|
|
| 764 |
|
| 765 |
total_time = (datetime.now() - start_time).total_seconds()
|
| 766 |
logger.info(f"PROCESO DE VIDEO FINALIZADO | Output: {output_path} | Tiempo total: {total_time:.2f}s")
|
| 767 |
+
return output_path
|
| 768 |
|
| 769 |
except ValueError as ve:
|
| 770 |
logger.error(f"ERROR CONTROLADO en crear_video: {str(ve)}")
|
|
|
|
| 840 |
def run_app(prompt_type, prompt_ia, prompt_manual, musica_file):
|
| 841 |
logger.info("="*80)
|
| 842 |
logger.info("SOLICITUD RECIBIDA EN INTERFAZ")
|
|
|
|
| 843 |
input_text = prompt_ia if prompt_type == "Generar Guion con IA" else prompt_manual
|
|
|
|
| 844 |
output_video = None
|
| 845 |
+
output_file = gr.update(value=None, visible=False) # Inicialmente oculto
|
| 846 |
status_msg = gr.update(value="⏳ Procesando...", interactive=False)
|
| 847 |
+
|
| 848 |
if not input_text or not input_text.strip():
|
| 849 |
logger.warning("Texto de entrada vacío.")
|
| 850 |
status_msg = gr.update(value="⚠️ Por favor, ingresa texto para el guion o el tema.", interactive=False)
|
| 851 |
return output_video, output_file, status_msg
|
| 852 |
+
|
| 853 |
logger.info(f"Tipo de entrada: {prompt_type}")
|
| 854 |
logger.debug(f"Texto de entrada: '{input_text[:100]}...'")
|
| 855 |
+
|
| 856 |
if musica_file:
|
| 857 |
logger.info(f"Archivo de música recibido: {musica_file}")
|
| 858 |
else:
|
| 859 |
logger.info("No se proporcionó archivo de música.")
|
| 860 |
+
|
| 861 |
try:
|
| 862 |
logger.info("Llamando a crear_video...")
|
| 863 |
video_path = crear_video(prompt_type, input_text, musica_file)
|
| 864 |
+
|
| 865 |
if video_path and os.path.exists(video_path):
|
| 866 |
logger.info(f"crear_video retornó path: {video_path}")
|
| 867 |
logger.info(f"Tamaño del archivo de video retornado: {os.path.getsize(video_path)} bytes")
|
| 868 |
+
|
| 869 |
+
# ASIGNACIÓN CORRECTA - HACER VISIBLE EL BOTÓN DE DESCARGA
|
| 870 |
output_video = video_path
|
| 871 |
+
output_file = gr.update(value=video_path, visible=True) # CAMBIAR A TRUE
|
| 872 |
status_msg = gr.update(value="✅ Video generado exitosamente.", interactive=False)
|
| 873 |
+
|
| 874 |
+
# IMPRIMIR LINK DIRECTO EN CONSOLA
|
| 875 |
+
print(f"\n\nLINK DE DESCARGA DIRECTO: file://{video_path}\n\n")
|
| 876 |
+
|
| 877 |
else:
|
| 878 |
logger.error(f"crear_video no retornó un path válido o el archivo no existe: {video_path}")
|
| 879 |
status_msg = gr.update(value="❌ Error: La generación del video falló o el archivo no se creó correctamente.", interactive=False)
|
| 880 |
+
|
| 881 |
except ValueError as ve:
|
| 882 |
logger.warning(f"Error de validación durante la creación del video: {str(ve)}")
|
| 883 |
status_msg = gr.update(value=f"⚠️ Error de validación: {str(ve)}", interactive=False)
|
|
|
|
| 886 |
status_msg = gr.update(value=f"❌ Error inesperado: {str(e)}", interactive=False)
|
| 887 |
finally:
|
| 888 |
logger.info("Fin del handler run_app.")
|
| 889 |
+
return output_video, output_file, status_msg
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|