Download app.py from yoyplay/ProyectoFinalDockerObservabilidad: direct link, hf CLI and curl.
- Browser
- Download file 3.51 kB
-
https://huggingface.co/spaces/yoyplay/ProyectoFinalDockerObservabilidad/resolve/main/app.py
- Command line
-
hf download hf://spaces/yoyplay/ProyectoFinalDockerObservabilidad/app.py
-
curl -L -o app.py https://huggingface.co/spaces/yoyplay/ProyectoFinalDockerObservabilidad/resolve/main/app.py
3.51 kB
| from fastapi import FastAPI, HTTPException | |
| from pydantic import BaseModel | |
| from transformers import pipeline | |
| import time | |
| import logging | |
| import torch | |
| # 1. CONFIGURACIÓN DE LOGGING (Observabilidad: Logs) | |
| # Esto permite que los mensajes aparezcan en la consola de Hugging Face | |
| logging.basicConfig( | |
| level=logging.INFO, | |
| format="%(asctime)s [%(levelname)s] %(message)s", | |
| handlers=[logging.StreamHandler()] | |
| ) | |
| logger = logging.getLogger(__name__) | |
| # 2. MÉTRICAS EN MEMORIA (Observabilidad: Métricas) | |
| # Diccionario para rastrear el uso de la API sin base de datos | |
| METRICAS = { | |
| "total_predicciones": 0, | |
| "errores": 0, | |
| "inicio_sistema": time.time() | |
| } | |
| # Estructuras de Pydantic | |
| class EntradaTexto(BaseModel): | |
| texto: str | |
| class Prediccion(BaseModel): | |
| sentimiento: str | |
| confianza: str | |
| tiempo_ms: float | |
| texto: str | |
| contador: int # Nueva métrica para el cliente | |
| app = FastAPI(title="MercaLatam Sentiment Analysis - Observable", version="2.0.0") | |
| # 3. CARGA ROBUSTA DEL MODELO | |
| logger.info("Iniciando carga del modelo DistilBERT de MercaLatam...") | |
| try: | |
| classifier = pipeline( | |
| "sentiment-analysis", | |
| model="./saved_model", | |
| tokenizer="./saved_model", | |
| device=-1 # Forzamos CPU para el entorno Space | |
| ) | |
| logger.info("✅ Modelo cargado exitosamente y listo para inferencia.") | |
| except Exception as e: | |
| logger.error(f"❌ Error crítico al cargar el modelo: {e}") | |
| classifier = None | |
| def health(): | |
| """Endpoint de salud mejorado con métricas de observabilidad""" | |
| uptime = round(time.time() - METRICAS["inicio_sistema"], 2) | |
| return { | |
| "status": "ok" if classifier else "error", | |
| "uptime_segundos": uptime, | |
| "predicciones_totales": METRICAS["total_predicciones"], | |
| "errores_registrados": METRICAS["errores"], | |
| "proyecto": "MercaLatam" | |
| } | |
| def predecir(entrada: EntradaTexto): | |
| METRICAS["total_predicciones"] += 1 | |
| # Validación con log de advertencia | |
| if not entrada.texto.strip(): | |
| METRICAS["errores"] += 1 | |
| logger.warning("Petición recibida con texto vacío.") | |
| raise HTTPException(status_code=400, detail="Texto vacío") | |
| if classifier is None: | |
| METRICAS["errores"] += 1 | |
| logger.error("Intento de predicción sin modelo cargado.") | |
| raise HTTPException(status_code=503, detail="Modelo no disponible") | |
| try: | |
| inicio = time.time() | |
| # Inferencia | |
| res = classifier(entrada.texto)[0] | |
| tiempo_ms = round((time.time() - inicio) * 1000, 2) | |
| # Mapeo según tu entrenamiento | |
| label_map = {"LABEL_0": "NEGATIVO 🚩", "LABEL_1": "POSITIVO ✅"} | |
| sentimiento = label_map.get(res['label'], res['label']) | |
| # Log de éxito (Audit trail) | |
| logger.info(f"Predicción #{METRICAS['total_predicciones']} | Sentimiento: {sentimiento} | Latencia: {tiempo_ms}ms") | |
| return Prediccion( | |
| sentimiento=sentimiento, | |
| confianza=f"{round(res['score'] * 100, 2)}%", | |
| tiempo_ms=tiempo_ms, | |
| texto=entrada.texto, | |
| contador=METRICAS["total_predicciones"] | |
| ) | |
| except Exception as e: | |
| METRICAS["errores"] += 1 | |
| logger.error(f"Error durante la inferencia para el texto '{entrada.texto[:20]}...': {e}") | |
| raise HTTPException(status_code=500, detail="Error interno procesando la solicitud") |