From 4bac7373c4dc1441b69a48ea2056d4832350c801 Mon Sep 17 00:00:00 2001 From: rhdolin Date: Thu, 24 Oct 2024 14:00:32 -0700 Subject: [PATCH 1/3] Add terminology translation utility --- app/api_spec.yml | 36 +++++++++++++ app/utilities_endpoints.py | 100 +++++++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+) diff --git a/app/api_spec.yml b/app/api_spec.yml index 48576307d..a2684daff 100644 --- a/app/api_spec.yml +++ b/app/api_spec.yml @@ -1280,6 +1280,7 @@ paths: type: string pattern: '^\s*[Nn][Pp]_\d{4,10}(\.)?(\d{1,2})?\s*$' example: "NP_000005.3" + /utilities/find-the-gene: get: description: |- @@ -1305,6 +1306,41 @@ paths: pattern: '^\s*[Nn][Cc]_\d{4,10}(\.)(\d{1,2}):\d{1,10}-\d{1,10}\s*$' example: "NC_000001.11:11794399-11794400" + /utilities/terminology-translation: + get: + description: |- + This utility demonstrates terminology translations SNOMED to MedGen and DiseaseOntology; ICD10 to MedGen and DiseaseOntology; RxNorm to NCIt. + summary: "Translate from one code system to another" + operationId: "app.utilities_endpoints.translate_terminology" + tags: + - "Operations Utilities (not part of balloted HL7 Operations)" + responses: + '200': + description: "Returns matching codes in target code system(s)." + content: + application/json: + schema: + type: object + parameters: + - name: codeSystem + in: query + required: true + description: Code system for code to be translated. + schema: + type: string + enum: + - "http://www.nlm.nih.gov/research/umls/rxnorm" + - "http://snomed.info/sct" + - "http://hl7.org/fhir/sid/icd-10" + example: "http://snomed.info/sct" + - name: code + in: query + schema: + type: string + example: '126949007' + required: true + description: The code to be translated. + tags: - name: Subject Genotype Operations - name: Subject Phenotype Operations diff --git a/app/utilities_endpoints.py b/app/utilities_endpoints.py index c2f278ff3..acc6b9955 100644 --- a/app/utilities_endpoints.py +++ b/app/utilities_endpoints.py @@ -1,6 +1,13 @@ from flask import abort, jsonify from collections import OrderedDict from app import common +import requests + + +def fetch_concept_map(mapID): + url = f"http://hapi.fhir.org/baseR4/ConceptMap/{mapID}" + headers = {'Accept': 'application/json'} + return requests.get(url, headers=headers) def get_feature_coordinates( @@ -189,3 +196,96 @@ def find_the_gene(range=None): output.append(ord_dict) return (jsonify(output)) + + +def translate_terminology(codeSystem, code): + # validate input parameters + if codeSystem not in ['http://www.nlm.nih.gov/research/umls/rxnorm', 'http://snomed.info/sct', 'http://hl7.org/fhir/sid/icd-10']: + return "unrecognized code system" + response = [{}] + + # process rxnorm input + if codeSystem == 'http://www.nlm.nih.gov/research/umls/rxnorm': + MapRxNorm = fetch_concept_map(44872525) + if MapRxNorm.status_code == 200: + MapRxNorm = MapRxNorm.json() + for element in MapRxNorm["group"][0]["element"]: + if element["code"] == code: + response[0]["outcome"] = 'match found' + response[0]["code"] = element["target"][0]["code"] + response[0]["system"] = 'https://ncithesaurus.nci.nih.gov/' + response[0]["display"] = element["target"][0]["display"] + return response + response[0]["outcome"] = 'no match found' + response[0]["system"] = 'https://ncithesaurus.nci.nih.gov/' + return response + else: + return "server down" + + # process snomed input, return disease ontology code AND medgen + if codeSystem == 'http://snomed.info/sct': + Mapsnomed = fetch_concept_map(44947014) + if Mapsnomed.status_code == 200: + Mapsnomed = Mapsnomed.json() + for element in Mapsnomed["group"][0]["element"]: + if element["code"] == code: + response[0]["outcome"] = 'match found' + response[0]["code"] = element["target"][0]["code"] + response[0]["system"] = 'https://disease-ontology.org/' + response[0]["display"] = element["target"][0]["display"] + break + response[0]["outcome"] = 'no match found' + response[0]["system"] = 'https://disease-ontology.org/' + else: + return "server down" + + Mapsnomed = fetch_concept_map(44872524) + if Mapsnomed.status_code == 200: + Mapsnomed = Mapsnomed.json() + response.append({}) + for element in Mapsnomed["group"][0]["element"]: + if element["code"] == code: + response[1]["outcome"] = 'match found' + response[1]["code"] = element["target"][0]["code"] + response[1]["system"] = 'https://www.ncbi.nlm.nih.gov/medgen/' + response[1]["display"] = element["target"][0]["display"] + break + response[1]["outcome"] = 'no match found' + response[1]["system"] = 'https://www.ncbi.nlm.nih.gov/medgen/' + else: + return "server down" + return response + + # process ICD10 input, return disease ontology AND medgen codes + if codeSystem == 'http://hl7.org/fhir/sid/icd-10': + MapICD10 = fetch_concept_map(44872527) + if MapICD10.status_code == 200: + MapICD10 = MapICD10.json() + for element in MapICD10["group"][0]["element"]: + if element["code"] == code: + response[0]["outcome"] = 'match found' + response[0]["code"] = element["target"][0]["code"] + response[0]["system"] = 'https://disease-ontology.org/' + response[0]["display"] = element["target"][0]["display"] + break + response[0]["outcome"] = 'no match found' + response[0]["system"] = 'https://disease-ontology.org/' + else: + return "server down" + + MapICD10 = fetch_concept_map(44872523) + if MapICD10.status_code == 200: + MapICD10 = MapICD10.json() + response.append({}) + for element in MapICD10["group"][0]["element"]: + if element["code"] == code: + response[1]["outcome"] = "match found" + response[1]["code"] = element["target"][0]["code"] + response[1]["system"] = "https://www.ncbi.nlm.nih.gov/medgen/" + response[1]["display"] = element["target"][0]["display"] + break + response[1]["outcome"] = "no match found" + response[1]["system"] = "https://www.ncbi.nlm.nih.gov/medgen/" + else: + return "Server down" + return response From aaea66c493bac2656347a2e67f37b4c0ec305e04 Mon Sep 17 00:00:00 2001 From: rhdolin Date: Thu, 7 Nov 2024 13:09:16 -0800 Subject: [PATCH 2/3] ICD10 normalization --- app/utilities_endpoints.py | 1 + 1 file changed, 1 insertion(+) diff --git a/app/utilities_endpoints.py b/app/utilities_endpoints.py index acc6b9955..895ce9aff 100644 --- a/app/utilities_endpoints.py +++ b/app/utilities_endpoints.py @@ -258,6 +258,7 @@ def translate_terminology(codeSystem, code): # process ICD10 input, return disease ontology AND medgen codes if codeSystem == 'http://hl7.org/fhir/sid/icd-10': + code = code.upper().replace(".", "") MapICD10 = fetch_concept_map(44872527) if MapICD10.status_code == 200: MapICD10 = MapICD10.json() From 0f730dba93f6ea8cc4f786258ced41296e33895e Mon Sep 17 00:00:00 2001 From: rhdolin Date: Thu, 7 Nov 2024 13:48:28 -0800 Subject: [PATCH 3/3] update terminology utility --- app/utilities_endpoints.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/utilities_endpoints.py b/app/utilities_endpoints.py index 895ce9aff..7e5cba29d 100644 --- a/app/utilities_endpoints.py +++ b/app/utilities_endpoints.py @@ -220,7 +220,7 @@ def translate_terminology(codeSystem, code): response[0]["system"] = 'https://ncithesaurus.nci.nih.gov/' return response else: - return "server down" + abort(500, "HAPI server error") # process snomed input, return disease ontology code AND medgen if codeSystem == 'http://snomed.info/sct': @@ -237,7 +237,7 @@ def translate_terminology(codeSystem, code): response[0]["outcome"] = 'no match found' response[0]["system"] = 'https://disease-ontology.org/' else: - return "server down" + abort(500, "HAPI server error") Mapsnomed = fetch_concept_map(44872524) if Mapsnomed.status_code == 200: @@ -253,7 +253,7 @@ def translate_terminology(codeSystem, code): response[1]["outcome"] = 'no match found' response[1]["system"] = 'https://www.ncbi.nlm.nih.gov/medgen/' else: - return "server down" + abort(500, "HAPI server error") return response # process ICD10 input, return disease ontology AND medgen codes @@ -272,7 +272,7 @@ def translate_terminology(codeSystem, code): response[0]["outcome"] = 'no match found' response[0]["system"] = 'https://disease-ontology.org/' else: - return "server down" + abort(500, "HAPI server error") MapICD10 = fetch_concept_map(44872523) if MapICD10.status_code == 200: @@ -288,5 +288,5 @@ def translate_terminology(codeSystem, code): response[1]["outcome"] = "no match found" response[1]["system"] = "https://www.ncbi.nlm.nih.gov/medgen/" else: - return "Server down" + abort(500, "HAPI server error") return response