aimedicalcoding 0.3.7__tar.gz → 0.3.9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {aimedicalcoding-0.3.7/aimedicalcoding.egg-info → aimedicalcoding-0.3.9}/PKG-INFO +1 -1
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/systems/cvx/patterns.py +12 -8
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/systems/icd10cm/patterns.py +10 -6
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/systems/loinc/patterns.py +9 -1
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/systems/rxnorm/patterns.py +13 -8
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/systems/snomed/patterns.py +13 -10
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9/aimedicalcoding.egg-info}/PKG-INFO +1 -1
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/docs/GAP_SCHEMA.md +2 -2
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/setup.py +1 -1
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/LICENSE +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/MANIFEST.in +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/README.md +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/README_PYPI.md +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/__init__.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/__main__.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/adapters/__init__.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/adapters/base.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/adapters/ccda/__init__.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/adapters/ccda/adapter.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/adapters/ccda/codes.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/adapters/ccda/narrative.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/adapters/ccda/sections.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/adapters/custom_json/__init__.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/adapters/custom_json/adapter.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/adapters/fhir/__init__.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/adapters/fhir/adapter.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/adapters/fhir/codes.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/adapters/fhir/mapping.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/api.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/core/__init__.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/core/checkdigits.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/core/models.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/core/system_registry.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/pipeline/__init__.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/pipeline/orchestrator.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/recovery/__init__.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/recovery/engine.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/serialize.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/systems/__init__.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/systems/base.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/systems/cvx/__init__.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/systems/cvx/handler.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/systems/cvx/normalize.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/systems/icd10cm/__init__.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/systems/icd10cm/handler.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/systems/icd10cm/icdformat.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/systems/loinc/__init__.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/systems/loinc/axes.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/systems/loinc/handler.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/systems/loinc/normalize.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/systems/rxnorm/__init__.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/systems/rxnorm/handler.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/systems/rxnorm/normalize.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/systems/snomed/__init__.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/systems/snomed/handler.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/systems/snomed/hierarchy.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/systems/snomed/qualifiers.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/terminology/__init__.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/terminology/service.py +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding.egg-info/SOURCES.txt +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding.egg-info/dependency_links.txt +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding.egg-info/entry_points.txt +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding.egg-info/requires.txt +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding.egg-info/top_level.txt +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/docs/ARCHITECTURE.md +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/docs/OUTPUT_GUIDE.md +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/docs/patterns/CVX_pattern_analysis.md +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/docs/patterns/ICD10CM_pattern_analysis.md +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/docs/patterns/LOINC_pattern_analysis.md +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/docs/patterns/RxNorm_pattern_analysis.md +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/docs/patterns/SNOMED_pattern_analysis.md +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/pyproject.toml +0 -0
- {aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aimedicalcoding
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.9
|
|
4
4
|
Summary: Detect missing/broken clinical codes (LOINC / SNOMED CT / RxNorm / ICD-10-CM / CVX) in CCDA and FHIR documents, with recovery evidence
|
|
5
5
|
Author: Aakash Kag, Vinay Shankar Miryala, Siva Karthik, Mohammed Rayaan
|
|
6
6
|
License: MIT
|
|
@@ -73,13 +73,14 @@ def classify(stmt: ClinicalStatement) -> Optional[CvxGapPattern]:
|
|
|
73
73
|
if cc and cc.code and cc.system not in STRUCTURAL:
|
|
74
74
|
return CvxGapPattern.LOCAL_CODE_ONLY
|
|
75
75
|
|
|
76
|
+
# no usable code + no vaccine name -> nothing to recover -> not a gap
|
|
77
|
+
if not stmt.raw_text:
|
|
78
|
+
return None
|
|
76
79
|
if _has_nullflavor(stmt):
|
|
77
80
|
return CvxGapPattern.NULLFLAVOR
|
|
78
|
-
if stmt.
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
return CvxGapPattern.DISPLAY_ONLY
|
|
82
|
-
return None
|
|
81
|
+
if "/text" in (stmt.source_ref or ""):
|
|
82
|
+
return CvxGapPattern.NARRATIVE_ONLY
|
|
83
|
+
return CvxGapPattern.DISPLAY_ONLY
|
|
83
84
|
|
|
84
85
|
|
|
85
86
|
# --------------------------------------------------------------------------
|
|
@@ -109,17 +110,20 @@ def parse_gap(stmt: ClinicalStatement, pattern: CvxGapPattern) -> Gap:
|
|
|
109
110
|
|
|
110
111
|
if pattern == CvxGapPattern.RXNORM_ONLY and cc:
|
|
111
112
|
gap.evidence["rxnorm_code"] = cc.code
|
|
112
|
-
gap.evidence["rxnorm_system"] = cc.
|
|
113
|
+
gap.evidence["rxnorm_system"] = cc.system.value if cc.system else None
|
|
114
|
+
gap.evidence["rxnorm_system_raw"] = cc.raw_system
|
|
113
115
|
gap.note = ("Use the CDC/NLM CVX↔RxNorm crosswalk — deterministic; "
|
|
114
116
|
"LLM only if a generic RxCUI maps to multiple CVX valences.")
|
|
115
117
|
elif pattern == CvxGapPattern.NDC_ONLY and cc:
|
|
116
118
|
gap.evidence["ndc_code"] = cc.code
|
|
117
|
-
gap.evidence["ndc_system"] = cc.
|
|
119
|
+
gap.evidence["ndc_system"] = cc.system.value if cc.system else None
|
|
120
|
+
gap.evidence["ndc_system_raw"] = cc.raw_system
|
|
118
121
|
gap.note = ("Use the CDC vaccine NDC↔CVX table (published, free) — "
|
|
119
122
|
"deterministic mapping from the dispensed NDC to CVX.")
|
|
120
123
|
elif pattern == CvxGapPattern.LOCAL_CODE_ONLY and cc:
|
|
121
124
|
gap.evidence["local_code"] = cc.code
|
|
122
|
-
gap.evidence["local_system"] = cc.
|
|
125
|
+
gap.evidence["local_system"] = cc.system.value if cc.system else None
|
|
126
|
+
gap.evidence["local_system_raw"] = cc.raw_system
|
|
123
127
|
gap.note = ("Crosswalk local immunization code → CVX first; else search "
|
|
124
128
|
"by normalized vaccine concept (+ valence) → CVX.")
|
|
125
129
|
elif pattern == CvxGapPattern.BAD_CODE and cc:
|
|
@@ -67,13 +67,16 @@ def classify(stmt: ClinicalStatement) -> Optional[Icd10cmGapPattern]:
|
|
|
67
67
|
if other: # ICD-9 / local / anything else
|
|
68
68
|
return Icd10cmGapPattern.LOCAL_CODE_ONLY
|
|
69
69
|
|
|
70
|
+
# diagnosis is value-slot: require a value-slot label to recover from.
|
|
71
|
+
# No code AND no value label (e.g. dataAbsentReason, no text) -> not a gap.
|
|
72
|
+
val_label = stmt.value and (stmt.value.original_text or stmt.value.raw)
|
|
73
|
+
if not val_label:
|
|
74
|
+
return None
|
|
70
75
|
if _has_nullflavor(stmt):
|
|
71
76
|
return Icd10cmGapPattern.NULLFLAVOR
|
|
72
|
-
if
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
return Icd10cmGapPattern.DISPLAY_ONLY
|
|
76
|
-
return None
|
|
77
|
+
if "/text" in (stmt.source_ref or ""):
|
|
78
|
+
return Icd10cmGapPattern.NARRATIVE_ONLY
|
|
79
|
+
return Icd10cmGapPattern.DISPLAY_ONLY
|
|
77
80
|
|
|
78
81
|
|
|
79
82
|
# --------------------------------------------------------------------------
|
|
@@ -117,7 +120,8 @@ def parse_gap(stmt: ClinicalStatement, pattern: Icd10cmGapPattern) -> Gap:
|
|
|
117
120
|
"deterministic; LLM to pick among targets / add specificity.")
|
|
118
121
|
elif pattern == Icd10cmGapPattern.LOCAL_CODE_ONLY and cc:
|
|
119
122
|
gap.evidence["local_code"] = cc.code
|
|
120
|
-
gap.evidence["local_system"] = (cc.system.value if cc.system else
|
|
123
|
+
gap.evidence["local_system"] = (cc.system.value if cc.system else None)
|
|
124
|
+
gap.evidence["local_system_raw"] = cc.raw_system
|
|
121
125
|
gap.note = ("Crosswalk the source code → ICD-10-CM (ICD-9 → use CMS GEMs); "
|
|
122
126
|
"else text + qualifier search.")
|
|
123
127
|
elif pattern == Icd10cmGapPattern.BAD_CODE and cc:
|
|
@@ -77,6 +77,11 @@ def classify(stmt: ClinicalStatement) -> Optional[GapPattern]:
|
|
|
77
77
|
if clinical_codes:
|
|
78
78
|
return GapPattern.LOCAL_CODE_ONLY
|
|
79
79
|
|
|
80
|
+
# No usable code: a gap is only actionable if a concept label exists to
|
|
81
|
+
# search with. No code AND no label (e.g. dataAbsentReason with no text)
|
|
82
|
+
# -> nothing to fill -> not a gap.
|
|
83
|
+
if not stmt.raw_text:
|
|
84
|
+
return None
|
|
80
85
|
has_nullflavor = any(c.system == System.NULLFLAVOR for c in stmt.codings)
|
|
81
86
|
if has_nullflavor:
|
|
82
87
|
return GapPattern.NULLFLAVOR
|
|
@@ -94,7 +99,10 @@ def parse_local_code_only(stmt: ClinicalStatement, expand_abbrev: bool = False)
|
|
|
94
99
|
local = next((c for c in stmt.codings if c.code and c.system != System.LOINC), None)
|
|
95
100
|
ev = axes.evidence_packet(stmt, expand_abbrev)
|
|
96
101
|
ev["local_code"] = local.code if local else None
|
|
97
|
-
|
|
102
|
+
# canonical system (format-independent: "CPT" whether from a CCDA OID or a
|
|
103
|
+
# FHIR URI) drives the crosswalk; raw is kept for provenance.
|
|
104
|
+
ev["local_system"] = (local.system.value if local and local.system else None)
|
|
105
|
+
ev["local_system_raw"] = (local.raw_system if local else None)
|
|
98
106
|
return Gap(
|
|
99
107
|
type=GapPattern.LOCAL_CODE_ONLY.value,
|
|
100
108
|
match_key=axes.build_match_key(stmt, expand_abbrev),
|
|
@@ -68,13 +68,14 @@ def classify(stmt: ClinicalStatement) -> Optional[RxnormGapPattern]:
|
|
|
68
68
|
if cc and cc.code and cc.system not in STRUCTURAL:
|
|
69
69
|
return RxnormGapPattern.LOCAL_CODE_ONLY # local/formulary/other
|
|
70
70
|
|
|
71
|
+
# no usable code + no drug name -> nothing to recover -> not a gap
|
|
72
|
+
if not stmt.raw_text:
|
|
73
|
+
return None
|
|
71
74
|
if _has_nullflavor(stmt):
|
|
72
75
|
return RxnormGapPattern.NULLFLAVOR
|
|
73
|
-
if stmt.
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
return RxnormGapPattern.DISPLAY_ONLY
|
|
77
|
-
return None
|
|
76
|
+
if "/text" in (stmt.source_ref or ""):
|
|
77
|
+
return RxnormGapPattern.NARRATIVE_ONLY
|
|
78
|
+
return RxnormGapPattern.DISPLAY_ONLY
|
|
78
79
|
|
|
79
80
|
|
|
80
81
|
# --------------------------------------------------------------------------
|
|
@@ -115,7 +116,8 @@ def parse_gap(stmt: ClinicalStatement, pattern: RxnormGapPattern) -> Gap:
|
|
|
115
116
|
|
|
116
117
|
if pattern == RxnormGapPattern.NDC_ONLY and cc:
|
|
117
118
|
gap.evidence["ndc_code"] = cc.code
|
|
118
|
-
gap.evidence["ndc_system"] = cc.
|
|
119
|
+
gap.evidence["ndc_system"] = cc.system.value if cc.system else None
|
|
120
|
+
gap.evidence["ndc_system_raw"] = cc.raw_system
|
|
119
121
|
gap.note = ("Use the NDC↔RxNorm crosswalk (RxNorm release / REST API) — "
|
|
120
122
|
"deterministic; LLM only if multiple RxCUIs map.")
|
|
121
123
|
elif pattern in _SOURCE_VOCAB_PATTERN.values() and cc:
|
|
@@ -123,15 +125,18 @@ def parse_gap(stmt: ClinicalStatement, pattern: RxnormGapPattern) -> Gap:
|
|
|
123
125
|
gap.evidence["source_code"] = cc.code
|
|
124
126
|
gap.evidence["source_vocab"] = vocab
|
|
125
127
|
gap.evidence["source_system"] = cc.raw_system
|
|
126
|
-
# serialize.py builds a crosswalk hint from local_code/local_system
|
|
128
|
+
# serialize.py builds a crosswalk hint from local_code/local_system.
|
|
129
|
+
# local_system is the canonical vocab (format-independent); raw kept too.
|
|
127
130
|
gap.evidence["local_code"] = cc.code
|
|
128
131
|
gap.evidence["local_system"] = vocab
|
|
132
|
+
gap.evidence["local_system_raw"] = cc.raw_system
|
|
129
133
|
gap.note = (f"Crosswalk {vocab} → RxNorm via the UMLS Metathesaurus "
|
|
130
134
|
f"(shared CUI) or the vendor's RxNorm map — deterministic; "
|
|
131
135
|
f"LLM only if the mapping is ambiguous or 1→many.")
|
|
132
136
|
elif pattern == RxnormGapPattern.LOCAL_CODE_ONLY and cc:
|
|
133
137
|
gap.evidence["local_code"] = cc.code
|
|
134
|
-
gap.evidence["local_system"] = cc.
|
|
138
|
+
gap.evidence["local_system"] = cc.system.value if cc.system else None
|
|
139
|
+
gap.evidence["local_system_raw"] = cc.raw_system
|
|
135
140
|
gap.note = ("Crosswalk local/formulary code → RxNorm first; else search by "
|
|
136
141
|
"ingredient + strength + dose form → SCD/SBD.")
|
|
137
142
|
elif pattern == RxnormGapPattern.NULLFLAVOR:
|
|
@@ -113,16 +113,17 @@ def classify(stmt: ClinicalStatement) -> Optional[SnomedGapPattern]:
|
|
|
113
113
|
if cc and cc.code and cc.system not in STRUCTURAL:
|
|
114
114
|
return SnomedGapPattern.LOCAL_CODE_ONLY # CPT / local / other
|
|
115
115
|
|
|
116
|
-
# no usable concept code.
|
|
117
|
-
# (value display/originalText for value-slot
|
|
118
|
-
#
|
|
116
|
+
# no usable concept code. A gap is only actionable if a recoverable label
|
|
117
|
+
# exists for the concept's slot (value display/originalText for value-slot
|
|
118
|
+
# contexts). If there is neither a code NOR a label (e.g. dataAbsentReason
|
|
119
|
+
# with no value text/note), there is nothing to fill -> not a gap.
|
|
120
|
+
if not concept_term(stmt):
|
|
121
|
+
return None
|
|
119
122
|
if _has_nullflavor(stmt):
|
|
120
123
|
return SnomedGapPattern.NULLFLAVOR
|
|
121
|
-
if
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
return SnomedGapPattern.DISPLAY_ONLY
|
|
125
|
-
return None
|
|
124
|
+
if "/text" in (stmt.source_ref or ""):
|
|
125
|
+
return SnomedGapPattern.NARRATIVE_ONLY
|
|
126
|
+
return SnomedGapPattern.DISPLAY_ONLY
|
|
126
127
|
|
|
127
128
|
|
|
128
129
|
# --------------------------------------------------------------------------
|
|
@@ -149,7 +150,8 @@ def parse_gap(stmt: ClinicalStatement, pattern: SnomedGapPattern) -> Gap:
|
|
|
149
150
|
|
|
150
151
|
if pattern == SnomedGapPattern.LOCAL_CODE_ONLY and cc:
|
|
151
152
|
gap.evidence["local_code"] = cc.code
|
|
152
|
-
gap.evidence["local_system"] = cc.
|
|
153
|
+
gap.evidence["local_system"] = cc.system.value if cc.system else None
|
|
154
|
+
gap.evidence["local_system_raw"] = cc.raw_system
|
|
153
155
|
gap.note = ("Crosswalk (system, code) → SNOMED first (e.g. CPT/local map); "
|
|
154
156
|
"else hierarchy-constrained text search, then LLM.")
|
|
155
157
|
elif pattern == SnomedGapPattern.ICD_ONLY and cc:
|
|
@@ -159,7 +161,8 @@ def parse_gap(stmt: ClinicalStatement, pattern: SnomedGapPattern) -> Gap:
|
|
|
159
161
|
"LLM only to choose among multiple map targets.")
|
|
160
162
|
elif pattern == SnomedGapPattern.RXNORM_ONLY and cc:
|
|
161
163
|
gap.evidence["rxnorm_code"] = cc.code
|
|
162
|
-
gap.evidence["rxnorm_system"] = cc.
|
|
164
|
+
gap.evidence["rxnorm_system"] = cc.system.value if cc.system else None
|
|
165
|
+
gap.evidence["rxnorm_system_raw"] = cc.raw_system
|
|
163
166
|
gap.note = ("RxNorm-coded allergen (drug allergy) — crosswalk RxNorm → "
|
|
164
167
|
"SNOMED substance/product via UMLS CUI; LLM only if the "
|
|
165
168
|
"ingredient maps ambiguously.")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aimedicalcoding
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.9
|
|
4
4
|
Summary: Detect missing/broken clinical codes (LOINC / SNOMED CT / RxNorm / ICD-10-CM / CVX) in CCDA and FHIR documents, with recovery evidence
|
|
5
5
|
Author: Aakash Kag, Vinay Shankar Miryala, Siva Karthik, Mohammed Rayaan
|
|
6
6
|
License: MIT
|
|
@@ -80,7 +80,7 @@ Each record separates four concerns:
|
|
|
80
80
|
"search_terms": ["BUN", "Blood Urea Nitrogen"], // text to query (raw + normalized)
|
|
81
81
|
"filters": { "specimen": "...", "property": "...", "scale": "..." }, // LOINC axis filters
|
|
82
82
|
"ecl": "< 404684003", // SNOMED: the candidate constraint
|
|
83
|
-
"crosswalk": { "from_system": "
|
|
83
|
+
"crosswalk": { "from_system": "CPT", "from_code": "80061" }, // try first (local/ICD/NDC → target). from_system is the CANONICAL system (e.g. "CPT","NDC","ICD-10-CM"), identical for CCDA and FHIR; the raw OID/URI is in evidence as *_system_raw
|
|
84
84
|
"checkdigit_correction": "2160-0", // BAD_CODE only
|
|
85
85
|
"match_key": "…", // human summary (do NOT query verbatim)
|
|
86
86
|
"suggested_action": "…"
|
|
@@ -132,7 +132,7 @@ CODE tag's — the other slot's labels are not mixed in.
|
|
|
132
132
|
"recovery": {
|
|
133
133
|
"search_terms": ["BUN", "Blood Urea Nitrogen"],
|
|
134
134
|
"filters": { "specimen": "Ser/Plas", "property": "MCnc", "scale": "Qn" },
|
|
135
|
-
"crosswalk": { "from_system": "
|
|
135
|
+
"crosswalk": { "from_system": "LOCAL", "from_code": "BUN" },
|
|
136
136
|
"match_key": "component:BUN | specimen:Ser/Plas | property:MCnc | scale:Qn | method:-",
|
|
137
137
|
"suggested_action": "crosswalk local code → target; else text + filter search"
|
|
138
138
|
},
|
|
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
|
|
2
2
|
|
|
3
3
|
setup(
|
|
4
4
|
name="aimedicalcoding",
|
|
5
|
-
version="0.3.
|
|
5
|
+
version="0.3.9",
|
|
6
6
|
author="Aakash Kag, Vinay Shankar Miryala, Siva Karthik, Mohammed Rayaan",
|
|
7
7
|
description=(
|
|
8
8
|
"Detect missing/broken clinical codes (LOINC / SNOMED CT / RxNorm / "
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/adapters/custom_json/__init__.py
RENAMED
|
File without changes
|
{aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/adapters/custom_json/adapter.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/systems/icd10cm/icdformat.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding/systems/snomed/qualifiers.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{aimedicalcoding-0.3.7 → aimedicalcoding-0.3.9}/aimedicalcoding.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|