Create knowledge_graph.py
Browse files- mcp/knowledge_graph.py +59 -0
mcp/knowledge_graph.py
ADDED
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# mcp/knowledge_graph.py
|
2 |
+
|
3 |
+
from pyvis.network import Network
|
4 |
+
import tempfile
|
5 |
+
|
6 |
+
def build_knowledge_graph(papers, umls, drugs):
|
7 |
+
"""
|
8 |
+
Build and return a pyvis Network object representing the knowledge graph.
|
9 |
+
Nodes: papers, UMLS concepts, drugs.
|
10 |
+
Edges: paper–concept, paper–drug, drug–concept.
|
11 |
+
"""
|
12 |
+
net = Network(height="550px", width="100%", bgcolor="#f3eaff", font_color="#222222", notebook=False, directed=False)
|
13 |
+
net.force_atlas_2based() # More visually appealing layout
|
14 |
+
|
15 |
+
# Add UMLS concept nodes
|
16 |
+
concept_nodes = {}
|
17 |
+
for concept in umls:
|
18 |
+
if concept["cui"]:
|
19 |
+
node_id = f"concept_{concept['cui']}"
|
20 |
+
net.add_node(node_id, label=concept["name"], color="#00b894", title=f"UMLS: {concept['cui']}\n{concept['definition'] or ''}")
|
21 |
+
concept_nodes[concept['name']] = node_id
|
22 |
+
|
23 |
+
# Add drug nodes
|
24 |
+
drug_nodes = {}
|
25 |
+
for drug_report in drugs:
|
26 |
+
if isinstance(drug_report, list):
|
27 |
+
# OpenFDA can return a list of dicts
|
28 |
+
for d in drug_report:
|
29 |
+
if "safety_report_id" in d:
|
30 |
+
node_id = f"drug_{d['safety_report_id']}"
|
31 |
+
drug_name = d.get('reactions', ['drug'])[0] if d.get('reactions') else 'drug'
|
32 |
+
net.add_node(node_id, label=drug_name, color="#d35400", title=str(d))
|
33 |
+
drug_nodes[drug_name] = node_id
|
34 |
+
|
35 |
+
# Add paper nodes and edges to concepts and drugs
|
36 |
+
for i, paper in enumerate(papers, 1):
|
37 |
+
paper_id = f"paper_{i}"
|
38 |
+
net.add_node(paper_id, label=paper["title"][:40] + "...", color="#0984e3", title=f"{paper['title']}\n{paper['summary']}\n{paper['link']}")
|
39 |
+
|
40 |
+
# Link paper to concepts by presence in summary/title
|
41 |
+
for cname, concept_id in concept_nodes.items():
|
42 |
+
if cname.lower() in (paper["summary"] + paper["title"]).lower():
|
43 |
+
net.add_edge(paper_id, concept_id, color="#00b894")
|
44 |
+
|
45 |
+
# Link paper to drugs if drug name is present in summary/title
|
46 |
+
for dname, drug_id in drug_nodes.items():
|
47 |
+
if dname.lower() in (paper["summary"] + paper["title"]).lower():
|
48 |
+
net.add_edge(paper_id, drug_id, color="#d35400")
|
49 |
+
|
50 |
+
# Optionally: link concepts to drugs if name overlap
|
51 |
+
for cname, concept_id in concept_nodes.items():
|
52 |
+
for dname, drug_id in drug_nodes.items():
|
53 |
+
if cname.lower() in dname.lower() or dname.lower() in cname.lower():
|
54 |
+
net.add_edge(concept_id, drug_id, color="#636e72")
|
55 |
+
|
56 |
+
# Save and return path to HTML
|
57 |
+
temp_path = tempfile.NamedTemporaryFile(delete=False, suffix=".html").name
|
58 |
+
net.show(temp_path)
|
59 |
+
return temp_path
|