Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import pandas as pd | |
| import joblib | |
| import os | |
| from huggingface_hub import hf_hub_download | |
| from dotenv import load_dotenv | |
| load_dotenv() | |
| # ============================================================================== | |
| # 1. CARGA DEL MODELO DESDE HUGGING FACE (CLOUD) | |
| # ============================================================================== | |
| # Cambia 'TU_USUARIO' por tu nombre de usuario en Hugging Face | |
| repo_id = "larxmind/student-dropout-predictor-rf" | |
| nombre_archivo = "modelo_rf_optimizado.pkl" | |
| try: | |
| print(f"⏳ Conectando con Hugging Face para descargar el modelo '{repo_id}'...") | |
| ruta_modelo_cache = hf_hub_download(repo_id=repo_id, filename=nombre_archivo) | |
| modelo = joblib.load(ruta_modelo_cache) | |
| print("✅ Modelo Cloud cargado correctamente y listo para inferencia.") | |
| except Exception as e: | |
| print(f"❌ Error crítico al cargar el modelo desde la nube: {e}") | |
| print("Asegúrate de que el repositorio es público o de que tu HF_TOKEN está en el .env") | |
| # ============================================================================== | |
| # 2. FUNCIÓN DE PREDICCIÓN | |
| # ============================================================================== | |
| def predecir_abandono(genero, region, nivel_educativo, nivel_economico, rango_edad, | |
| intentos_previos, creditos, discapacidad, | |
| clics, entregas, nota, asistencia): | |
| # Preparamos el dataframe emulando las columnas que espera tu modelo | |
| datos_entrada = pd.DataFrame([{ | |
| 'code_module': 0, | |
| 'code_presentation': 0, | |
| 'genero': 0 if genero == 'F' else 1, | |
| 'region': 0, | |
| 'nivel_educativo': 1, | |
| 'nivel_economico': 5, | |
| 'rango_edad': 0 if rango_edad == '0-35' else (1 if rango_edad == '35-55' else 2), | |
| 'intentos_previos': intentos_previos, | |
| 'creditos_matriculados': creditos, | |
| 'discapacidad': 1 if discapacidad == 'Sí' else 0, | |
| 'total_clics': clics, | |
| 'evaluaciones_entregadas': entregas, | |
| 'nota_media': nota, | |
| 'dias_asistencia_mes': asistencia | |
| }]) | |
| # ------------------------------------------------------------------------- | |
| # 🛡️ BLINDAJE DE COLUMNAS: Reordenar exactamente como en el entrenamiento | |
| # ------------------------------------------------------------------------- | |
| if hasattr(modelo, 'feature_names_in_'): | |
| # Rellenamos columnas que falten (por si el encoder creó más de la cuenta) | |
| for col in modelo.feature_names_in_: | |
| if col not in datos_entrada.columns: | |
| datos_entrada[col] = 0 | |
| # Forzamos el orden estricto | |
| datos_entrada = datos_entrada[modelo.feature_names_in_] | |
| # ------------------------------------------------------------------------- | |
| # Extraemos probabilidad (clase 1 = Abandono) y la predicción final | |
| probabilidad = modelo.predict_proba(datos_entrada)[0][1] | |
| prediccion = modelo.predict(datos_entrada)[0] | |
| if prediccion == 1: | |
| return f"⚠️ RIESGO ALTO DE ABANDONO ({probabilidad:.1%})", "Se recomienda intervención inmediata por parte del tutor." | |
| else: | |
| return f"✅ ESTUDIANTE SEGURO ({1 - probabilidad:.1%} de permanencia)", "El ritmo de estudio es adecuado." | |
| # ============================================================================== | |
| # 3. INTERFAZ GRÁFICA (GRADIO BLOCKS) | |
| # ============================================================================== | |
| with gr.Blocks() as demo: | |
| gr.Markdown( | |
| """ | |
| # 🎓 Sistema de Alerta Temprana (Early Warning System) | |
| ### Predicción de Abandono Estudiantil basada en Telemetría (Primeros 45 días) | |
| """ | |
| ) | |
| with gr.Row(): | |
| # COLUMNA 1: Perfil | |
| with gr.Column(): | |
| gr.Markdown("### 👤 Perfil del Estudiante") | |
| genero = gr.Radio(choices=["M", "F"], label="Género", value="F") | |
| rango_edad = gr.Dropdown(choices=["0-35", "35-55", "55<="], label="Rango de Edad", value="0-35") | |
| discapacidad = gr.Radio(choices=["Sí", "No"], label="¿Discapacidad declarada?", value="No") | |
| region = gr.Textbox(label="Región (Ej. Scotland)", placeholder="Opcional") | |
| nivel_educativo = gr.Textbox(label="Nivel Educativo", placeholder="Opcional") | |
| nivel_economico = gr.Textbox(label="Nivel Socioeconómico", placeholder="Opcional") | |
| # COLUMNA 2: Telemetría y Notas | |
| with gr.Column(): | |
| gr.Markdown("### 📚 Historial Académico") | |
| intentos_previos = gr.Slider(minimum=0, maximum=5, step=1, label="Intentos Previos", value=0) | |
| creditos = gr.Slider(minimum=30, maximum=300, step=30, label="Créditos Matriculados", value=60) | |
| gr.Markdown("### 🖱️ Telemetría (Primeros 45 días)") | |
| clics = gr.Number(label="Total de Clics en el Campus", value=120) | |
| entregas = gr.Slider(minimum=0, maximum=3, step=1, label="Evaluaciones Entregadas", value=2) | |
| nota = gr.Slider(minimum=0, maximum=100, step=1, label="Nota Media Provisional", value=65) | |
| asistencia = gr.Slider(minimum=0, maximum=30, step=1, label="Días de Asistencia en el Mes", value=12) | |
| btn_predecir = gr.Button("🔍 Analizar Riesgo", variant="primary") | |
| with gr.Row(): | |
| # Quitamos el text_color="red" para evitar el TypeError en Gradio 6.0 | |
| resultado_estado = gr.Textbox(label="Estado de Alerta") | |
| resultado_accion = gr.Textbox(label="Acción Recomendada") | |
| btn_predecir.click( | |
| fn=predecir_abandono, | |
| inputs=[genero, region, nivel_educativo, nivel_economico, rango_edad, | |
| intentos_previos, creditos, discapacidad, | |
| clics, entregas, nota, asistencia], | |
| outputs=[resultado_estado, resultado_accion] | |
| ) | |
| # 4. Lanzar el servidor | |
| if __name__ == "__main__": | |
| # Pasamos el tema directamente a la función de lanzamiento | |
| demo.launch(share=True, theme=gr.themes.Soft()) |