Spaces:
Sleeping
Sleeping
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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|