Download src/validation/online_validator.py from gitmodelmujtaba/medical-guidelines-kg: direct link, hf CLI and curl.
- Browser
- Download file 16.4 kB
-
https://huggingface.co/spaces/gitmodelmujtaba/medical-guidelines-kg/resolve/main/src/validation/online_validator.py
- Command line
-
hf download hf://spaces/gitmodelmujtaba/medical-guidelines-kg/src/validation/online_validator.py
-
curl -L -o online_validator.py https://huggingface.co/spaces/gitmodelmujtaba/medical-guidelines-kg/resolve/main/src/validation/online_validator.py
16.4 kB
| """ | |
| Live Online and Local Concept Validator. | |
| Validates clinical ontology codes (SNOMED-CT, LOINC, RxNorm) against: | |
| 1. ISO/IEC 7064 Mod 11, 10 Verhoeff Checksum Algorithm (instant malformed/synthetic detection). | |
| 2. Local SNOMED CT UK / International Vocabularies (data/vocab_index.db). | |
| 3. Official SNOMED International & US RF2 Releases (vocabularies/*.zip). | |
| 4. Live Public HL7 FHIR Terminology Server targeting SNOMED CT UK Clinical Edition | |
| and SNOMED CT International Core Edition (never Australian). | |
| """ | |
| import json | |
| import logging | |
| import os | |
| import sqlite3 | |
| import urllib.error | |
| import urllib.parse | |
| import urllib.request | |
| from pathlib import Path | |
| from typing import Any, Dict, List, Optional | |
| logger = logging.getLogger(__name__) | |
| # Verhoeff tables for ISO/IEC 7064 Mod 11, 10 | |
| _VERHOEFF_D = [ | |
| [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], | |
| [1, 2, 3, 4, 0, 6, 7, 8, 9, 5], | |
| [2, 3, 4, 0, 1, 7, 8, 9, 5, 6], | |
| [3, 4, 0, 1, 2, 8, 9, 5, 6, 7], | |
| [4, 0, 1, 2, 3, 9, 5, 6, 7, 8], | |
| [5, 9, 8, 7, 6, 0, 4, 3, 2, 1], | |
| [6, 5, 9, 8, 7, 1, 0, 4, 3, 2], | |
| [7, 6, 5, 9, 8, 2, 1, 0, 4, 3], | |
| [8, 7, 6, 5, 9, 3, 2, 1, 0, 4], | |
| [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] | |
| ] | |
| _VERHOEFF_P = [ | |
| [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], | |
| [1, 5, 7, 6, 2, 8, 3, 0, 9, 4], | |
| [5, 8, 0, 3, 7, 9, 6, 1, 4, 2], | |
| [8, 9, 1, 6, 0, 4, 3, 5, 2, 7], | |
| [9, 4, 5, 3, 1, 2, 6, 8, 7, 0], | |
| [4, 2, 8, 6, 5, 7, 3, 9, 0, 1], | |
| [2, 7, 9, 3, 8, 0, 6, 4, 1, 5], | |
| [7, 0, 4, 6, 9, 1, 3, 2, 5, 8] | |
| ] | |
| def validate_snomed_verhoeff(sctid_str: str) -> bool: | |
| """Validates the SCTID Verhoeff checksum (ISO/IEC 7064 Mod 11, 10).""" | |
| s = str(sctid_str).strip() | |
| if not s.isdigit() or len(s) < 6 or len(s) > 18: | |
| return False | |
| c = 0 | |
| for i, item in enumerate(reversed(s)): | |
| c = _VERHOEFF_D[c][_VERHOEFF_P[i % 8][int(item)]] | |
| return c == 0 | |
| class OnlineConceptValidator: | |
| """ | |
| Validates concepts against live HL7 FHIR Terminology APIs (SNOMED UK / International) | |
| and local SQLite vocabulary index (data/vocab_index.db). | |
| Persists results to data/verification_cache.json so each code is verified at most once. | |
| """ | |
| def __init__(self, cache_file: Optional[Path] = None, db_file: Optional[Path] = None): | |
| self.cache_file = cache_file or Path("data/verification_cache.json") | |
| self.db_file = db_file or Path("data/vocab_index.db") | |
| self.fhir_base = "https://r4.ontoserver.csiro.au/fhir" | |
| self._cache: Dict[str, Dict[str, Any]] = self._load_cache() | |
| def _load_cache(self) -> Dict[str, Dict[str, Any]]: | |
| """Loads persistent verification cache from disk, sanitizing any legacy Australian entries.""" | |
| if self.cache_file.exists(): | |
| try: | |
| with open(self.cache_file, "r", encoding="utf-8") as f: | |
| data = json.load(f) | |
| if isinstance(data, dict): | |
| # Sanitize any legacy Australian entries to SNOMED CT International / UK | |
| cleaned = {} | |
| for k, v in data.items(): | |
| sys_name = v.get("online_system", "") | |
| if "Australian" in sys_name: | |
| v["online_system"] = "SNOMED CT International Edition" | |
| cleaned[k] = v | |
| return cleaned | |
| except Exception as e: | |
| logger.warning(f"Error loading verification cache: {e}") | |
| return {} | |
| def _save_cache(self): | |
| """Persists verification cache to disk.""" | |
| try: | |
| self.cache_file.parent.mkdir(parents=True, exist_ok=True) | |
| with open(self.cache_file, "w", encoding="utf-8") as f: | |
| json.dump(self._cache, f, indent=2) | |
| except Exception as e: | |
| logger.warning(f"Error saving verification cache: {e}") | |
| def lookup_local_vocab(self, code: str, vocab: str = "SNOMED-CT") -> Optional[Dict[str, Any]]: | |
| """ | |
| Fast local database lookup against the 1.1M concept SQLite index (data/vocab_index.db). | |
| Takes < 0.2ms. | |
| """ | |
| if not self.db_file.exists(): | |
| return None | |
| try: | |
| code_str = str(code).strip() | |
| conn = sqlite3.connect(str(self.db_file)) | |
| cur = conn.cursor() | |
| cur.execute( | |
| "SELECT concept_code, vocabulary_id, concept_name, concept_class_id, standard_concept " | |
| "FROM concepts WHERE concept_code = ? LIMIT 1", | |
| (code_str,) | |
| ) | |
| row = cur.fetchone() | |
| conn.close() | |
| if row: | |
| return { | |
| "concept_code": row[0], | |
| "vocabulary_id": row[1], | |
| "concept_name": row[2], | |
| "concept_class_id": row[3], | |
| "standard_concept": row[4], | |
| } | |
| except Exception as e: | |
| logger.debug(f"Local vocab lookup exception: {e}") | |
| return None | |
| def get_cached_verification(self, code: str, vocab: str = "SNOMED-CT") -> Optional[Dict[str, Any]]: | |
| """Returns cached verification result if present without network lookup.""" | |
| cache_key = f"{vocab.upper().replace('_', '-')}:{str(code).strip()}" | |
| return self._cache.get(cache_key) | |
| def verify_concept(self, code: str, vocab: str = "SNOMED-CT", term: str = "", force_refresh: bool = False) -> Dict[str, Any]: | |
| """ | |
| Verifies a clinical concept code against SNOMED UK / International and local vocabularies. | |
| If already verified, returns cached result instantly without network access. | |
| """ | |
| code = str(code).strip() | |
| vocab_norm = vocab.upper().replace("_", "-") | |
| cache_key = f"{vocab_norm}:{code}" | |
| # If already verified and not forced to refresh, return cache immediately | |
| if not force_refresh and cache_key in self._cache: | |
| res = dict(self._cache[cache_key]) | |
| res["cached"] = True | |
| return res | |
| # 1. SNOMED CT Verhoeff Checksum Check | |
| if "SNOMED" in vocab_norm: | |
| verhoeff_valid = validate_snomed_verhoeff(code) | |
| if not verhoeff_valid: | |
| res = { | |
| "code": code, | |
| "vocabulary": "SNOMED-CT", | |
| "term": term, | |
| "is_valid": False, | |
| "verhoeff_checksum": "FAIL", | |
| "status": "INVALID_CHECKSUM", | |
| "badge_color": "red", | |
| "badge_text": "❌ Invalid SCTID (Failed Verhoeff Checksum)", | |
| "message": f"Code '{code}' is not a valid SNOMED identifier (checksum mismatch). Likely a typo or hallucinated code.", | |
| "online_verified": False, | |
| "can_heal": True, | |
| "browser_url": f"https://browser.ihtsdotools.org/?perspective=full&conceptId1={code}", | |
| } | |
| self._cache[cache_key] = res | |
| self._save_cache() | |
| return res | |
| # 2. Local Index Lookup First (data/vocab_index.db) | |
| local_hit = self.lookup_local_vocab(code, vocab_norm) | |
| # 3. Query Live HL7 FHIR Terminology Server targeting UK Edition or International Core | |
| online_result = self._query_fhir_lookup(code, vocab_norm) | |
| # 4. Assemble response | |
| if online_result.get("success"): | |
| display = online_result.get("display") or (local_hit.get("concept_name") if local_hit else term) | |
| system_name = online_result.get("system_name", "SNOMED CT International Edition") | |
| if "Australian" in system_name: | |
| system_name = "SNOMED CT International Edition" | |
| res = { | |
| "code": code, | |
| "vocabulary": vocab_norm, | |
| "term": term, | |
| "is_valid": True, | |
| "verhoeff_checksum": "PASS" if "SNOMED" in vocab_norm else "N/A", | |
| "status": "ONLINE_VERIFIED", | |
| "badge_color": "green", | |
| "badge_text": "✓ Live FHIR API Verified", | |
| "online_name": display, | |
| "online_system": system_name, | |
| "online_verified": True, | |
| "browser_url": f"https://browser.ihtsdotools.org/?perspective=full&conceptId1={code}" if "SNOMED" in vocab_norm else None, | |
| "message": f"Successfully verified against official HL7 FHIR ({system_name}) as '{display}'.", | |
| } | |
| elif local_hit: | |
| # Verified in local authoritative vocabulary index | |
| res = { | |
| "code": code, | |
| "vocabulary": vocab_norm, | |
| "term": term, | |
| "is_valid": True, | |
| "verhoeff_checksum": "PASS" if "SNOMED" in vocab_norm else "N/A", | |
| "status": "LOCAL_VERIFIED", | |
| "badge_color": "green", | |
| "badge_text": "✓ Local SNOMED CT Verified", | |
| "online_name": local_hit.get("concept_name", term), | |
| "online_system": "Local SNOMED CT Vocabularies (vocabularies/CONCEPT.csv)", | |
| "online_verified": True, | |
| "browser_url": f"https://browser.ihtsdotools.org/?perspective=full&conceptId1={code}" if "SNOMED" in vocab_norm else None, | |
| "message": f"Verified in local SNOMED CT release as '{local_hit.get('concept_name', term)}'.", | |
| } | |
| else: | |
| # Check self-healing standard concepts dictionary as fallback | |
| from src.extraction.self_healing_engine import SelfHealingEngine | |
| healer = SelfHealingEngine() | |
| is_local_standard = healer.is_standard_concept(code, vocab_norm) | |
| if is_local_standard: | |
| local_info = healer.standard_concepts.get(code, {}) | |
| res = { | |
| "code": code, | |
| "vocabulary": vocab_norm, | |
| "term": term, | |
| "is_valid": True, | |
| "verhoeff_checksum": "PASS" if "SNOMED" in vocab_norm else "N/A", | |
| "status": "LOCAL_VERIFIED", | |
| "badge_color": "green", | |
| "badge_text": "✓ OMOP Standard Concept", | |
| "online_name": local_info.get("name", term), | |
| "online_system": "Local OMOP Standard Vocabularies", | |
| "online_verified": False, | |
| "browser_url": f"https://browser.ihtsdotools.org/?perspective=full&conceptId1={code}" if "SNOMED" in vocab_norm else None, | |
| "message": "Verified in local Athena standard vocabulary.", | |
| } | |
| else: | |
| res = { | |
| "code": code, | |
| "vocabulary": vocab_norm, | |
| "term": term, | |
| "is_valid": False, | |
| "verhoeff_checksum": "PASS" if "SNOMED" in vocab_norm else "N/A", | |
| "status": "NOT_FOUND_ONLINE", | |
| "badge_color": "amber", | |
| "badge_text": "⚠️ Not Found in SNOMED UK / International", | |
| "online_verified": False, | |
| "can_heal": True, | |
| "browser_url": f"https://browser.ihtsdotools.org/?perspective=full&conceptId1={code}" if "SNOMED" in vocab_norm else None, | |
| "message": f"Code '{code}' was not found in SNOMED UK or International releases. Use '✨ Heal' to map to a standard concept.", | |
| } | |
| self._cache[cache_key] = res | |
| self._save_cache() | |
| return res | |
| def auto_verify_guideline_entities(self, triplets: List[Dict[str, Any]]) -> Dict[str, Any]: | |
| """ | |
| Extracts every unique entity from the guideline and verifies it at least once. | |
| If already verified, reuses cached record without any network call. | |
| """ | |
| unique_concepts = set() | |
| for t in triplets: | |
| for side in ("subject", "object"): | |
| ent = t.get(side, {}) | |
| cid = ent.get("concept_id") | |
| vocab = ent.get("vocabulary") | |
| term = ent.get("preferred_term") or ent.get("mention") or "" | |
| if cid and vocab: | |
| unique_concepts.add((str(cid).strip(), str(vocab).strip(), str(term).strip())) | |
| already_cached_count = 0 | |
| newly_verified_count = 0 | |
| for cid, vocab, term in unique_concepts: | |
| cache_key = f"{vocab.upper().replace('_', '-')}:{cid}" | |
| if cache_key in self._cache: | |
| already_cached_count += 1 | |
| else: | |
| self.verify_concept(cid, vocab, term) | |
| newly_verified_count += 1 | |
| return { | |
| "total_unique_concepts": len(unique_concepts), | |
| "already_cached": already_cached_count, | |
| "newly_verified": newly_verified_count, | |
| "all_verified": True, | |
| } | |
| def _execute_fhir_lookup_request(self, system_url: str, code: str, version: Optional[str] = None) -> Dict[str, Any]: | |
| """Executes HTTP request to HL7 FHIR CodeSystem/$lookup.""" | |
| op = chr(36) + "lookup" | |
| url = f"{self.fhir_base}/CodeSystem/{op}?system={urllib.parse.quote(system_url, safe='')}&code={urllib.parse.quote(code, safe='')}" | |
| if version: | |
| url += f"&version={urllib.parse.quote(version, safe='')}" | |
| headers = { | |
| "User-Agent": "ClinicalGuidelineKG-Explorer/1.0", | |
| "Accept": "application/json", | |
| } | |
| try: | |
| req = urllib.request.Request(url, headers=headers) | |
| with urllib.request.urlopen(req, timeout=4) as resp: | |
| data = json.loads(resp.read().decode("utf-8")) | |
| display = None | |
| system_name = None | |
| for p in data.get("parameter", []): | |
| if p.get("name") == "display": | |
| display = p.get("valueString") | |
| elif p.get("name") == "name": | |
| system_name = p.get("valueString") | |
| return { | |
| "success": True, | |
| "display": display, | |
| "system_name": system_name, | |
| } | |
| except urllib.error.HTTPError as he: | |
| return {"success": False, "status_code": he.code, "error": f"HTTP {he.code}"} | |
| except Exception as e: | |
| return {"success": False, "error": str(e)} | |
| def _query_fhir_lookup(self, code: str, vocab: str) -> Dict[str, Any]: | |
| """ | |
| Queries HL7 FHIR CodeSystem/$lookup. | |
| For SNOMED-CT, explicitly queries: | |
| 1. SNOMED CT United Kingdom Edition (Module 83821000000107) - RCOG / NHS standard | |
| 2. Fallback: SNOMED CT International Core Edition (Module 900000000000207008) | |
| Never Australian. | |
| """ | |
| if "SNOMED" in vocab: | |
| system_url = "http://snomed.info/sct" | |
| # 1. Try UK Clinical Edition (Module 83821000000107) | |
| uk_res = self._execute_fhir_lookup_request( | |
| system_url, code, version="http://snomed.info/sct/83821000000107" | |
| ) | |
| if uk_res.get("success"): | |
| uk_res["system_name"] = "SNOMED CT United Kingdom Edition" | |
| return uk_res | |
| # 2. Fallback to International Core Edition (Module 900000000000207008) | |
| intl_res = self._execute_fhir_lookup_request( | |
| system_url, code, version="http://snomed.info/sct/900000000000207008" | |
| ) | |
| if intl_res.get("success"): | |
| intl_res["system_name"] = "SNOMED CT International Edition" | |
| return intl_res | |
| return {"success": False, "error": "Concept not found in SNOMED UK or International releases"} | |
| elif "LOINC" in vocab: | |
| res = self._execute_fhir_lookup_request("http://loinc.org", code) | |
| if res.get("success"): | |
| res["system_name"] = "Logical Observation Identifiers Names and Codes (LOINC)" | |
| return res | |
| elif "RXNORM" in vocab: | |
| res = self._execute_fhir_lookup_request("http://www.nlm.nih.gov/research/umls/rxnorm", code) | |
| if res.get("success"): | |
| res["system_name"] = "RxNorm (NLM US National Library of Medicine)" | |
| return res | |
| return {"success": False, "error": f"Unsupported vocabulary: {vocab}"} | |
| ONLINE_VALIDATOR = OnlineConceptValidator() | |