import gradio as gr import requests import io from PIL import Image import re import base64 # URL interna de la API API_URL = "http://127.0.0.1:8000" # --- Imagenes --- def get_base64_image(image_path): try: with open(image_path, "rb") as img_file: return base64.b64encode(img_file.read()).decode('utf-8') except Exception: return "" nombre_archivo = "protection-environment-robot-holding-lightbulb-with-recycle-icon-sustainable-and-nature_10461459.jpg!sw800" img_base64 = get_base64_image(nombre_archivo) robot_html = f"" # --- Estilos --- custom_css = """ #titulo-proyecto h1, #respuesta-agente h2 { font-family: 'Charter', 'Bitstream Charter', 'Cambria', 'Georgia', serif !important; font-weight: 700 !important; letter-spacing: -0.5px !important; color: #F3F4F6 !important; /* El color blanco hueso que elegiste */ } #respuesta-agente p { font-family: 'Charter', 'Georgia', serif !important; font-size: 1.1em; } #btn-actualizar { background: #2D5A27 !important; color: white !important; border: none !important; } #btn-actualizar:hover { background: #3e7a36 !important; } """ # --- FUNCIONES --- def registrar_usuario(new_user, new_pass): if not new_user or not new_pass: return " Por favor, rellena ambos campos.", gr.update() try: data = {"username": new_user, "password": new_pass} response = requests.post(f"{API_URL}/registrar", data=data) if response.ok: return f" Usuario '{new_user}' registrado. ¡Inicia sesión!", gr.Tabs(selected=1) error_msg = response.json().get('detail', 'No se pudo registrar') return f" Error: {error_msg}", gr.update() except Exception as e: return f" Error de conexión: {str(e)}", gr.update() def login_usuario(username, password): if not username or not password: return None, " Introduce tus credenciales.", gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update() try: login_data = {"username": username, "password": password} res = requests.post(f"{API_URL}/login", data=login_data) if res.ok: token = res.json().get("access_token") user_txt = f" **Usuario:** {username}" return token, f" Hola {username}", gr.Tabs(selected=2), user_txt, user_txt, user_txt, user_txt, gr.update(visible=False), gr.update(visible=True), " Preparado para analizar imágenes" error_msg = res.json().get('detail', 'Error al iniciar sesión') return None, f"⚠️ {error_msg}", gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update() except Exception as e: return None, f" Error: {str(e)}", gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update() def analizar_foto(token, imagen): if not token: return " Debes iniciar sesión primero.", None, gr.Tabs(selected=1) if imagen is None: return " Por favor, sube una foto.", None, gr.update() try: buf = io.BytesIO() imagen.save(buf, format="JPEG") buf.seek(0) headers = {"Authorization": f"Bearer {token}"} files = {"file": ("image.jpg", buf, "image/jpeg")} res = requests.post(f"{API_URL}/detectar-visual", headers=headers, files=files) if res.ok: msg_crudo = res.headers.get("X-Agent-Reply", "Sin respuesta") det = res.headers.get("X-Detection", "Desconocido") msg_formateado = msg_crudo.replace("|", "\n\n") msg_formateado = re.sub(r' +', ' ', msg_formateado).strip() img_res = Image.open(io.BytesIO(res.content)) return f"## {robot_html} ReciclA Dice:\n\n{msg_formateado}\n\n**Objeto:** {det}", img_res, gr.update() error_msg = res.json().get('detail', 'Error al analizar la imagen') return f"### ⚠️ Aviso\n{error_msg}", None, gr.update() except Exception as e: return f" Error: {str(e)}", None, gr.update() def ver_historial(token): if not token: return " Inicia sesión primero.", gr.Tabs(selected=1) try: headers = {"Authorization": f"Bearer {token}"} res = requests.get(f"{API_URL}/historial", headers=headers) if res.ok: h = res.json() if not h: return "Aún no tienes historial.", gr.update() texto = "### Tu historial de reciclaje:\n" for item in h: fecha = item.get('fecha', 'Sin fecha')[:10] resp = item.get('respuesta_agente', 'Sin respuesta') texto += f"**{fecha}**:\n> {robot_html} {resp}\n\n--- \n" return texto, gr.update() return f" Error: {res.text}", gr.update() except Exception as e: return f" Error: {str(e)}", gr.update() def logout_usuario(): no_user = " **Usuario:** No identificado" return None, "Sesión cerrada.", gr.Tabs(selected=1), no_user, no_user, no_user, no_user, gr.update(visible=True), gr.update(visible=False) def update_usuario(token, nuevo_nombre): no_user = " **Usuario:** No identificado" if not token or not nuevo_nombre: return token, " Error: Datos incompletos", gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update() try: headers = {"Authorization": f"Bearer {token}"} nuevo_nombre = nuevo_nombre.strip() res = requests.put(f"{API_URL}/usuarios/actualizarUsuario?nuevo_username={nuevo_nombre}", headers=headers) if res.ok: mensaje_exito = f" Nombre cambiado a '{nuevo_nombre}'. Reinicia sesión por seguridad." return None, mensaje_exito, gr.Tabs(selected=1), no_user, no_user, no_user, no_user, gr.update(visible=True), gr.update(visible=False) error_api = res.json().get('detail', 'Error desconocido') return token, f" Error: {error_api}", gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update() except Exception as e: return token, f" Error de conexion: {str(e)}", gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update() def vaciar_historial_usuario(token): if not token: return " Inicia sesión primero." headers = {"Authorization": f"Bearer {token}"} res = requests.delete(f"{API_URL}/historial", headers=headers) return " Historial vaciado correctamente." if res.ok else f" Error: {res.text}" # --- INTERFAZ --- with gr.Blocks(title="ReciclA", css=custom_css) as demo: token_state = gr.State() gr.Markdown(f"# {robot_html} ReciclA : Tu Asistente Inteligente de Reciclaje", elem_id="titulo-proyecto") with gr.Tabs() as main_tabs: # PESTAÑA 0: REGISTRO with gr.TabItem("📝 Registro", id=0) as tab_registro: user_info_0 = gr.Markdown(" **Usuario:** No identificado") gr.Markdown("---") reg_user = gr.Textbox(label="Usuario") reg_pass = gr.Textbox(label="Contraseña", type="password") reg_btn = gr.Button("Registrarme") reg_out = gr.Markdown() # PESTAÑA 4: PERFIL with gr.TabItem("👤 Mi Perfil", id=4, visible=False) as tab_perfil: user_info_p = gr.Markdown(" **Usuario:** No identificado") with gr.Group(): gr.Markdown("### Configuración de Perfil") nuevo_nombre_input = gr.Textbox(label="Nuevo nombre de usuario", placeholder="Escribe tu nuevo nombre aquí...") btn_cambiar_nombre = gr.Button("Actualizar Nombre", variant="primary", elem_id="btn-actualizar") gr.Markdown("
Por seguridad, se cerrará la sesión tras el cambio.
") logout_btn = gr.Button("Cerrar Sesión", variant="stop") # PESTAÑA 1: LOGIN with gr.TabItem("🔐 Login", id=1): user_info_1 = gr.Markdown(" **Usuario:** No identificado") gr.Markdown("---") l_user = gr.Textbox(label="Usuario") l_pass = gr.Textbox(label="Contraseña", type="password") with gr.Row(): l_btn = gr.Button("Iniciar Sesión", variant="primary") l_status = gr.Markdown(visible=False) # PESTAÑA 2: ANALISIS with gr.TabItem("🔍 Análisis", id=2): user_info_2 = gr.Markdown(" **Usuario:** No identificado") gr.Markdown("---") img_input = gr.Image(type="pil", show_label=False) btn_scan = gr.Button("Analizar", variant="primary") txt_output = gr.Markdown("Inicia sesión para poder analizar tus imagenes", elem_id="respuesta-agente") img_output = gr.Image(show_label=False) # PESTAÑA 3: HISTORIAL with gr.TabItem("📜 Historial", id=3): user_info_3 = gr.Markdown(" **Usuario:** No identificado") gr.Markdown("---") with gr.Row(): btn_hist = gr.Button(" Cargar mi Historial", variant="primary") btn_vaciar = gr.Button(" Vaciar Historial", variant="stop") out_hist = gr.Markdown("Dale a 'Cargar' para ver tus movimientos.") # --- Botones --- reg_btn.click(registrar_usuario, [reg_user, reg_pass], [reg_out, main_tabs]) l_btn.click( login_usuario, [l_user, l_pass], [token_state, l_status, main_tabs, user_info_0, user_info_1, user_info_2, user_info_3, tab_registro, tab_perfil] ) logout_btn.click( logout_usuario, None, [token_state, l_status, main_tabs, user_info_0, user_info_1, user_info_2, user_info_3, tab_registro, tab_perfil] ) btn_scan.click(analizar_foto, [token_state, img_input], [txt_output, img_output, main_tabs]) btn_hist.click(ver_historial, [token_state], [out_hist, main_tabs]) btn_vaciar.click(vaciar_historial_usuario, [token_state], [out_hist]) btn_cambiar_nombre.click( fn=update_usuario, inputs=[token_state, nuevo_nombre_input], outputs=[token_state, l_status, main_tabs, user_info_0, user_info_1, user_info_2, user_info_3, tab_registro, tab_perfil] ) if __name__ == "__main__": demo.launch( server_name="0.0.0.0", server_port=7860, theme=gr.themes.Soft(), favicon_path="favicon.png", allowed_paths=["/app"] )