Spaces:
Sleeping
Sleeping
| """Завантаження відкритих довідкових БД (детерміноване джерело для L1/L2a/L2b). | |
| Усі коди узгоджені між файлами: RxNorm (ліки), LOINC (аналізи), SNOMED (діагнози). | |
| Loader-и кешуються (`lru_cache`) і повертають **незмінні** структури: заморожені | |
| Pydantic-моделі (`refmodels.FrozenModel`) у tuple/MappingProxyType. Це водночас | |
| прибирає перебудову об'єктів на кожен виклик і унеможливлює псування спільного | |
| довідника випадковою мутацією (раніше від цього захищали свіжі копії). | |
| """ | |
| from __future__ import annotations | |
| import json | |
| from collections.abc import Mapping | |
| from functools import lru_cache | |
| from types import MappingProxyType | |
| from typing import Any, Optional | |
| from .config import DATA_DIR | |
| from .refmodels import ( | |
| CondTerm, | |
| DoseLimit, | |
| Interaction, | |
| LabTerm, | |
| MedTerm, | |
| RangeSpec, | |
| RefRange, | |
| Vocab, | |
| ) | |
| def _raw(name: str) -> Any: | |
| return json.loads((DATA_DIR / name).read_text(encoding="utf-8")) | |
| def load_interactions() -> tuple[Interaction, ...]: | |
| """Пари RxNorm-кодів із тяжкістю взаємодії.""" | |
| return tuple(Interaction(**p) for p in _raw("interactions.json")["pairs"]) | |
| def load_dose_limits() -> Mapping[str, DoseLimit]: | |
| """RxNorm → DoseLimit.""" | |
| return MappingProxyType( | |
| {d["rxnorm"]: DoseLimit(**d) for d in _raw("dose_limits.json")["limits"]} | |
| ) | |
| def load_range_specs() -> Mapping[str, RangeSpec]: | |
| """LOINC → RangeSpec (з опціональними варіантами за статтю).""" | |
| return MappingProxyType({ | |
| loinc: RangeSpec(**spec) | |
| for loinc, spec in _raw("reference_ranges.json")["ranges"].items() | |
| }) | |
| def range_for(loinc: str, sex: Optional[str] = None) -> Optional[RefRange]: | |
| """Референсні межі показника, розвʼязані під стать пацієнта (або None).""" | |
| spec = load_range_specs().get(loinc) | |
| return spec.resolve(sex) if spec is not None else None | |
| def load_vocab() -> Vocab: | |
| """Словник для StubExtractor: labs / medications / conditions.""" | |
| raw = _raw("vocab.json") | |
| return Vocab( | |
| labs={k: LabTerm(**v) for k, v in raw.get("labs", {}).items()}, | |
| medications={k: MedTerm(**v) for k, v in raw.get("medications", {}).items()}, | |
| conditions={k: CondTerm(**v) for k, v in raw.get("conditions", {}).items()}, | |
| ) | |
| def load_sample_docs(lang: str = "uk") -> list[dict]: | |
| """Демо-документи мовою ``lang`` (``uk``|``en``). Щоразу свіжа копія. | |
| Набори дзеркальні: ті самі значення й ті самі призначення, тож сигнали | |
| безпеки збігаються — демо не залежить від того, якою мовою його дивляться. | |
| """ | |
| key = "en" if lang == "en" else "uk" | |
| return json.loads(json.dumps(_raw("sample_docs.json")[key])) | |