import math
import torch
from huggingface_hub import hf_hub_download
from transformers import AutoModelForCausalLM, AutoTokenizer
repo = "agusnieto77/qwen2.5-0.5b-conflict-classifier"
tok = AutoTokenizer.from_pretrained(repo)
model = AutoModelForCausalLM.from_pretrained(repo)
model.eval()
definition = open(
hf_hub_download(repo, "conflict_definition.md"), encoding="utf-8"
).read()
LABEL_IDS = {L: tok.encode(L, add_special_tokens=False)
for L in ("CONFLICTO", "NO_CONFLICTO")}
def clasificar(texto: str) -> tuple[str, float]:
system = (
"Eres un clasificador de notas periodísticas.\n\n"
"Tu tarea consiste exclusivamente en determinar si la nota contiene\n"
"un conflicto según la siguiente definición operacional:\n\n"
f"{definition}\n\n"
"Debes responder exclusivamente con una de estas dos etiquetas:\n\n"
"CONFLICTO\n"
"NO_CONFLICTO"
)
messages = [
{"role": "system", "content": system},
{"role": "user", "content": f"Clasifica la siguiente nota:\n\n{texto}"},
]
prompt = tok.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
prompt_ids = tok.encode(prompt, add_special_tokens=False)
seqs, labels = [], []
for L in ("CONFLICTO", "NO_CONFLICTO"):
seqs.append(prompt_ids + LABEL_IDS[L]); labels.append(L)
maxlen = max(len(s) for s in seqs)
input_ids = torch.full((2, maxlen), tok.pad_token_id, dtype=torch.long)
attn = torch.zeros((2, maxlen), dtype=torch.long)
for j, s in enumerate(seqs):
input_ids[j, maxlen - len(s):] = torch.tensor(s)
attn[j, maxlen - len(s):] = 1
keep = 6
with torch.no_grad():
logits = model(input_ids, attention_mask=attn, logits_to_keep=keep).logits
mean_lp = {}
for j, L in enumerate(labels):
llen = len(LABEL_IDS[L])
logp = torch.log_softmax(logits[j, keep - llen - 1:keep - 1], dim=-1)
toks = torch.tensor(LABEL_IDS[L])
mean_lp[L] = logp[torch.arange(llen), toks].mean().item()
p_c, p_n = math.exp(mean_lp["CONFLICTO"]), math.exp(mean_lp["NO_CONFLICTO"])
score = p_c / (p_c + p_n)
etiqueta = "CONFLICTO" if score >= 0.5 else "NO_CONFLICTO"
return etiqueta, score
texto_de_la_nota = (
"Los trabajadores del hospital municipal decidieron continuar con el paro "
"de actividades en reclamo de mejoras salariales. El gremio anunció una "
"movilización hacia la Municipalidad y rechazó la propuesta de aumento "
"del Ejecutivo."
)
etiqueta, score = clasificar(texto_de_la_nota)
print(f"{etiqueta} (score = {score:.3f})")