Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -399,7 +399,15 @@ def extract_visual_keywords_from_script(script_text):
|
|
| 399 |
logger.info("Extrayendo palabras clave del guion")
|
| 400 |
if not script_text or not script_text.strip():
|
| 401 |
logger.warning("Guion vacío, no se pueden extraer palabras clave.")
|
| 402 |
-
return ["
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 403 |
|
| 404 |
clean_text = re.sub(r'[^\w\sáéíóúñÁÉÍÓÚÑ]', '', script_text)
|
| 405 |
keywords_list = []
|
|
@@ -1036,25 +1044,23 @@ with gr.Blocks(title="Generador de Videos con IA", theme=gr.themes.Soft(), css="
|
|
| 1036 |
value="Generar Guion con IA"
|
| 1037 |
)
|
| 1038 |
|
| 1039 |
-
# Contenedores para
|
| 1040 |
with gr.Column(visible=True) as ia_guion_column:
|
| 1041 |
prompt_ia = gr.Textbox(
|
| 1042 |
label="Tema para IA",
|
| 1043 |
lines=2,
|
| 1044 |
-
placeholder="Ej: Un paisaje natural con montañas y ríos al amanecer
|
| 1045 |
max_lines=4,
|
| 1046 |
value=""
|
| 1047 |
-
# visible=... <-- ¡NO DEBE ESTAR AQUÍ!
|
| 1048 |
)
|
| 1049 |
|
| 1050 |
with gr.Column(visible=False) as manual_guion_column:
|
| 1051 |
prompt_manual = gr.Textbox(
|
| 1052 |
label="Tu Guion Completo",
|
| 1053 |
lines=5,
|
| 1054 |
-
placeholder="Ej: En este video exploraremos los misterios del océano
|
| 1055 |
max_lines=10,
|
| 1056 |
value=""
|
| 1057 |
-
# visible=... <-- ¡NO DEBE ESTAR AQUÍ!
|
| 1058 |
)
|
| 1059 |
|
| 1060 |
musica_input = gr.Audio(
|
|
@@ -1062,20 +1068,17 @@ with gr.Blocks(title="Generador de Videos con IA", theme=gr.themes.Soft(), css="
|
|
| 1062 |
type="filepath",
|
| 1063 |
interactive=True,
|
| 1064 |
value=None
|
| 1065 |
-
# visible=... <-- ¡NO DEBE ESTAR AQUÍ!
|
| 1066 |
)
|
| 1067 |
|
| 1068 |
-
# ---
|
| 1069 |
voice_dropdown = gr.Dropdown(
|
| 1070 |
label="Seleccionar Voz para Guion",
|
| 1071 |
-
choices=AVAILABLE_VOICES,
|
| 1072 |
-
value=DEFAULT_VOICE_ID,
|
| 1073 |
interactive=True
|
| 1074 |
-
# visible=... <-- ¡NO DEBE ESTAR AQUÍ!
|
| 1075 |
)
|
| 1076 |
# --- FIN COMPONENTE ---
|
| 1077 |
|
| 1078 |
-
|
| 1079 |
generate_btn = gr.Button("✨ Generar Video", variant="primary")
|
| 1080 |
|
| 1081 |
with gr.Column():
|
|
@@ -1083,13 +1086,11 @@ with gr.Blocks(title="Generador de Videos con IA", theme=gr.themes.Soft(), css="
|
|
| 1083 |
label="Previsualización del Video Generado",
|
| 1084 |
interactive=False,
|
| 1085 |
height=400
|
| 1086 |
-
# visible=... <-- ¡NO DEBE ESTAR AQUÍ!
|
| 1087 |
)
|
| 1088 |
file_output = gr.File(
|
| 1089 |
label="Descargar Archivo de Video",
|
| 1090 |
interactive=False,
|
| 1091 |
-
visible=False
|
| 1092 |
-
# visible=... <-- ¡NO DEBE ESTAR AQUÍ si ya está visible=False arriba!
|
| 1093 |
)
|
| 1094 |
status_output = gr.Textbox(
|
| 1095 |
label="Estado",
|
|
@@ -1097,51 +1098,44 @@ with gr.Blocks(title="Generador de Videos con IA", theme=gr.themes.Soft(), css="
|
|
| 1097 |
show_label=False,
|
| 1098 |
placeholder="Esperando acción...",
|
| 1099 |
value="Esperando entrada..."
|
| 1100 |
-
# visible=... <-- ¡NO DEBE ESTAR AQUÍ!
|
| 1101 |
)
|
| 1102 |
|
| 1103 |
-
#
|
| 1104 |
prompt_type.change(
|
| 1105 |
lambda x: (gr.update(visible=x == "Generar Guion con IA"),
|
| 1106 |
gr.update(visible=x == "Usar Mi Guion")),
|
| 1107 |
inputs=prompt_type,
|
| 1108 |
-
outputs=[ia_guion_column, manual_guion_column]
|
| 1109 |
)
|
| 1110 |
|
| 1111 |
-
#
|
| 1112 |
generate_btn.click(
|
| 1113 |
-
# Acción 1 (síncrona): Resetear salidas y establecer estado
|
| 1114 |
lambda: (None, None, gr.update(value="⏳ Procesando... Esto puede tomar varios minutos.", interactive=False)),
|
| 1115 |
outputs=[video_output, file_output, status_output],
|
| 1116 |
-
queue=True,
|
| 1117 |
).then(
|
| 1118 |
-
# Acción 2 (asíncrona): Llamar a la función principal
|
| 1119 |
run_app,
|
| 1120 |
-
|
| 1121 |
-
inputs=[prompt_type, prompt_ia, prompt_manual, musica_input, voice_dropdown], # <-- Pasar los 5 inputs a run_app
|
| 1122 |
-
# run_app retornará los 3 outputs esperados
|
| 1123 |
outputs=[video_output, file_output, status_output]
|
| 1124 |
).then(
|
| 1125 |
-
# Acción 3 (síncrona): Hacer visible el enlace de descarga
|
| 1126 |
lambda video_path, file_path, status_msg: gr.update(visible=file_path is not None),
|
| 1127 |
inputs=[video_output, file_output, status_output],
|
| 1128 |
outputs=[file_output]
|
| 1129 |
)
|
| 1130 |
|
| 1131 |
-
|
| 1132 |
gr.Markdown("### Instrucciones:")
|
| 1133 |
gr.Markdown("""
|
| 1134 |
1. **Clave API de Pexels:** Asegúrate de haber configurado la variable de entorno `PEXELS_API_KEY` con tu clave.
|
| 1135 |
2. **Selecciona el tipo de entrada**: "Generar Guion con IA" o "Usar Mi Guion".
|
| 1136 |
-
3. **Sube música** (opcional)
|
| 1137 |
-
4. **Selecciona la voz** deseada
|
| 1138 |
5. **Haz clic en "✨ Generar Video"**.
|
| 1139 |
-
6. Espera
|
| 1140 |
-
7.
|
| 1141 |
-
8. Revisa `video_generator_full.log`
|
| 1142 |
""")
|
| 1143 |
gr.Markdown("---")
|
| 1144 |
-
gr.Markdown("Desarrollado por [Tu Nombre/Empresa/Alias
|
| 1145 |
|
| 1146 |
if __name__ == "__main__":
|
| 1147 |
logger.info("Verificando dependencias críticas...")
|
|
@@ -1152,17 +1146,17 @@ if __name__ == "__main__":
|
|
| 1152 |
temp_clip.close()
|
| 1153 |
logger.info("Clips base de MoviePy creados y cerrados exitosamente. FFmpeg parece accesible.")
|
| 1154 |
except Exception as e:
|
| 1155 |
-
logger.critical(f"Fallo al crear clip base de MoviePy.
|
| 1156 |
-
|
| 1157 |
except Exception as e:
|
| 1158 |
-
|
| 1159 |
|
| 1160 |
-
#
|
| 1161 |
-
os.environ['GRADIO_SERVER_TIMEOUT'] = '6000' #
|
|
|
|
| 1162 |
|
| 1163 |
logger.info("Iniciando aplicación Gradio...")
|
| 1164 |
try:
|
| 1165 |
-
app.launch(server_name="0.0.0.0", server_port=7860, share=False)
|
| 1166 |
except Exception as e:
|
| 1167 |
logger.critical(f"No se pudo iniciar la app: {str(e)}", exc_info=True)
|
| 1168 |
-
raise
|
|
|
|
| 399 |
logger.info("Extrayendo palabras clave del guion")
|
| 400 |
if not script_text or not script_text.strip():
|
| 401 |
logger.warning("Guion vacío, no se pueden extraer palabras clave.")
|
| 402 |
+
return ["distopico", "dark", "terror", "ansiedad", "encuentros", "demonios", "siniestro",
|
| 403 |
+
"oscuro", "noche", "niebla", "abandonado", "miedo", "suspenso", "sombrio", "lluvia", "tormenta", "bosque", "cementerio",
|
| 404 |
+
"iglesia", "ruinas", "hospital", "escuela", "tunel", "puente", "carretera", "desierto", "pantano", "cueva", "paredes",
|
| 405 |
+
"ventanas rotas", "sombras", "silueta", "ojos", "susurros", "gritos", "corredor", "puerta cerrada", "escaleras",
|
| 406 |
+
"reloj parado", "matrix", "muñeca", "manchas", "sangre", "cadenas", "ritual", "velas", "libro antiguo",
|
| 407 |
+
"cruz invertida", "campanario", "campana", "nieve oscura", "cielo rojo", "luna llena", "animales muertos",
|
| 408 |
+
"cuervos", "arañas", "telarañas", "niebla densa", "luces parpadeando", "televisor estático", "radio interferencia",
|
| 409 |
+
"voz distorsionada", "figura encapuchada", "mascaras", "manos", "pies descalzos", "huellas", "ventana abierta",
|
| 410 |
+
"viento fuerte", "reloj de pared", "sotano"]
|
| 411 |
|
| 412 |
clean_text = re.sub(r'[^\w\sáéíóúñÁÉÍÓÚÑ]', '', script_text)
|
| 413 |
keywords_list = []
|
|
|
|
| 1044 |
value="Generar Guion con IA"
|
| 1045 |
)
|
| 1046 |
|
| 1047 |
+
# Contenedores para controlar la visibilidad
|
| 1048 |
with gr.Column(visible=True) as ia_guion_column:
|
| 1049 |
prompt_ia = gr.Textbox(
|
| 1050 |
label="Tema para IA",
|
| 1051 |
lines=2,
|
| 1052 |
+
placeholder="Ej: Un paisaje natural con montañas y ríos al amanecer...",
|
| 1053 |
max_lines=4,
|
| 1054 |
value=""
|
|
|
|
| 1055 |
)
|
| 1056 |
|
| 1057 |
with gr.Column(visible=False) as manual_guion_column:
|
| 1058 |
prompt_manual = gr.Textbox(
|
| 1059 |
label="Tu Guion Completo",
|
| 1060 |
lines=5,
|
| 1061 |
+
placeholder="Ej: En este video exploraremos los misterios del océano...",
|
| 1062 |
max_lines=10,
|
| 1063 |
value=""
|
|
|
|
| 1064 |
)
|
| 1065 |
|
| 1066 |
musica_input = gr.Audio(
|
|
|
|
| 1068 |
type="filepath",
|
| 1069 |
interactive=True,
|
| 1070 |
value=None
|
|
|
|
| 1071 |
)
|
| 1072 |
|
| 1073 |
+
# --- Selección de Voz ---
|
| 1074 |
voice_dropdown = gr.Dropdown(
|
| 1075 |
label="Seleccionar Voz para Guion",
|
| 1076 |
+
choices=AVAILABLE_VOICES,
|
| 1077 |
+
value=DEFAULT_VOICE_ID,
|
| 1078 |
interactive=True
|
|
|
|
| 1079 |
)
|
| 1080 |
# --- FIN COMPONENTE ---
|
| 1081 |
|
|
|
|
| 1082 |
generate_btn = gr.Button("✨ Generar Video", variant="primary")
|
| 1083 |
|
| 1084 |
with gr.Column():
|
|
|
|
| 1086 |
label="Previsualización del Video Generado",
|
| 1087 |
interactive=False,
|
| 1088 |
height=400
|
|
|
|
| 1089 |
)
|
| 1090 |
file_output = gr.File(
|
| 1091 |
label="Descargar Archivo de Video",
|
| 1092 |
interactive=False,
|
| 1093 |
+
visible=False
|
|
|
|
| 1094 |
)
|
| 1095 |
status_output = gr.Textbox(
|
| 1096 |
label="Estado",
|
|
|
|
| 1098 |
show_label=False,
|
| 1099 |
placeholder="Esperando acción...",
|
| 1100 |
value="Esperando entrada..."
|
|
|
|
| 1101 |
)
|
| 1102 |
|
| 1103 |
+
# Mostrar/ocultar campos de texto
|
| 1104 |
prompt_type.change(
|
| 1105 |
lambda x: (gr.update(visible=x == "Generar Guion con IA"),
|
| 1106 |
gr.update(visible=x == "Usar Mi Guion")),
|
| 1107 |
inputs=prompt_type,
|
| 1108 |
+
outputs=[ia_guion_column, manual_guion_column]
|
| 1109 |
)
|
| 1110 |
|
| 1111 |
+
# Botón generar video con manejo de estado y cola
|
| 1112 |
generate_btn.click(
|
|
|
|
| 1113 |
lambda: (None, None, gr.update(value="⏳ Procesando... Esto puede tomar varios minutos.", interactive=False)),
|
| 1114 |
outputs=[video_output, file_output, status_output],
|
| 1115 |
+
queue=True,
|
| 1116 |
).then(
|
|
|
|
| 1117 |
run_app,
|
| 1118 |
+
inputs=[prompt_type, prompt_ia, prompt_manual, musica_input, voice_dropdown],
|
|
|
|
|
|
|
| 1119 |
outputs=[video_output, file_output, status_output]
|
| 1120 |
).then(
|
|
|
|
| 1121 |
lambda video_path, file_path, status_msg: gr.update(visible=file_path is not None),
|
| 1122 |
inputs=[video_output, file_output, status_output],
|
| 1123 |
outputs=[file_output]
|
| 1124 |
)
|
| 1125 |
|
|
|
|
| 1126 |
gr.Markdown("### Instrucciones:")
|
| 1127 |
gr.Markdown("""
|
| 1128 |
1. **Clave API de Pexels:** Asegúrate de haber configurado la variable de entorno `PEXELS_API_KEY` con tu clave.
|
| 1129 |
2. **Selecciona el tipo de entrada**: "Generar Guion con IA" o "Usar Mi Guion".
|
| 1130 |
+
3. **Sube música** (opcional).
|
| 1131 |
+
4. **Selecciona la voz** deseada.
|
| 1132 |
5. **Haz clic en "✨ Generar Video"**.
|
| 1133 |
+
6. Espera el procesamiento (puede tardar varios minutos).
|
| 1134 |
+
7. Se mostrará la previsualización y el enlace de descarga si fue exitoso.
|
| 1135 |
+
8. Revisa `video_generator_full.log` si hay errores.
|
| 1136 |
""")
|
| 1137 |
gr.Markdown("---")
|
| 1138 |
+
gr.Markdown("Desarrollado por [Tu Nombre/Empresa/Alias]")
|
| 1139 |
|
| 1140 |
if __name__ == "__main__":
|
| 1141 |
logger.info("Verificando dependencias críticas...")
|
|
|
|
| 1146 |
temp_clip.close()
|
| 1147 |
logger.info("Clips base de MoviePy creados y cerrados exitosamente. FFmpeg parece accesible.")
|
| 1148 |
except Exception as e:
|
| 1149 |
+
logger.critical(f"Fallo al crear clip base de MoviePy. Error: {e}", exc_info=True)
|
|
|
|
| 1150 |
except Exception as e:
|
| 1151 |
+
logger.critical(f"Fallo al importar MoviePy. Error: {e}", exc_info=True)
|
| 1152 |
|
| 1153 |
+
# --- FIX TIMEOUT ---
|
| 1154 |
+
os.environ['GRADIO_SERVER_TIMEOUT'] = '6000' # 6000 segundos = 100 minutos
|
| 1155 |
+
# -------------------
|
| 1156 |
|
| 1157 |
logger.info("Iniciando aplicación Gradio...")
|
| 1158 |
try:
|
| 1159 |
+
app.queue(max_size=1).launch(server_name="0.0.0.0", server_port=7860, share=False)
|
| 1160 |
except Exception as e:
|
| 1161 |
logger.critical(f"No se pudo iniciar la app: {str(e)}", exc_info=True)
|
| 1162 |
+
raise
|