Update app.py
Browse files
app.py
CHANGED
@@ -13,7 +13,7 @@ from mcp.orchestrator import orchestrate_search, answer_ai_question
|
|
13 |
from mcp.schemas import UnifiedSearchInput, UnifiedSearchResult
|
14 |
from mcp.workspace import get_workspace, save_query
|
15 |
from mcp.knowledge_graph import build_agraph
|
16 |
-
from streamlit_agraph import agraph
|
17 |
|
18 |
ROOT = Path(__file__).parent
|
19 |
LOGO = ROOT / "assets" / "logo.png"
|
@@ -35,17 +35,21 @@ def generate_pdf(papers):
|
|
35 |
def render_ui():
|
36 |
st.set_page_config(page_title="MedGenesis AI", layout="wide")
|
37 |
|
|
|
38 |
with st.sidebar:
|
39 |
st.header("ποΈ Workspace")
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
st.
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
|
|
|
|
|
|
49 |
col1, col2 = st.columns([0.15, 0.85])
|
50 |
with col1:
|
51 |
if LOGO.exists():
|
@@ -55,69 +59,76 @@ def render_ui():
|
|
55 |
st.caption("Built by Oluwafemi Idiakhoa β’ Hugging Face Spaces")
|
56 |
|
57 |
st.markdown("---")
|
58 |
-
query = st.text_input("π Enter research question:", placeholder="e.g. CRISPR treatments for glioblastoma")
|
59 |
|
60 |
results = None
|
61 |
if st.button("Run Search π"):
|
62 |
-
with st.spinner("
|
63 |
results = asyncio.run(orchestrate_search(query))
|
64 |
-
st.success("Search complete")
|
65 |
|
66 |
if results:
|
67 |
tabs = st.tabs(["π Results", "πΊοΈ Knowledge Graph", "π Visualizations"])
|
68 |
|
|
|
69 |
with tabs[0]:
|
70 |
-
st.header("π Papers")
|
71 |
for i, p in enumerate(results["papers"], 1):
|
72 |
-
st.markdown(f"**{i}. [{p['title']}]({p['link']})**
|
73 |
st.markdown(f"<div style='color:gray'>{p['summary']}</div>", unsafe_allow_html=True)
|
74 |
if st.button("Save to Workspace"):
|
75 |
-
save_query(query, results)
|
|
|
76 |
df = pd.DataFrame(results["papers"])
|
77 |
-
st.download_button("π₯ CSV", df.to_csv(index=False), "results.csv", "text/csv")
|
78 |
pdf = generate_pdf(results["papers"])
|
79 |
-
st.download_button("π PDF", pdf, "results.pdf", "application/pdf")
|
80 |
st.subheader("π§ UMLS Concepts")
|
81 |
for c in results["umls"]:
|
82 |
if c.get("cui"):
|
83 |
-
st.markdown(f"- **{c['name']}** (CUI:{c['cui']}): {c.get('definition','')}")
|
84 |
-
st.subheader("π Drug Safety")
|
85 |
for d in results["drug_safety"]:
|
86 |
st.json(d)
|
87 |
-
st.subheader("π€ AI Summary")
|
88 |
st.info(results["ai_summary"])
|
89 |
|
|
|
90 |
with tabs[1]:
|
91 |
-
st.header("
|
92 |
-
search_term = st.text_input("Highlight
|
93 |
try:
|
94 |
nodes, edges, config = build_agraph(results["papers"], results["umls"], results["drug_safety"])
|
95 |
-
if search_term:
|
96 |
-
|
97 |
for node in nodes:
|
98 |
-
if
|
99 |
-
node.color = "#f1c40f"
|
|
|
100 |
else:
|
101 |
node.color = "#ddd"
|
102 |
agraph(nodes=nodes, edges=edges, config=config)
|
103 |
except Exception as e:
|
104 |
-
st.warning("
|
105 |
|
|
|
106 |
with tabs[2]:
|
107 |
-
|
108 |
-
if
|
109 |
-
|
|
|
110 |
|
|
|
111 |
st.markdown("---")
|
112 |
-
st.subheader("π¬ Ask
|
113 |
-
|
114 |
if st.button("Ask AI"):
|
115 |
-
with st.spinner("
|
116 |
-
|
117 |
-
st.write(
|
118 |
|
119 |
st.markdown("---")
|
120 |
-
st.caption("β¨ Built by Oluwafemi Idiakhoa β’ Powered by Streamlit
|
121 |
|
122 |
if __name__ == "__main__":
|
123 |
render_ui()
|
|
|
13 |
from mcp.schemas import UnifiedSearchInput, UnifiedSearchResult
|
14 |
from mcp.workspace import get_workspace, save_query
|
15 |
from mcp.knowledge_graph import build_agraph
|
16 |
+
from streamlit_agraph import agraph
|
17 |
|
18 |
ROOT = Path(__file__).parent
|
19 |
LOGO = ROOT / "assets" / "logo.png"
|
|
|
35 |
def render_ui():
|
36 |
st.set_page_config(page_title="MedGenesis AI", layout="wide")
|
37 |
|
38 |
+
# Workspace in sidebar
|
39 |
with st.sidebar:
|
40 |
st.header("ποΈ Workspace")
|
41 |
+
ws = get_workspace()
|
42 |
+
if ws:
|
43 |
+
for i, item in enumerate(ws, 1):
|
44 |
+
with st.expander(f"{i}. {item['query']}"):
|
45 |
+
st.write("**AI Summary:**", item["result"]["ai_summary"])
|
46 |
+
st.write("**Top Paper:**", item["result"]["papers"][0]["title"] if item["result"]["papers"] else "None")
|
47 |
+
df = pd.DataFrame(item["result"]["papers"])
|
48 |
+
st.download_button("π₯ CSV", df.to_csv(index=False), f"query_{i}.csv", "text/csv")
|
49 |
+
else:
|
50 |
+
st.info("Run & save searches here.")
|
51 |
+
|
52 |
+
# Header and logo
|
53 |
col1, col2 = st.columns([0.15, 0.85])
|
54 |
with col1:
|
55 |
if LOGO.exists():
|
|
|
59 |
st.caption("Built by Oluwafemi Idiakhoa β’ Hugging Face Spaces")
|
60 |
|
61 |
st.markdown("---")
|
62 |
+
query = st.text_input("π Enter biomedical research question:", placeholder="e.g. CRISPR treatments for glioblastoma")
|
63 |
|
64 |
results = None
|
65 |
if st.button("Run Search π"):
|
66 |
+
with st.spinner("Gathering and analyzing data..."):
|
67 |
results = asyncio.run(orchestrate_search(query))
|
68 |
+
st.success("β
Search complete")
|
69 |
|
70 |
if results:
|
71 |
tabs = st.tabs(["π Results", "πΊοΈ Knowledge Graph", "π Visualizations"])
|
72 |
|
73 |
+
# Tab 1: Results
|
74 |
with tabs[0]:
|
75 |
+
st.header("π Most Relevant Papers")
|
76 |
for i, p in enumerate(results["papers"], 1):
|
77 |
+
st.markdown(f"**{i}. [{p['title']}]({p['link']})** \n*{p['authors']}* ({p['source']})")
|
78 |
st.markdown(f"<div style='color:gray'>{p['summary']}</div>", unsafe_allow_html=True)
|
79 |
if st.button("Save to Workspace"):
|
80 |
+
save_query(query, results)
|
81 |
+
st.success("Saved to workspace!")
|
82 |
df = pd.DataFrame(results["papers"])
|
83 |
+
st.download_button("π₯ Download CSV", df.to_csv(index=False), "results.csv", "text/csv")
|
84 |
pdf = generate_pdf(results["papers"])
|
85 |
+
st.download_button("π Download PDF", pdf, "results.pdf", "application/pdf")
|
86 |
st.subheader("π§ UMLS Concepts")
|
87 |
for c in results["umls"]:
|
88 |
if c.get("cui"):
|
89 |
+
st.markdown(f"- **{c['name']}** (CUI: `{c['cui']}`): {c.get('definition','No definition')}")
|
90 |
+
st.subheader("π Drug Safety (OpenFDA)")
|
91 |
for d in results["drug_safety"]:
|
92 |
st.json(d)
|
93 |
+
st.subheader("π€ AI-Powered Summary")
|
94 |
st.info(results["ai_summary"])
|
95 |
|
96 |
+
# Tab 2: Knowledge Graph (with Node Search Highlight)
|
97 |
with tabs[1]:
|
98 |
+
st.header("πΊοΈ Knowledge Graph Explorer")
|
99 |
+
search_term = st.text_input("π Highlight nodes containing:", value="")
|
100 |
try:
|
101 |
nodes, edges, config = build_agraph(results["papers"], results["umls"], results["drug_safety"])
|
102 |
+
if search_term.strip():
|
103 |
+
pattern = re.compile(re.escape(search_term), re.IGNORECASE)
|
104 |
for node in nodes:
|
105 |
+
if pattern.search(node.label) or (hasattr(node, "tooltip") and pattern.search(getattr(node, "tooltip", ""))):
|
106 |
+
node.color = "#f1c40f"
|
107 |
+
node.size = max(node.size, 30)
|
108 |
else:
|
109 |
node.color = "#ddd"
|
110 |
agraph(nodes=nodes, edges=edges, config=config)
|
111 |
except Exception as e:
|
112 |
+
st.warning("Knowledge graph unavailable: " + str(e))
|
113 |
|
114 |
+
# Tab 3: Visualizations
|
115 |
with tabs[2]:
|
116 |
+
pub_years = [p["published"] for p in results["papers"] if p.get("published")]
|
117 |
+
if pub_years:
|
118 |
+
fig = px.histogram(pub_years, nbins=10, title="Publication Year Distribution")
|
119 |
+
st.plotly_chart(fig)
|
120 |
|
121 |
+
# Follow-up AI Q&A
|
122 |
st.markdown("---")
|
123 |
+
st.subheader("π¬ Ask a Follow-up Question")
|
124 |
+
follow_up = st.text_input("Based on above:", placeholder="e.g. What's the most promising therapy?")
|
125 |
if st.button("Ask AI"):
|
126 |
+
with st.spinner("Analyzing..."):
|
127 |
+
ai_ans = asyncio.run(answer_ai_question(follow_up, context=query))
|
128 |
+
st.write(ai_ans.get("answer", ai_ans))
|
129 |
|
130 |
st.markdown("---")
|
131 |
+
st.caption("β¨ Built by Oluwafemi Idiakhoa β’ Powered by FastAPI, Streamlit, OpenAI, UMLS, OpenFDA, NCBI")
|
132 |
|
133 |
if __name__ == "__main__":
|
134 |
render_ui()
|