Spaces:
Runtime error
Runtime error
| """ | |
| Clasificador ONNX para personajes Sanrio. | |
| SanrioClassifier: | |
| - Carga modelo ONNX INT8 (11.4 MB) en CPU con onnxruntime | |
| - Preprocesa imagen: resize a 224x224, normalización ImageNet | |
| - Softmax manual para obtener probabilidades calibradas | |
| - Top-3 con nombres human-readable desde NOMBRES_MOSTRAR | |
| - Threshold de confianza: <50% → mensaje "no parece Sanrio" | |
| - 30 clases mapeadas desde clases_sanrio.json | |
| Uso: | |
| from app.model import clasificador | |
| clasificador.cargar() | |
| resultado = clasificador.predecir(tensor, threshold=0.50) | |
| """ | |
| import json | |
| import os | |
| import numpy as np | |
| import onnxruntime as ort | |
| from app.config import MODELS_DIR, CLASES_JSON, MODELO_ONNX | |
| # Nombres para mostrar (human-readable) | |
| # Misma clave que en clases_sanrio.json para mapping consistente | |
| NOMBRES_MOSTRAR = { | |
| "badtz_maru": "Badtz-Maru", | |
| "chococat": "Chococat", | |
| "cinnamon": "Cinnamoroll", | |
| "hello_kitty": "Hello Kitty", | |
| "keroppi": "Keroppi", | |
| "kuromi": "Kuromi", | |
| "my_melody": "My Melody", | |
| "pochacco": "Pochacco", | |
| "pompompurin": "Pompompurin", | |
| "tuxedo_sam": "Tuxedo Sam", | |
| "pekkle": "Pekkle", | |
| "hangyodon": "Hangyodon", | |
| "little_twin_stars": "Little Twin Stars", | |
| "cogimyun": "Cogimyun", | |
| "my_sweet_piano": "My Sweet Piano", | |
| "hanamaruobake": "Hanamaruobake", | |
| "wish_me_mell": "Wish Me Mell", | |
| "usahana": "Usahana", | |
| "gaopowerroo": "Gaopowerroo", | |
| "kuririn": "Corocorokuririn", | |
| "gudetama": "Gudetama", | |
| "aggretsuko": "Aggretsuko", | |
| "kirimichan": "Kirimichan", | |
| "marroncream": "Marroncream", | |
| "marumofubiyori": "Marumofubiyori", | |
| "charmmykitty": "Charmmy Kitty", | |
| "dear_daniel": "Dear Daniel", | |
| "sugarbunnies": "Sugarbunnies", | |
| "yoshikitty": "Yoshikitty", | |
| "hello_mimmy": "Hello Mimmy", | |
| } | |
| class SanrioClassifier: | |
| def __init__(self): | |
| self.session = None | |
| self.clases = [] | |
| self.input_name = None | |
| self.cargado = False | |
| def cargar(self): | |
| if not os.path.exists(MODELO_ONNX): | |
| return False | |
| if not os.path.exists(CLASES_JSON): | |
| return False | |
| with open(CLASES_JSON, 'r') as f: | |
| data = json.load(f) | |
| self.clases = data if isinstance(data, list) else data['classes'] | |
| self.session = ort.InferenceSession( | |
| MODELO_ONNX, | |
| providers=['CPUExecutionProvider'] | |
| ) | |
| self.input_name = self.session.get_inputs()[0].name | |
| self.cargado = True | |
| return True | |
| def predecir(self, input_tensor: np.ndarray, threshold: float = 0.50): | |
| if not self.cargado: | |
| raise RuntimeError("Modelo no cargado") | |
| outputs = self.session.run(None, {self.input_name: input_tensor.astype(np.float32)})[0] | |
| exp = np.exp(outputs - outputs.max(axis=1, keepdims=True)) | |
| probs = exp / exp.sum(axis=1, keepdims=True) | |
| probs = probs[0] | |
| idxs = np.argsort(probs)[::-1] | |
| top3 = [] | |
| for i in idxs[:3]: | |
| clase = self.clases[i] | |
| top3.append({ | |
| 'clase': clase, | |
| 'nombre_mostrar': NOMBRES_MOSTRAR.get(clase, clase), | |
| 'confianza': round(float(probs[i] * 100), 2), | |
| }) | |
| mejor = top3[0] | |
| if mejor['confianza'] < threshold * 100: | |
| return { | |
| 'exito': True, | |
| 'prediccion': None, | |
| 'confianza': None, | |
| 'top_3': top3, | |
| 'mensaje': "No parece un personaje Sanrio conocido, o no estoy segura de cuál es.", | |
| } | |
| gap = mejor['confianza'] - top3[1]['confianza'] | |
| if gap < 10.0: | |
| return { | |
| 'exito': True, | |
| 'prediccion': None, | |
| 'confianza': None, | |
| 'top_3': top3, | |
| 'mensaje': "No parece un personaje Sanrio conocido, o no estoy segura de cuál es.", | |
| } | |
| return { | |
| 'exito': True, | |
| 'prediccion': mejor['clase'], | |
| 'nombre_mostrar': mejor['nombre_mostrar'], | |
| 'confianza': mejor['confianza'], | |
| 'top_3': top3, | |
| 'mensaje': None, | |
| } | |
| clasificador = SanrioClassifier() | |