Spaces:
Running
Running
| """ | |
| Sentiment analyzer. | |
| - mode "light": lexicon-based sederhana (cepat, tanpa dependency berat) | |
| - mode "transformer": IndoBERT/RoBERTa (akurat, butuh torch + transformers) | |
| """ | |
| from typing import List, Dict | |
| from app.config import settings | |
| # Lexicon ringan Bahasa Indonesia (subset). Bisa diperluas. | |
| POSITIVE_WORDS = { | |
| "baik", "bagus", "hebat", "sukses", "untung", "naik", "tumbuh", "positif", | |
| "menang", "juara", "prestasi", "maju", "berhasil", "setuju", "dukung", | |
| "apresiasi", "optimis", "damai", "sehat", "aman", "puas", "senang", | |
| "bangga", "harapan", "solusi", "peluang", "inovasi", "manfaat", "efektif", | |
| } | |
| NEGATIVE_WORDS = { | |
| "buruk", "jelek", "gagal", "rugi", "turun", "anjlok", "negatif", "kalah", | |
| "krisis", "masalah", "korupsi", "tewas", "meninggal", "bencana", "konflik", | |
| "protes", "demo", "tolak", "kecam", "marah", "takut", "khawatir", "sakit", | |
| "bahaya", "ancaman", "kritik", "lemah", "lambat", "mahal", "sulit", "rusak", | |
| "kecewa", "tertekan", "korban", "darurat", | |
| } | |
| _pipeline = None | |
| def _load_transformer(): | |
| global _pipeline | |
| if _pipeline is None: | |
| from transformers import pipeline | |
| _pipeline = pipeline( | |
| "text-classification", | |
| model=settings.SENTIMENT_MODEL, | |
| truncation=True, | |
| max_length=512, | |
| ) | |
| return _pipeline | |
| def _normalize_label(label: str) -> str: | |
| low = label.lower() | |
| if "pos" in low: | |
| return "positive" | |
| if "neg" in low: | |
| return "negative" | |
| return "neutral" | |
| def analyze_light(text: str) -> Dict: | |
| tokens = [t.strip(".,!?;:\"'()[]").lower() for t in text.split()] | |
| pos = sum(1 for t in tokens if t in POSITIVE_WORDS) | |
| neg = sum(1 for t in tokens if t in NEGATIVE_WORDS) | |
| total = pos + neg | |
| if total == 0: | |
| return {"sentiment": "neutral", "score": 0.0, "confidence": 0.5} | |
| score = round((pos - neg) / total, 3) | |
| if score > 0.15: | |
| sentiment = "positive" | |
| elif score < -0.15: | |
| sentiment = "negative" | |
| else: | |
| sentiment = "neutral" | |
| confidence = round(min(1.0, total / 10), 3) | |
| return {"sentiment": sentiment, "score": score, "confidence": confidence} | |
| def analyze_transformer(texts: List[str]) -> List[Dict]: | |
| pipe = _load_transformer() | |
| outputs = pipe(texts) | |
| results = [] | |
| for out in outputs: | |
| label = _normalize_label(out["label"]) | |
| conf = round(float(out["score"]), 3) | |
| score = conf if label == "positive" else (-conf if label == "negative" else 0.0) | |
| results.append({"sentiment": label, "score": round(score, 3), "confidence": conf}) | |
| return results | |
| def analyze_batch(items: List) -> List[Dict]: | |
| if settings.MODEL_MODE == "transformer": | |
| try: | |
| texts = [it.text[:2000] for it in items] | |
| tf = analyze_transformer(texts) | |
| return [{"id": it.id, **r} for it, r in zip(items, tf)] | |
| except Exception: | |
| # Fallback ke light bila transformer gagal load | |
| pass | |
| return [{"id": it.id, **analyze_light(it.text)} for it in items] | |