Spaces:
Sleeping
Sleeping
| # src/expon/ml/text_embed.py | |
| from __future__ import annotations | |
| import re | |
| import numpy as np | |
| class TextEncoder: | |
| """ | |
| Encoder de texto super liviano basado en keywords. | |
| Produce una distribuci贸n de probabilidad sobre las clases. | |
| """ | |
| # Orden de clases (隆mantener igual en todo el proyecto!) | |
| labels = ["entusiasta", "neutra", "confiada", "ansiosa", "motivada", "nerviosa"] | |
| # Palabras/claves simples por clase (ajustables) | |
| _lexicon = { | |
| "entusiasta": [ | |
| r"emocionad[oa]s?", r"entusias[mt]o?", r"content[oa]s?", | |
| r"alegr[ia]", r"feliz", r"genial", r"fant[a谩]stic[oa]", r"encantad[oa]" | |
| ], | |
| "neutra": [ | |
| r"present(a|are)mos", r"metodolog[i铆]a", r"resultados?", r"conclusi[o贸]n", | |
| r"validaci[o贸]n", r"an[a谩]lisis", r"datos?", r"grupo?s?" | |
| ], | |
| "confiada": [ | |
| r"segur[oa]", r"claro", r"convencid[oa]", r"garantiz[ao]?", r"confirm(a|an|amos)", | |
| r"demostr(a|amos|ado)", r"solidez", r"certeza" | |
| ], | |
| "ansiosa": [ | |
| r"preocupad[oa]s?", r"ansios[oa]s?", r"inquiet[oa]s?", r"dud[ao]?", | |
| r"nervios?", r"temor", r"incertidumbre", r"estresad[oa]" | |
| ], | |
| "motivada": [ | |
| r"motivad[oa]s?", r"impuls[oa]?", r"seguir trabajando", r"inspirad[oa]", | |
| r"proactividad", r"superaci[o贸]n", r"lograr", r"objetiv[oa]s?" | |
| ], | |
| "nerviosa": [ | |
| r"nervios[oa]s?", r"tensi[o贸]n", r"temblor", r"titube[oa]?", r"dificultad para", | |
| r"insegur[oa]", r"me puse", r"me siento mal" | |
| ], | |
| } | |
| def __init__(self) -> None: | |
| # Precompilar regex | |
| self._compiled = { | |
| k: [re.compile(pat, flags=re.IGNORECASE) for pat in arr] | |
| for k, arr in self._lexicon.items() | |
| } | |
| def _score_text(self, text: str) -> np.ndarray: | |
| """ | |
| Suma match de keywords por clase. Devuelve vector de scores raw (no normalizados). | |
| """ | |
| text = text or "" | |
| scores = [] | |
| for lab in self.labels: | |
| pats = self._compiled.get(lab, []) | |
| s = 0.0 | |
| for rgx in pats: | |
| for m in rgx.finditer(text): | |
| # peso por coincidencia (m谩s largo, un poco m谩s de score) | |
| span = m.end() - m.start() | |
| s += 1.0 + min(span / 10.0, 1.0) | |
| scores.append(s) | |
| return np.asarray(scores, dtype=float) | |
| def probs(self, text: str) -> np.ndarray: | |
| """ | |
| Devuelve una distribuci贸n [L] en el mismo orden que `labels`. | |
| Usa suavizado para evitar vectores nulos. | |
| """ | |
| raw = self._score_text(text) | |
| # Suavizado: prior uniforme peque帽o | |
| eps = 1e-3 | |
| raw = raw + eps | |
| s = raw.sum() | |
| if s <= 0: | |
| return np.full(len(self.labels), 1.0 / len(self.labels), dtype=float) | |
| return raw / s | |