# En: app/app.py import gradio as gr import requests # Para llamar a nuestra propia API de FastAPI import os # --- 1. Importa tu App de FastAPI --- # (Asegúrate de que api/main.py exista en la carpeta 'api') from api.main import app as fastapi_app # --- 2. Define la URL de tu API --- # Esto es CLAVE para que funcione en Hugging Face Spaces # Busca la URL del Space y, si no la encuentra, usa la local. BASE_URL = os.getenv("SPACE_URL", "http://127.0.0.1:7860") API_PREDICT_URL = f"{BASE_URL}/api/predict" API_COACH_URL = f"{BASE_URL}/api/coach" # --- 3. Lógica de la Interfaz Gradio --- # Esta función es el "cerebro" de la UI. # Llama a los endpoints FALSOS de FastAPI. def chatbot_response(chat_message, chat_history, edad, sexo, asistencia, notas): """ Función que Gradio ChatInterface llamará. Se comunica con la API (FastAPI) para obtener respuestas. """ # --- Paso A: Llamar a /predict --- predict_payload = { "edad": edad, "sexo": sexo, "asistencia": asistencia, "notas": notas } try: # Llama al endpoint /predict de tu API response_predict = requests.post(API_PREDICT_URL, json=predict_payload) response_predict.raise_for_status() # Lanza un error si la API falla predict_data = response_predict.json() score = predict_data.get("score", 0.0) except requests.exceptions.RequestException as e: yield f"Error al conectar con el motor de riesgo (/predict): {e}" return # --- Paso B: Llamar a /coach --- coach_payload = { "consulta": chat_message, "riesgo": score } try: # Llama al endpoint /coach de tu API response_coach = requests.post(API_COACH_URL, json=coach_payload) response_coach.raise_for_status() coach_data = response_coach.json() # Formatear la respuesta del coach para el chat plan_texto = coach_data.get("plan", "No se pudo generar un plan.") citas = coach_data.get("citas", []) # Esta es la respuesta final que ve el usuario respuesta_final = f"**Riesgo Estimado: {score*100:.0f}%**\n\n{plan_texto}" if citas: respuesta_final += "\n\n**Fuentes (Mock):**\n" for cita in citas: respuesta_final += f"- `{cita}`\n" yield respuesta_final except requests.exceptions.RequestException as e: yield f"Error al conectar con el Coach RAG (/coach): {e}" # --- 4. Definición de la UI de Gradio --- with gr.Blocks(theme=gr.themes.Soft(), title="Tutor Virtual") as demo: gr.Markdown("# 🤖 Tutor Virtual Adaptativo (Demo)") gr.Markdown("Esta demo usa un backend **simulado (mock)** para pruebas.") with gr.Row(): # --- Columna 1: El "Formulario" (Sidebar) --- with gr.Column(scale=1, min_width=350): with gr.Accordion("Perfil del Alumno", open=True): gr.Markdown("Ingrese los datos del alumno para la simulación.") input_edad = gr.Slider(10, 25, value=18, label="Edad") input_sexo = gr.Radio(["Masculino", "Femenino", "Otro"], value="Masculino", label="Sexo") input_asistencia = gr.Slider(0, 100, value=80, label="Asistencia (%)") input_notas = gr.Slider(1.0, 7.0, step=0.1, value=4.5, label="Promedio Notas") gr.Markdown("*(Nota: El puntaje de riesgo cambiará si las notas son < 4.0)*") # --- Columna 2: El "Chat" (Área Principal) --- # --- Columna 2: El "Chat" (Área Principal) --- with gr.Column(scale=4): gr.ChatInterface( fn=chatbot_response, type="messages", # <--- 1. AÑADE ESTO (para el Warning) chatbot=gr.Chatbot( height=500, label="Chat con Tutor", avatar_images=("user.png", "bot.png"), type='messages' ), textbox=gr.Textbox(placeholder="Hola, ¿en qué puedo ayudarte hoy?"), submit_btn="Enviar Consulta", additional_inputs=[input_edad, input_sexo, input_asistencia, input_notas] ) # ... (más abajo) ... # --- 5. Montar y Lanzar (La Magia) --- # ¡Esta es la sintaxis correcta para Gradio 4.0+! # Vuelve a usar 'gr.mount_app' app = gr.mount_app(demo, fastapi_app, path="/api") # NOTA: No uses demo.launch(). # Hugging Face usará la variable 'app' para lanzar el se