analisisNews / app /analyzers /framing.py
ahmadsayadi's picture
feat: add emotion, framing, fake-score, opinion-fact endpoints
599f4e5
Raw
History Blame Contribute Delete
2.01 kB
"""
Narrative framing detection.
Identifikasi angle/frame yang digunakan media dalam meliput suatu berita.
"""
from typing import List, Dict
import re
# Frame categories berdasarkan teori framing media
FRAME_PATTERNS: Dict[str, List[str]] = {
"conflict": ["konflik", "versus", "lawan", "sengketa", "pertentangan", "tuduh", "serang", "bantah", "polemik", "debat", "perang"],
"human_interest": ["korban", "keluarga", "anak", "ibu", "kisah", "cerita", "perjuangan", "nasib", "derita", "harapan hidup"],
"economic": ["rupiah", "inflasi", "harga", "ekonomi", "bisnis", "investasi", "saham", "anggaran", "pajak", "untung", "rugi", "pasar"],
"morality": ["etika", "moral", "haram", "halal", "dosa", "adil", "korupsi", "integritas", "tanggung jawab", "amanah"],
"attribution": ["pemerintah", "presiden", "menteri", "DPR", "partai", "kebijakan", "regulasi", "aturan", "instruksi", "perintah"],
"solution": ["solusi", "program", "langkah", "upaya", "strategi", "inovasi", "rencana", "pembangunan", "perbaikan", "reformasi"],
"sensational": ["viral", "heboh", "gempar", "terungkap", "rahasia", "skandal", "mencengangkan", "bikin", "wow", "ternyata"],
}
def detect_framing(text: str) -> Dict:
text_lower = text.lower()
scores = {}
for frame, keywords in FRAME_PATTERNS.items():
hits = sum(1 for kw in keywords if kw in text_lower)
scores[frame] = hits
total = sum(scores.values())
if total == 0:
return {"frames": {k: 0.0 for k in FRAME_PATTERNS}, "dominant_frame": "neutral", "score": 0.0}
normalized = {k: round(v / total, 3) for k, v in scores.items()}
dominant = max(scores, key=scores.get)
return {
"frames": normalized,
"dominant_frame": dominant,
"score": round(scores[dominant] / total, 3),
}
def analyze_batch(items: List) -> List[Dict]:
results = []
for item in items:
framing = detect_framing(item.text)
results.append({"id": item.id, **framing})
return results