"""
app.py — Identificador Caribicus warrenii (Hugging Face Spaces)
Versión para servidor: con login (usuario/contraseña vía secretos del Space)
y el modelo afinado. El cómputo ocurre en el Space, no en tu PC.
"""
import os
import pandas as pd
import gradio as gr
import caribicus_finetuned as cf
print("Cargando modelo afinado Caribicus...")
try:
cf._cargar_modelo()
BASE = cf.cargar_base()
U_CONF, U_DUD = cf.cargar_umbrales()
N = len(BASE)
OK = True
print(f"Base: {N} individuos | Umbrales: {U_CONF}/{U_DUD}")
except Exception as exc:
BASE = {}; N = 0; OK = False; ERR = str(exc); U_CONF, U_DUD = 65.0, 50.0
print("ADVERTENCIA:", exc)
COLOR = {'CONFIRMADO': '#27ae60', 'DUDOSO': '#e67e22', 'NUEVO': '#e74c3c'}
ICONO = {'CONFIRMADO': '✅', 'DUDOSO': '⚠️', 'NUEVO': '❌'}
ETIQ = {'CONFIRMADO': 'Confirmado',
'DUDOSO': 'Dudoso — requiere revisión manual',
'NUEVO': 'Nuevo individuo no registrado'}
def _barra(pct, color, alto=10):
return (f"
")
def _html_resultado(estado, c1, p1, c2, p2):
color = COLOR[estado]
bloque2 = ""
if c2:
bloque2 = (f"SEGUNDO CANDIDATO
"
f""
f"{c2}{p2:.1f} %
"
f"{_barra(p2,'#95a5a6',7)}")
return (f""
f"
{ICONO[estado]} {ETIQ[estado]}
"
f"
"
f"
MEJOR CANDIDATO
"
f"
"
f"{c1}"
f"{p1:.1f} %
"
f"{_barra(p1,color)}{bloque2}
")
def predecir(imagen_path):
if imagen_path is None:
return "Sube una foto y presiona Identificar.
", None
if not OK:
return f"Error: {ERR}
", None
try:
emb = cf.foto_a_embedding(imagen_path, recortar=True)
ranking = cf.identificar_embedding(emb, BASE)
c1, p1 = ranking[0]
c2, p2 = ranking[1] if len(ranking) > 1 else (None, 0.0)
estado = cf.interpretar(p1, U_CONF, U_DUD)
df = pd.DataFrame(ranking, columns=['Individuo', 'Confianza (%)'])
df['Confianza (%)'] = df['Confianza (%)'].round(1)
return _html_resultado(estado, c1, p1, c2, p2), df
except Exception as exc:
return f"Error: {exc}
", None
_sub = (f"**{N} individuos** · modelo afinado + recorte automático · "
f"✅ ≥{U_CONF:.0f}% ⚠️ {U_DUD:.0f}–{U_CONF:.0f}% ❌ <{U_DUD:.0f}%"
if OK else "⚠️ Error al cargar el modelo/base.")
with gr.Blocks(title="Identificador Caribicus", theme=gr.themes.Soft()) as demo:
gr.Markdown("# Identificador de Individuos — *Caribicus warrenii*")
gr.Markdown(_sub)
with gr.Row():
with gr.Column(scale=1):
img_input = gr.Image(label="Foto a identificar", type="filepath", height=340)
btn = gr.Button("Identificar", variant="primary", size="lg")
with gr.Column(scale=1):
html_out = gr.HTML(value="Sube una foto y presiona Identificar.
")
tabla_out = gr.Dataframe(headers=["Individuo", "Confianza (%)"],
label="Ranking completo", interactive=False, wrap=False)
btn.click(fn=predecir, inputs=img_input, outputs=[html_out, tabla_out])
gr.Markdown("La foto se recorta automáticamente (quita el fondo) antes de identificar.")
# --- Login (usuario/contraseña desde los secretos del Space) ---
_USER = os.environ.get("APP_USER", "equipo")
_PASS = os.environ.get("APP_PASSWORD") # definido como secreto del Space
_auth = (_USER, _PASS) if _PASS else None
if __name__ == "__main__":
demo.launch(auth=_auth)