Rifqi Hafizuddin
[NOTICKET] feat(knowledge_extraction): paid extraction stage + validate, diff, queue
ab5ea78 | """Detect contradictory definitions within one cluster. | |
| Token overlap, not embeddings: cheaper, needs no model, and — the reason that | |
| matters — **explainable to the reviewer who has to act on it**. | |
| This module deliberately does NOT pick a winner. Two contradictory definitions | |
| of the same term is a decision only the expert can make, and it is only | |
| detectable at all because clustering puts all the evidence in one call. | |
| """ | |
| from __future__ import annotations | |
| import re | |
| from ..settings import CONFLICT_OVERLAP_THRESHOLD | |
| def tokens(text: str) -> set[str]: | |
| return {t for t in re.findall(r"\w+", (text or "").casefold()) if len(t) > 2} | |
| def overlap(a: str, b: str) -> float: | |
| ta, tb = tokens(a), tokens(b) | |
| if not ta or not tb: | |
| return 0.0 | |
| return len(ta & tb) / min(len(ta), len(tb)) | |
| def find_conflicts(definitions: list[str]) -> tuple[bool, list[str]]: | |
| """Returns (conflicting, variants). Definitions that share little vocabulary | |
| are treated as competing rather than as rewordings of each other.""" | |
| present = [d.strip() for d in definitions if d and d.strip()] | |
| unique: list[str] = [] | |
| for definition in present: | |
| if not any(overlap(definition, seen) >= 0.9 for seen in unique): | |
| unique.append(definition) | |
| if len(unique) < 2: | |
| return False, [] | |
| conflicting = any( | |
| overlap(unique[i], unique[j]) < CONFLICT_OVERLAP_THRESHOLD | |
| for i in range(len(unique)) | |
| for j in range(i + 1, len(unique)) | |
| ) | |
| return conflicting, unique if conflicting else [] | |