Spaces:
Running
Running
| """ | |
| Fake news score (heuristik). | |
| Skor 0-100 indikasi potensi hoax/misinformasi berdasarkan pola teks. | |
| """ | |
| from typing import List, Dict | |
| import re | |
| # Indikator clickbait/hoax | |
| HOAX_INDICATORS = [ | |
| "terungkap", "ternyata", "rahasia", "viral", "heboh", "bikin", | |
| "terbongkar", "fakta mencengangkan", "anda harus tahu", | |
| "jangan sampai", "ini dia", "wow", "gempar", | |
| ] | |
| CREDIBILITY_MARKERS = [ | |
| "menurut", "berdasarkan", "data", "riset", "penelitian", | |
| "sumber", "narasumber", "konfirmasi", "verifikasi", "resmi", | |
| ] | |
| def calculate_fake_score(text: str, title: str = "") -> Dict: | |
| text_lower = (title + " " + text).lower() | |
| score = 0 | |
| reasons = [] | |
| # 1. Kata-kata pemicu hoax di judul | |
| title_lower = title.lower() | |
| hoax_hits = sum(1 for w in HOAX_INDICATORS if w in title_lower) | |
| if hoax_hits > 0: | |
| score += min(30, hoax_hits * 15) | |
| reasons.append(f"{hoax_hits} kata pemicu hoax") | |
| # 2. Tanda seru/tanya berlebihan | |
| excl = title.count("!") + title.count("?") | |
| if excl > 1: | |
| score += min(15, excl * 7) | |
| reasons.append(f"{excl} tanda seru/tanya") | |
| # 3. ALL CAPS | |
| caps = len(re.findall(r'\b[A-Z]{3,}\b', title)) | |
| if caps > 1: | |
| score += min(15, caps * 7) | |
| reasons.append(f"{caps} kata KAPITAL") | |
| # 4. Tidak ada sumber/narasumber | |
| cred_hits = sum(1 for w in CREDIBILITY_MARKERS if w in text_lower) | |
| if cred_hits == 0: | |
| score += 20 | |
| reasons.append("tidak ada sumber terverifikasi") | |
| elif cred_hits >= 3: | |
| score -= 10 | |
| reasons.append(f"{cred_hits} marker kredibilitas") | |
| # 5. Teks sangat pendek (kurang substansi) | |
| word_count = len(text.split()) | |
| if word_count < 50: | |
| score += 15 | |
| reasons.append("konten sangat pendek") | |
| # 6. Banyak klaim tanpa bukti (kalimat deklaratif tanpa attributor) | |
| sentences = re.split(r'[.!?]', text) | |
| declarative = sum(1 for s in sentences if len(s.strip()) > 20 and not any(m in s.lower() for m in CREDIBILITY_MARKERS)) | |
| ratio = declarative / max(len(sentences), 1) | |
| if ratio > 0.8: | |
| score += 10 | |
| reasons.append("mayoritas klaim tanpa atribusi") | |
| score = max(0, min(100, score)) | |
| level = "tinggi" if score >= 60 else "sedang" if score >= 30 else "rendah" | |
| return {"score": score, "level": level, "reasons": reasons} | |
| def analyze_batch(items: List) -> List[Dict]: | |
| results = [] | |
| for item in items: | |
| # Pisah title dari text (asumsi: kalimat pertama = title) | |
| parts = item.text.split(". ", 1) | |
| title = parts[0] if len(parts) > 1 else "" | |
| content = parts[1] if len(parts) > 1 else item.text | |
| result = calculate_fake_score(content, title) | |
| results.append({"id": item.id, **result}) | |
| return results | |