mgbam's picture
Update genesis/api_clients/umls_api.py
a2918ce verified
# 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 []