mgbam commited on
Commit
0f5d296
Β·
verified Β·
1 Parent(s): bc40121

Update mcp/knowledge_graph.py

Browse files
Files changed (1) hide show
  1. mcp/knowledge_graph.py +57 -88
mcp/knowledge_graph.py CHANGED
@@ -1,93 +1,62 @@
1
- """
2
- Graph builder for Streamlit-agraph.
3
- β€’ Safely skips bad nodes (RuntimeError / None)
4
- β€’ Colour-codes papers = #3498db (blue)
5
- drugs = #e67e22 (orange)
6
- concepts= #2ecc71 (green)
7
- """
8
-
9
- from __future__ import annotations
10
- import re
11
- from typing import List, Dict, Tuple
12
  from streamlit_agraph import Node, Edge, Config
13
-
14
- # ── colour palette ----------------------------------------------------
15
- CLR_PAPER = "#3498db"
16
- CLR_DRUG = "#e67e22"
17
- CLR_CONCEPT = "#2ecc71"
18
-
19
- def _add_node_safe(nodes: List[Node], nid: str, **kwargs) -> None:
20
- if not any(n.id == nid for n in nodes):
21
- nodes.append(Node(id=nid, **kwargs))
22
-
23
- def build_agraph(papers: List[Dict],
24
- umls : List[Dict],
25
- safety: List[Dict]) -> Tuple[List[Node], List[Edge], Config]:
26
- """
27
- Map MedGenesis payload β†’ (nodes, edges, config) for Streamlit-agraph.
28
- """
29
-
30
- nodes: List[Node] = []
31
- edges: List[Edge] = []
32
-
33
- # 1 UMLS CONCEPTS ---------------------------------------------------
34
- for concept in umls:
35
- try:
36
- cui = concept.get("cui")
37
- name = concept.get("name", "")
38
- if cui and name:
39
- cid = f"CUI_{cui}"
40
- _add_node_safe(nodes, cid, label=name, size=25, color=CLR_CONCEPT)
41
- except Exception:
42
- continue # malformed concept
43
-
44
- # 2 DRUGS (OpenFDA) -------------------------------------------------
45
- drug_label_pairs: List[Tuple[str, str]] = []
46
- for i, rec in enumerate(safety):
47
- if not rec: # may be {} if rate-limited
48
- continue
49
- drug_name = (rec.get("drug_name") or
50
- rec.get("patient", {}).get("drug") or
51
- rec.get("medicinalproduct") or
52
- f"unknown_{i}")
53
- did = f"DRUG_{i}"
54
- drug_label_pairs.append((did, drug_name))
55
- _add_node_safe(nodes, did, label=drug_name, size=22, color=CLR_DRUG)
56
-
57
- # 3 PAPERS ----------------------------------------------------------
58
- for idx, p in enumerate(papers):
59
- pid = f"PAPER_{idx}"
60
- _add_node_safe(nodes, pid,
61
- label=f"P{idx+1}",
62
- tooltip=p.get("title", ""),
63
- size=15,
64
- color=CLR_PAPER)
65
-
66
- plain = (p.get("title", "") + " " + p.get("summary", "")).lower()
67
-
68
- # (i) concept edges
69
- for concept in umls:
70
- name = concept.get("name", "")
71
- cui = concept.get("cui")
72
- if name and cui and name.lower() in plain:
73
- edges.append(Edge(source=pid,
74
- target=f"CUI_{cui}",
75
- label="mentions"))
76
-
77
- # (ii) drug edges
78
- for did, dname in drug_label_pairs:
79
- if dname.lower() in plain:
80
- edges.append(Edge(source=pid,
81
- target=did,
82
- label="mentions"))
83
 
84
  cfg = Config(
85
- width = "100%",
86
- height = 600,
87
- directed = False,
88
- nodeHighlightBehavior = True,
89
- highlightColor = "#f1c40f",
90
- collapsible = True,
91
- node = {"labelProperty": "label"}
92
  )
93
  return nodes, edges, cfg
 
 
 
 
 
 
 
 
 
 
 
 
1
  from streamlit_agraph import Node, Edge, Config
2
+ import re, itertools
3
+ from typing import List, Tuple
4
+
5
+ _GREEN = "#00b894"
6
+ _ORANGE = "#d35400"
7
+ _BLUE = "#0984e3"
8
+
9
+ def _safe(node_like):
10
+ """Return empty dict if node_like is an Exception."""
11
+ return node_like if isinstance(node_like, dict) else {}
12
+
13
+ def build_agraph(
14
+ papers: List[dict],
15
+ umls: List[dict],
16
+ drug_safety: List[dict],
17
+ ) -> Tuple[List[Node], List[Edge], Config]:
18
+ nodes, edges = [], []
19
+
20
+ # UMLS concept nodes
21
+ for c in filter(bool, map(_safe, umls)):
22
+ cui, name = c.get("cui"), c.get("name", "")
23
+ if cui and name:
24
+ nid = f"cui:{cui}"
25
+ nodes.append(Node(id=nid, label=name, color=_GREEN, size=25))
26
+
27
+ # Drug nodes
28
+ def _drug_name(d: dict) -> str:
29
+ return (
30
+ d.get("drug_name")
31
+ or d.get("patient", {}).get("drug", "")
32
+ or d.get("medicinalproduct", "")
33
+ )
34
+
35
+ for idx, rec in enumerate(itertools.chain.from_iterable(
36
+ [r if isinstance(r, list) else [r] for r in drug_safety])):
37
+ dn = _drug_name(rec) or f"drug_{idx}"
38
+ did = f"drug_{idx}"
39
+ nodes.append(Node(id=did, label=dn, color=_ORANGE, size=25))
40
+
41
+ # Paper nodes
42
+ for i, p in enumerate(papers, 1):
43
+ pid = f"paper_{i}"
44
+ nodes.append(Node(id=pid, label=f"P{i}", tooltip=p["title"], color=_BLUE, size=15))
45
+
46
+ txt = f"{p['title']} {p['summary']}".lower()
47
+ # link ↔ concepts
48
+ for c in filter(bool, map(_safe, umls)):
49
+ if (name := c.get("name", "")).lower() in txt and c.get("cui"):
50
+ edges.append(Edge(source=pid, target=f"cui:{c['cui']}", label="mentions"))
51
+ # link ↔ drugs
52
+ for n in nodes:
53
+ if n.id.startswith("drug_") and n.label.lower() in txt:
54
+ edges.append(Edge(source=pid, target=n.id, label="mentions"))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
  cfg = Config(
57
+ width="100%", height="600px", directed=False,
58
+ node={"labelProperty": "label"},
59
+ nodeHighlightBehavior=True, highlightColor="#f1c40f",
60
+ collapsible=True,
 
 
 
61
  )
62
  return nodes, edges, cfg