Spaces:
Running
Running
| """ | |
| 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] | |