Spaces:
Sleeping
Sleeping
# genesis/api_clients/umls_api.py | |
import os | |
import requests | |
from typing import List, Dict, Optional | |
UMLS_API_KEY = os.getenv("UMLS_API_KEY") # Your UMLS API key from NIH UTS | |
UMLS_AUTH_ENDPOINT = "https://utslogin.nlm.nih.gov/cas/v1/api-key" | |
UMLS_BASE = "https://uts-ws.nlm.nih.gov/rest" | |
session = requests.Session() | |
# ------------------------- | |
# Authentication Helpers | |
# ------------------------- | |
def get_umls_ticket_granting_ticket() -> str: | |
""" | |
Get the Ticket Granting Ticket (TGT) for UMLS API authentication. | |
""" | |
if not UMLS_API_KEY: | |
raise ValueError("UMLS API key not found in environment variables.") | |
params = {"apikey": UMLS_API_KEY} | |
r = session.post(UMLS_AUTH_ENDPOINT, data=params) | |
r.raise_for_status() | |
# Extract TGT location from XML | |
if "location" in r.headers: | |
return r.headers["location"] | |
# Fallback: parse XML body | |
from xml.etree import ElementTree as ET | |
root = ET.fromstring(r.text) | |
form = root.find(".//form") | |
if form is not None and "action" in form.attrib: | |
return form.attrib["action"] | |
raise RuntimeError("Unable to retrieve UMLS TGT. Check API key or response format.") | |
def get_umls_service_ticket(tgt: str) -> str: | |
""" | |
Use TGT to request a one-time Service Ticket (ST). | |
""" | |
params = {"service": "http://umlsks.nlm.nih.gov"} | |
r = session.post(tgt, data=params) | |
r.raise_for_status() | |
return r.text.strip() | |
# ------------------------- | |
# Search Concepts | |
# ------------------------- | |
def search_umls(term: str, page_size: int = 5) -> List[Dict]: | |
""" | |
Search the UMLS Metathesaurus for a given term. | |
Returns a list of concepts with CUI and metadata. | |
""" | |
tgt = get_umls_ticket_granting_ticket() | |
st = get_umls_service_ticket(tgt) | |
params = { | |
"string": term, | |
"ticket": st, | |
"pageSize": page_size | |
} | |
r = session.get(f"{UMLS_BASE}/search/current", params=params) | |
r.raise_for_status() | |
results = r.json().get("result", {}).get("results", []) | |
concepts = [] | |
for res in results: | |
if res.get("ui") != "NONE": | |
concepts.append({ | |
"name": res.get("name"), | |
"cui": res.get("ui"), | |
"rootSource": res.get("rootSource") | |
}) | |
return concepts | |
# ------------------------- | |
# Concept Details | |
# ------------------------- | |
def get_concept_details(cui: str) -> Dict: | |
""" | |
Fetch details for a UMLS CUI (definitions, atoms, semantic types). | |
""" | |
tgt = get_umls_ticket_granting_ticket() | |
st = get_umls_service_ticket(tgt) | |
r = session.get(f"{UMLS_BASE}/content/current/CUI/{cui}", params={"ticket": st}) | |
r.raise_for_status() | |
return r.json().get("result", {}) | |
# ------------------------- | |
# Related Concepts | |
# ------------------------- | |
def get_related_concepts(cui: str) -> List[Dict]: | |
""" | |
Fetch related concepts for a given CUI. | |
""" | |
tgt = get_umls_ticket_granting_ticket() | |
st = get_umls_service_ticket(tgt) | |
r = session.get(f"{UMLS_BASE}/content/current/CUI/{cui}/relations", params={"ticket": st}) | |
r.raise_for_status() | |
relations = r.json().get("result", []) | |
related = [] | |
for rel in relations: | |
related.append({ | |
"relatedCUI": rel.get("relatedId"), | |
"relationLabel": rel.get("relationLabel"), | |
"relatedName": rel.get("relatedIdName") | |
}) | |
return related | |
# ------------------------- | |
# Term β Semantic Network | |
# ------------------------- | |
def umls_network(term: str) -> Dict: | |
""" | |
Build a semantic network for a term: concepts, details, and related CUIs. | |
""" | |
concepts = search_umls(term) | |
network = [] | |
for concept in concepts: | |
cui = concept["cui"] | |
details = get_concept_details(cui) | |
related = get_related_concepts(cui) | |
network.append({ | |
"concept": concept, | |
"details": details, | |
"related": related | |
}) | |
return { | |
"term": term, | |
"network": network | |
} | |
# ------------------------- | |
# Expansion Helper for pipeline.py | |
# ------------------------- | |
def expand_with_umls(term: str, max_results: int = 5) -> List[str]: | |
""" | |
Expand a biomedical term into related synonyms & preferred names from UMLS. | |
Used by pipeline.py for ontology enrichment. | |
""" | |
try: | |
concepts = search_umls(term, page_size=max_results) | |
expanded = [] | |
for c in concepts: | |
if c["name"] and c["name"].lower() != term.lower(): | |
expanded.append(c["name"]) | |
return list(set(expanded)) | |
except Exception as e: | |
print(f"[UMLS] Expansion failed for '{term}': {e}") | |
return [] | |