c-armor's picture
Update app.py
16cf566 verified
Raw
History Blame Contribute Delete
4.48 kB
import gradio as gr
import re
import emoji
import spacy
import torch
from transformers import AutoModelForSequenceClassification, AutoTokenizer
from collections import Counter
# --- 1. CONFIGURACIÓN ---
MODEL_ID = "c-armor/finetuned_emotions"
DEVICE = "cpu" # Usamos CPU
EMOTION_LABELS = ["alegria", "tristeza", "ira", "miedo", "sorpresa", "asco"]
UMBRALES = {
"alegria": 0.50,
"tristeza": 0.50,
"ira": 0.50,
"miedo": 0.30,
"sorpresa": 0.30,
"asco": 0.30 # <--- Coincide con entrenamiento
}
# --- 2. CARGAR MODELOS (Se cargan UNA VEZ al iniciar el Space) ---
print("Cargando modelo spaCy...")
NLP = spacy.load("es_core_news_md")
STOP_WORDS = NLP.Defaults.stop_words
print("spaCy cargado y STOP_WORDS listas")
print(f"Cargando modelo BETO desde {MODEL_ID}...")
TOKENIZER = AutoTokenizer.from_pretrained("dccuchile/bert-base-spanish-wwm-cased", use_fast=False)
MODEL = AutoModelForSequenceClassification.from_pretrained(MODEL_ID)
MODEL.to(DEVICE)
MODEL.eval()
print(f"BETO cargado exitosamente en {DEVICE}")
# --- 3. FUNCIONES DE PREPROCESAMIENTO---
def preprocesar_texto(texto: str) -> str:
if not isinstance(texto, str): return ""
texto = texto.lower()
texto = emoji.demojize(texto, language="es")
texto = re.sub(r"https://?://\S+|www\.\S+", "", texto)
texto = re.sub(r"[^a-záéíóúüñ_.,!?¿¡]", " ", texto)
texto = re.sub(r"\s{2,}", " ", texto).strip()
return texto
def lematizar_texto_para_lista(texto: str):
"""Lematiza el texto y devuelve una LISTA (para nube de palabras)"""
with NLP.disable_pipes("parser", "ner"):
doc = NLP(texto)
return [token.lemma_ for token in doc if token.text.strip()]
# --- 4. FUNCIÓN API 1: ANÁLISIS DE EMOCIONES ---
def analizar_emociones(texto: str):
if not texto or not isinstance(texto, str) or len(texto.strip()) < 3:
return {"error": "texto_invalido"}
try:
texto_limpio = preprocesar_texto(texto)
# Pasamos directo el texto_limpio al tokenizer
inputs = TOKENIZER(texto_limpio, padding=True, truncation=True, max_length=128, return_tensors="pt").to(DEVICE)
with torch.no_grad():
outputs = MODEL(**inputs)
logits = outputs.logits
probabilidades = torch.sigmoid(logits).cpu().numpy()[0]
emociones_detectadas = []
probabilidades_dict = {}
for i, emocion in enumerate(EMOTION_LABELS):
prob = float(probabilidades[i])
umbral = UMBRALES[emocion]
probabilidades_dict[emocion] = round(prob, 4)
if prob >= umbral:
emociones_detectadas.append(emocion)
if not emociones_detectadas:
emociones_detectadas = ["neutro"]
return {"emociones": emociones_detectadas, "probabilidades": probabilidades_dict}
except Exception as e:
print(f"Error en predicción de emociones: {e}")
return {"error": "error_prediccion"}
# --- 5. FUNCIÓN API 2: FRECUENCIA DE PALABRAS ---
def generar_frecuencia_palabras(texto: str):
"""Calcula las 50 palabras más frecuentes (devuelve una lista de listas)"""
if not texto or not isinstance(texto, str) or not texto.strip():
return []
try:
lemmas = lematizar_texto_para_lista(preprocesar_texto(texto))
# Usa las STOP_WORDS globales
important_words = [lem for lem in lemmas if lem not in STOP_WORDS and lem.isalpha() and len(lem) > 2]
word_counts = Counter(important_words)
# Devuelve el formato que tu frontend espera (lista de [palabra, conteo])
return word_counts.most_common(50)
except Exception as e:
print(f"Error en frecuencia de palabras: {e}")
return []
# --- 6. LANZAR AMBAS APIS USANDO GR.BLOCKS ---
with gr.Blocks() as demo:
# --- Interfaz/API para Emociones ---
with gr.Tab("Análisis de Emociones"):
gr.Interface(
fn=analizar_emociones,
inputs=gr.Textbox(lines=5, label="Texto a Analizar"),
outputs="json",
api_name="predict_emotions" # <-- API endpoint 1
)
# --- Interfaz/API para Frecuencia de Palabras ---
with gr.Tab("Frecuencia de Palabras"):
gr.Interface(
fn=generar_frecuencia_palabras,
inputs=gr.Textbox(lines=5, label="Texto completo"),
outputs="json",
api_name="predict_frequency" # <-- API endpoint 2
)
demo.launch()