CoolFace
Apppublic

mobixconsulting/eatc-class4

sourceHugging Faceunknownupdated 1y agoView on Hugging Face
0likes
app.py165 linesDownload Raw Back to root
1from fastapi import FastAPI, Query, HTTPException2import csv3import unicodedata4from typing import Dict5 6# ==============================7# CONFIGURACIÓN DE CLASIFICADORES8# ==============================9 10CLASIFICADORES = {11    "abaco": {12        "csv": "asociaciones_abaco.csv",13        "categoria_tipo": {14            'Sin Categoria': 'Sin Categoria',15            'Otros No Alimentos': 'other',16            'Alimentos de hoteles, restaurantes o casinos': 'food',17            'Juguetes': 'other',18            'Muebles': 'other',19            'Pequeño Aparato': 'other',20            'Textiles': 'other',21            'Bebidas Alcohólicas': 'food',22            'Dulces y Postres': 'food',23            'Papelería': 'other',24            'Bebidas Azucaradas': 'food',25            'Bebidas Azúcaradas': 'food',26            'Carnes': 'food',27            'Panadería de sal': 'food',28            'Materiales de construcción': 'other',29            'Hogar': 'other',30            'Otras bebidas': 'food',31            'Grasas tipo 3 (saturadas)': 'food',32            'Otros Alimentos': 'food',33            'Cereales': 'food',34            'Frutas': 'food',35            'Personal': 'other',36            'Gama Blanca': 'other',37            'Gama Marron': 'other',38            'Frutos secos y semillas': 'food',39            'Paquetes/snacks': 'food',40            'Agua': 'food',41            'Productos lácteos grasa entera': 'food',42            'Dulces y postres': 'food',43            'Otras fórmulas especiales': 'food',44            'Leches Enteras': 'food',45            'Fórmulas infantiles': 'food',46            'Leguminosas Secas': 'food',47            'Tuberculos': 'food',48            'Raíz': 'food',49            'Plátano': 'food',50            'Verduras': 'food',51            'Panadería dulce': 'food',52            'Huevos': 'food',53            'Azúcares Simples': 'food',54            'Medicamentos sin fórmula médica': 'other',55            'Suplementos nutricionales': 'food',56            'Cereales ': 'food',57            'Alimentos para Mascotas': 'other',58            'Grasas tipo 2 (poliinsaturadas)': 'food',59            'Grasas tipo 1 (monoinsaturadas)': 'food'60        }61    },62    "mexico": {63        "csv": "asociaciones_bamx.csv",64        "categoria_tipo": {65            'No Comestible': 'other',66            'Fruta y verdura': 'food',67            'Pan': 'food',68            'Cereales y Leguminosas': 'food',69            'Bebidas Saborizadas': 'food',70            'Azucares': 'food',71            'Abarrotes': 'food',72            'Proteina animal': 'food',73            'Alimento Preparado': 'food',74            'Refrigerados y Congelados': 'food',75            'Lactéos': 'food',76            'Agua': 'food',77            'Jugo y Néctar': 'food',78            'Leguminosa': 'food',79            'Grasas Animales': 'food',80            'Confiteria': 'food',81            'Suplementos': 'food',82            'Salsas': 'food',83            'Café y Té': 'food',84            'Sabores listos para comer': 'food',85            'Aceites Vegetales': 'food',86            'Raices, Tuberculos': 'food',87            'Semillas y Nueces': 'food',88            'Productos veganos': 'food'89        }90    }91}92 93# ==============================94# FUNCIONES DE PROCESAMIENTO95# ==============================96 97def quitar_tildes(texto: str) -> str:98    """Normaliza texto removiendo acentos y caracteres especiales"""99    return unicodedata.normalize('NFD', texto).encode('ascii', 'ignore').decode('utf-8').lower()100 101def cargar_asociaciones(ruta_csv: str) -> Dict[str, str]:102    """Carga y procesa las asociaciones desde un CSV clave-valor"""103    try:104        with open(ruta_csv, mode='r', encoding='utf-8') as archivo:105            lector = csv.reader(archivo)106            next(lector)  # Saltar cabecera107            return {quitar_tildes(fila[0]): fila[1] for fila in lector}108    except Exception as e:109        raise RuntimeError(f"Error cargando {ruta_csv}: {str(e)}")110 111# ==============================112# INICIALIZACIÓN DE LA APLICACIÓN113# ==============================114 115app = FastAPI()116clasificadores_cargados = {}117 118@app.on_event("startup")119async def inicializar_clasificadores():120    """Carga las asociaciones al iniciar la aplicación"""121    for nombre, config in CLASIFICADORES.items():122        try:123            clasificadores_cargados[nombre] = {124                "asociaciones": cargar_asociaciones(config["csv"]),125                "categoria_tipo": config["categoria_tipo"]126            }127            print(f"✅ Clasificador {nombre} cargado correctamente")128        except Exception as e:129            print(f"❌ Error inicializando {nombre}: {str(e)}")130            raise131 132# ==============================133# ENDPOINT PRINCIPAL134# ==============================135 136@app.get("/categorize")137def categorizar_producto(138    cua_master: str = Query(..., description="Selección de clasificador (abaco/mexico)"),139    eatc_typology: str = Query(..., description="Valor de typology a clasificar")140):141    # Validar clasificador142    cua_master = cua_master.lower()143    if cua_master not in clasificadores_cargados:144        raise HTTPException(145            status_code=400,146            detail=f"Clasificador no válido. Opciones: {', '.join(CLASIFICADORES.keys())}"147        )148 149    # Obtener configuración del clasificador150    config = clasificadores_cargados[cua_master]151    asociaciones = config["asociaciones"]152    mapeo_tipos = config["categoria_tipo"]153 154    # Procesar entrada155    typology_limpio = quitar_tildes(eatc_typology)156    categoria = asociaciones.get(typology_limpio, "Sin Categoria")157 158    # Mapear a tipo general159    tipo = mapeo_tipos.get(categoria, "Sin Categoria")160 161    return {162        "eatc-odd_typology_b": categoria,163        "eatc-odd_typology_a": tipo164    }165