| import typing as t |
| import pymorphy3 |
| import re |
| import ujson as json |
| import pathlib |
| from transliterate import translit |
| from functools import lru_cache |
| from .config import Keys, Paths |
| from collections import defaultdict |
|
|
|
|
| CACHE_SIZE = 256 |
|
|
|
|
| class Matcher: |
| def __init__(self): |
| self.morph = pymorphy3.MorphAnalyzer(lang="ru") |
| self.pairs: dict[str, tuple[float, bool]] = json.loads(pathlib.Path(Paths.PAIRS).read_text()) |
| self.preprocess: dict[str, str] = json.loads(pathlib.Path(Paths.PREPROCESSOR).read_text()) |
|
|
| def __call__(self, key: Keys) -> t.Callable: |
| match key: |
| case Keys.DIAG: |
| return self.match_diags |
| case Keys.DOC: |
| return self.match_doctors |
| raise KeyError |
|
|
| def match_doctors(self, doc: str, other_doc: str) -> bool: |
| if not doc or not other_doc: |
| return False |
| words: set[str] = self.text_to_words(doc) |
| other_words: set[str] = self.text_to_words(other_doc) |
| return len(words & other_words) / min(len(words), len(other_words), 1) > 0.49 |
|
|
| def match_diags(self, raw_diag: str, raw_other_diag: str) -> bool: |
| diag: str = self.preprocess.get(raw_diag, "") |
| other_diag: str = self.preprocess.get(raw_other_diag, "") |
| if not diag or not other_diag: |
| return False |
| if diag == other_diag: |
| return True |
| pair_check: bool | None = self.pairs.get(f"{diag}|{other_diag}", None) |
| if pair_check is not None: |
| return pair_check[1] |
| reverse_pair_check: bool | None = self.pairs.get(f"{other_diag}|{diag}", None) |
| if reverse_pair_check is not None: |
| return reverse_pair_check[1] |
| return True |
|
|
| @lru_cache(maxsize=CACHE_SIZE) |
| def text_to_words(self, input_text: str) -> set[str]: |
| text = input_text.lower() |
| text = translit(text, "ru") |
| text = re.sub(r"[^а-я_]+", " ", text).strip() |
| return set([self.morph.parse(word)[0].normal_form for word in text.split()]) |
|
|