Update app.py
Browse files
app.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1 |
-
#
|
2 |
import asyncio
|
3 |
import re
|
|
|
4 |
|
5 |
import streamlit as st
|
6 |
import pandas as pd
|
@@ -13,8 +14,8 @@ from mcp.knowledge_graph import build_agraph
|
|
13 |
from mcp.graph_metrics import build_nx, get_top_hubs, get_density
|
14 |
from mcp.protocols import draft_protocol
|
15 |
|
16 |
-
#
|
17 |
-
st.set_page_config(
|
18 |
if "res" not in st.session_state:
|
19 |
st.session_state.res = None
|
20 |
|
@@ -22,8 +23,7 @@ st.title("𧬠MedGenesis AI")
|
|
22 |
llm = st.radio("LLM engine", ["openai", "gemini"], horizontal=True)
|
23 |
query = st.text_input("Enter biomedical question")
|
24 |
|
25 |
-
# PDF
|
26 |
-
|
27 |
def _make_pdf(papers):
|
28 |
pdf = FPDF()
|
29 |
pdf.add_page(); pdf.set_font("Helvetica", size=12)
|
@@ -39,7 +39,8 @@ def _make_pdf(papers):
|
|
39 |
return pdf.output(dest="S").encode("latin-1", errors="replace")
|
40 |
|
41 |
# Run search
|
42 |
-
|
|
|
43 |
with st.spinner("Gathering dataβ¦"):
|
44 |
st.session_state.res = asyncio.run(orchestrate_search(query, llm))
|
45 |
res = st.session_state.res
|
@@ -48,10 +49,15 @@ if not res:
|
|
48 |
st.stop()
|
49 |
|
50 |
# Tabs
|
51 |
-
tabs = st.tabs([
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
|
53 |
-
|
54 |
-
with tabs[0]:
|
55 |
for i, p in enumerate(res["papers"], 1):
|
56 |
st.markdown(f"**{i}. [{p['title']}]({p['link']})**")
|
57 |
st.write(p["summary"])
|
@@ -62,8 +68,8 @@ with tabs[0]:
|
|
62 |
"papers.pdf", "application/pdf")
|
63 |
st.subheader("AI summary"); st.info(res["ai_summary"])
|
64 |
|
65 |
-
#
|
66 |
-
with
|
67 |
nodes, edges, cfg = build_agraph(
|
68 |
res["papers"], res["umls"], res["drug_safety"], res["umls_relations"]
|
69 |
)
|
@@ -74,8 +80,8 @@ with tabs[1]:
|
|
74 |
n.color = "#f1c40f" if pat.search(n.label) else n.color
|
75 |
agraph(nodes, edges, cfg)
|
76 |
|
77 |
-
#
|
78 |
-
with
|
79 |
clusters = res.get("clusters", [])
|
80 |
if clusters:
|
81 |
df = pd.DataFrame({
|
@@ -85,77 +91,49 @@ with tabs[2]:
|
|
85 |
st.write("### Paper Clusters")
|
86 |
for c in sorted(set(clusters)):
|
87 |
st.write(f"**Cluster {c}**")
|
88 |
-
for t in df[df['cluster']
|
89 |
st.write(f"- {t}")
|
90 |
else:
|
91 |
st.info("No clusters to show.")
|
92 |
|
93 |
-
#
|
94 |
-
with
|
95 |
if res.get("variants"):
|
96 |
st.json(res["variants"])
|
97 |
else:
|
98 |
st.warning("No variants found. Try 'TP53' or 'BRCA1'.")
|
99 |
|
100 |
-
#
|
101 |
-
with
|
102 |
if res.get("clinical_trials"):
|
103 |
st.json(res["clinical_trials"])
|
104 |
else:
|
105 |
st.warning("No trials found. Try a disease or drug.")
|
106 |
|
107 |
-
#
|
108 |
-
with
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
st.metric("Density", f"{get_density(G):.3f}")
|
113 |
st.markdown("**Top hubs**")
|
114 |
-
for nid,
|
115 |
-
lbl = next((n.label for n in nodes if n.id
|
116 |
-
st.write(f"- {lbl}: {
|
117 |
|
118 |
-
#
|
119 |
-
with
|
120 |
years = [p.get("published","")[:4] for p in res["papers"] if p.get("published")]
|
121 |
if years:
|
122 |
st.plotly_chart(px.histogram(years, nbins=10, title="Publication Year"))
|
123 |
|
124 |
-
#
|
125 |
-
with
|
126 |
-
|
127 |
-
if st.button("Draft Protocol") and
|
128 |
with st.spinner("Generating protocolβ¦"):
|
129 |
-
|
130 |
-
|
131 |
))
|
132 |
st.subheader("Experimental Protocol")
|
133 |
-
st.write(
|
134 |
-
βββββββββββββββββββββββββββββββββββββββββββββββββββ
|
135 |
-
# In import section:
|
136 |
-
from mcp.embeddings import embed_texts, cluster_embeddings
|
137 |
-
from mcp.protocols import draft_protocol
|
138 |
-
|
139 |
-
# After creating tabs = st.tabs([...,'Clusters','Protocols']):
|
140 |
-
with tabs[-2]: # second last tab = Clusters
|
141 |
-
if res.get('clusters'):
|
142 |
-
df = pd.DataFrame({
|
143 |
-
'title': [p['title'] for p in res['papers']],
|
144 |
-
'cluster': res['clusters']
|
145 |
-
})
|
146 |
-
st.write("### Paper Clusters")
|
147 |
-
for c in sorted(set(res['clusters'])):
|
148 |
-
st.write(f"**Cluster {c}**")
|
149 |
-
for t in df[df['cluster']==c]['title']:
|
150 |
-
st.write(f"- {t}")
|
151 |
-
else:
|
152 |
-
st.info("No clusters to show.")
|
153 |
-
|
154 |
-
with tabs[-1]: # last tab = Protocols
|
155 |
-
proto_q = st.text_input("Enter hypothesis for protocol:", key="proto_q")
|
156 |
-
if st.button("Draft Protocol") and proto_q.strip():
|
157 |
-
with st.spinner("Generating protocolβ¦"):
|
158 |
-
proto = asyncio.run(draft_protocol(
|
159 |
-
proto_q, context=res['ai_summary'], llm=llm))
|
160 |
-
st.subheader("Experimental Protocol")
|
161 |
-
st.write(proto)
|
|
|
1 |
+
# app.py
|
2 |
import asyncio
|
3 |
import re
|
4 |
+
from pathlib import Path
|
5 |
|
6 |
import streamlit as st
|
7 |
import pandas as pd
|
|
|
14 |
from mcp.graph_metrics import build_nx, get_top_hubs, get_density
|
15 |
from mcp.protocols import draft_protocol
|
16 |
|
17 |
+
# Streamlit config
|
18 |
+
st.set_page_config(page_title="MedGenesis AI", layout="wide")
|
19 |
if "res" not in st.session_state:
|
20 |
st.session_state.res = None
|
21 |
|
|
|
23 |
llm = st.radio("LLM engine", ["openai", "gemini"], horizontal=True)
|
24 |
query = st.text_input("Enter biomedical question")
|
25 |
|
26 |
+
# PDF generator
|
|
|
27 |
def _make_pdf(papers):
|
28 |
pdf = FPDF()
|
29 |
pdf.add_page(); pdf.set_font("Helvetica", size=12)
|
|
|
39 |
return pdf.output(dest="S").encode("latin-1", errors="replace")
|
40 |
|
41 |
# Run search
|
42 |
+
enabled = st.button("Run Search π") and query.strip()
|
43 |
+
if enabled:
|
44 |
with st.spinner("Gathering dataβ¦"):
|
45 |
st.session_state.res = asyncio.run(orchestrate_search(query, llm))
|
46 |
res = st.session_state.res
|
|
|
49 |
st.stop()
|
50 |
|
51 |
# Tabs
|
52 |
+
tabs = st.tabs([
|
53 |
+
"Results", "Graph", "Clusters", "Variants",
|
54 |
+
"Trials", "Metrics", "Visuals", "Protocols"
|
55 |
+
])
|
56 |
+
|
57 |
+
# Results
|
58 |
+
title_tab, graph_tab, clust_tab, var_tab, trial_tab, met_tab, vis_tab, proto_tab = tabs
|
59 |
|
60 |
+
with title_tab:
|
|
|
61 |
for i, p in enumerate(res["papers"], 1):
|
62 |
st.markdown(f"**{i}. [{p['title']}]({p['link']})**")
|
63 |
st.write(p["summary"])
|
|
|
68 |
"papers.pdf", "application/pdf")
|
69 |
st.subheader("AI summary"); st.info(res["ai_summary"])
|
70 |
|
71 |
+
# Graph
|
72 |
+
with graph_tab:
|
73 |
nodes, edges, cfg = build_agraph(
|
74 |
res["papers"], res["umls"], res["drug_safety"], res["umls_relations"]
|
75 |
)
|
|
|
80 |
n.color = "#f1c40f" if pat.search(n.label) else n.color
|
81 |
agraph(nodes, edges, cfg)
|
82 |
|
83 |
+
# Clusters
|
84 |
+
with clust_tab:
|
85 |
clusters = res.get("clusters", [])
|
86 |
if clusters:
|
87 |
df = pd.DataFrame({
|
|
|
91 |
st.write("### Paper Clusters")
|
92 |
for c in sorted(set(clusters)):
|
93 |
st.write(f"**Cluster {c}**")
|
94 |
+
for t in df[df['cluster']==c]['title']:
|
95 |
st.write(f"- {t}")
|
96 |
else:
|
97 |
st.info("No clusters to show.")
|
98 |
|
99 |
+
# Variants
|
100 |
+
with var_tab:
|
101 |
if res.get("variants"):
|
102 |
st.json(res["variants"])
|
103 |
else:
|
104 |
st.warning("No variants found. Try 'TP53' or 'BRCA1'.")
|
105 |
|
106 |
+
# Trials
|
107 |
+
with trial_tab:
|
108 |
if res.get("clinical_trials"):
|
109 |
st.json(res["clinical_trials"])
|
110 |
else:
|
111 |
st.warning("No trials found. Try a disease or drug.")
|
112 |
|
113 |
+
# Metrics
|
114 |
+
with met_tab:
|
115 |
+
G = build_nx(
|
116 |
+
[n.__dict__ for n in nodes], [e.__dict__ for e in edges]
|
117 |
+
)
|
118 |
st.metric("Density", f"{get_density(G):.3f}")
|
119 |
st.markdown("**Top hubs**")
|
120 |
+
for nid, score in get_top_hubs(G):
|
121 |
+
lbl = next((n.label for n in nodes if n.id==nid), nid)
|
122 |
+
st.write(f"- {lbl}: {score:.3f}")
|
123 |
|
124 |
+
# Visuals
|
125 |
+
with vis_tab:
|
126 |
years = [p.get("published","")[:4] for p in res["papers"] if p.get("published")]
|
127 |
if years:
|
128 |
st.plotly_chart(px.histogram(years, nbins=10, title="Publication Year"))
|
129 |
|
130 |
+
# Protocols
|
131 |
+
with proto_tab:
|
132 |
+
hyp = st.text_input("Enter hypothesis for protocol:", key="proto_q")
|
133 |
+
if st.button("Draft Protocol") and hyp.strip():
|
134 |
with st.spinner("Generating protocolβ¦"):
|
135 |
+
doc = asyncio.run(draft_protocol(
|
136 |
+
hyp, context=res["ai_summary"], llm=llm
|
137 |
))
|
138 |
st.subheader("Experimental Protocol")
|
139 |
+
st.write(doc)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|