analisisNews / app /analyzers /similarity.py
ahmadsayadi's picture
feat: BrainWatches Python Analysis Service - sentiment, topics, summarize, similarity
60e8c0a
Raw
History Blame Contribute Delete
1.31 kB
"""
Semantic similarity via TF-IDF + cosine (scikit-learn).
Cari pasangan artikel mirip secara makna.
"""
from typing import List, Dict
import re
INDO_STOPWORDS = {
"yang", "di", "ke", "dari", "untuk", "pada", "dengan", "ini", "itu", "dan",
"atau", "adalah", "akan", "juga", "tidak", "para", "oleh", "sebagai",
}
def _clean(text: str) -> str:
text = re.sub(r"[^a-zA-Z\s]", " ", text.lower())
return re.sub(r"\s+", " ", text).strip()
def find_similar_pairs(items: List, threshold: float = 0.3) -> List[Dict]:
if len(items) < 2:
return []
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
docs = [_clean(it.text) for it in items]
ids = [it.id for it in items]
vectorizer = TfidfVectorizer(max_features=3000, stop_words=list(INDO_STOPWORDS))
try:
X = vectorizer.fit_transform(docs)
except ValueError:
return []
sim = cosine_similarity(X)
pairs = []
n = len(ids)
for i in range(n):
for j in range(i + 1, n):
score = float(sim[i, j])
if score >= threshold:
pairs.append({"id_a": ids[i], "id_b": ids[j], "score": round(score, 3)})
pairs.sort(key=lambda p: p["score"], reverse=True)
return pairs[:500]