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("