line-webhook / sentiment.py
Therdpoom's picture
Upload 10 files
82eac1b verified
Raw History Blame Contribute Delete
3.39 kB
"""
HuggingFace Sentiment Analysis
─────────────────────────────
เรียก HuggingFace Inference API เพื่อวิเคราะห์ความรู้สึกของข้อความภาษาไทย
Model ที่แนะนำ:
- airesearch/wangchanberta-base-att-spm-uncased (ภาษาไทย ทั่วไป)
- pythainlp/thai-sentiment-analysis (ถ้ามี fine-tune)
- อาจใช้ multilingual model: cardiffnlp/twitter-xlm-roberta-base-sentiment
"""
import httpx
import logging
from app.config import settings
from app.models import SentimentResult
logger = logging.getLogger(__name__)
HF_API_URL = (
f"https://api-inference.huggingface.co/models/{settings.HF_MODEL_NAME}"
)
# Label mapping จาก model output → ชื่อ standard
LABEL_MAP = {
# WangchanBERTa / Thai models
"pos": "positive",
"neu": "neutral",
"neg": "negative",
# cardiffnlp / XLM-RoBERTa
"positive": "positive",
"neutral": "neutral",
"negative": "negative",
# LABEL_0/1/2 fallback (ขึ้นกับ model)
"LABEL_0": "negative",
"LABEL_1": "neutral",
"LABEL_2": "positive",
}
async def analyze_sentiment(text: str) -> SentimentResult:
"""
ส่งข้อความไปวิเคราะห์ที่ HuggingFace แล้วคืน SentimentResult
HuggingFace Inference API คืนรูปแบบ:
[[{"label": "pos", "score": 0.91}, {"label": "neg", "score": 0.05}, ...]]
"""
headers = {"Authorization": f"Bearer {settings.HF_API_TOKEN}"}
payload = {"inputs": text, "options": {"wait_for_model": True}}
try:
async with httpx.AsyncClient(timeout=15.0) as client:
response = await client.post(HF_API_URL, headers=headers, json=payload)
response.raise_for_status()
data = response.json()
# Flatten nested list ที่ HF คืนมา
scores = data[0] if isinstance(data[0], list) else data
# แปลง label และสร้าง raw_scores dict
raw_scores: dict[str, float] = {}
for item in scores:
normalized = LABEL_MAP.get(item["label"], item["label"].lower())
raw_scores[normalized] = round(item["score"], 4)
# หา label ที่มี score สูงสุด
best_label = max(raw_scores, key=raw_scores.get)
return SentimentResult(
label=best_label,
score=raw_scores[best_label],
raw_scores=raw_scores,
)
except httpx.HTTPStatusError as e:
logger.error(f"HuggingFace API error {e.response.status_code}: {e.response.text}")
return _fallback_result()
except httpx.TimeoutException:
logger.error("HuggingFace API timeout")
return _fallback_result()
except Exception as e:
logger.error(f"Unexpected error in sentiment analysis: {e}")
return _fallback_result()
def _fallback_result() -> SentimentResult:
"""คืน neutral เมื่อ API ล้มเหลว เพื่อไม่ให้ระบบหยุด"""
return SentimentResult(
label="neutral",
score=0.0,
raw_scores={"positive": 0.0, "neutral": 0.0, "negative": 0.0},
)