mgbam commited on
Commit
d26962d
Β·
verified Β·
1 Parent(s): 9965499

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +90 -76
app.py CHANGED
@@ -1,134 +1,148 @@
1
  # app.py
2
 
3
- import os
4
- import streamlit as st
5
- import asyncio
6
  from pathlib import Path
 
 
7
  import pandas as pd
8
- from fpdf import FPDF
9
  import plotly.express as px
10
- import re
 
11
 
12
  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"
20
 
 
21
  def generate_pdf(papers):
22
- pdf = FPDF()
23
- pdf.add_page()
24
- pdf.set_font("Arial", size=12)
25
  pdf.cell(200, 10, "MedGenesis AI - Search Results", ln=True, align="C")
26
  pdf.ln(10)
27
  for i, p in enumerate(papers, 1):
28
  pdf.set_font("Arial", "B", 12)
29
  pdf.multi_cell(0, 10, f"{i}. {p['title']}")
30
  pdf.set_font("Arial", "", 10)
31
- pdf.multi_cell(0, 8, f"Authors: {p['authors']}\nLink: {p['link']}\nSummary: {p['summary']}\n")
 
32
  pdf.ln(2)
33
  return pdf.output(dest="S").encode("latin-1")
34
 
 
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():
56
- st.image(str(LOGO), width=100)
57
  with col2:
58
- st.markdown("## 🧬 MedGenesis AI\n*Unified Intelligence from PubMed, ArXiv, OpenFDA, UMLS, GPT‑4o*")
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()
 
1
  # app.py
2
 
3
+ import asyncio, os, re
 
 
4
  from pathlib import Path
5
+
6
+ import streamlit as st
7
  import pandas as pd
 
8
  import plotly.express as px
9
+ from fpdf import FPDF
10
+ from streamlit_agraph import agraph
11
 
12
  from mcp.orchestrator import orchestrate_search, answer_ai_question
13
+ from mcp.workspace import get_workspace, save_query
 
14
  from mcp.knowledge_graph import build_agraph
 
15
 
16
  ROOT = Path(__file__).parent
17
  LOGO = ROOT / "assets" / "logo.png"
18
 
19
+ # ------------------------- helpers -------------------------
20
  def generate_pdf(papers):
21
+ pdf = FPDF(); pdf.add_page(); pdf.set_font("Arial", size=12)
 
 
22
  pdf.cell(200, 10, "MedGenesis AI - Search Results", ln=True, align="C")
23
  pdf.ln(10)
24
  for i, p in enumerate(papers, 1):
25
  pdf.set_font("Arial", "B", 12)
26
  pdf.multi_cell(0, 10, f"{i}. {p['title']}")
27
  pdf.set_font("Arial", "", 10)
28
+ pdf.multi_cell(0, 8,
29
+ f"Authors: {p['authors']}\nLink: {p['link']}\nSummary: {p['summary']}\n")
30
  pdf.ln(2)
31
  return pdf.output(dest="S").encode("latin-1")
32
 
33
+ # ------------------------- UI -------------------------
34
  def render_ui():
35
  st.set_page_config(page_title="MedGenesis AI", layout="wide")
36
 
37
+ # ----- Sidebar ----------
38
  with st.sidebar:
39
  st.header("πŸ—‚οΈ Workspace")
40
+ for i, it in enumerate(get_workspace(), 1):
41
+ with st.expander(f"{i}. {it['query']}"):
42
+ st.write("**AI Summary:**", it["result"]["ai_summary"])
43
+ df = pd.DataFrame(it["result"]["papers"])
44
+ st.download_button("CSV", df.to_csv(index=False), f"ws_{i}.csv", "text/csv")
45
+ if not get_workspace():
46
+ st.info("Run and save searches to populate workspace.")
47
+
48
+ # ----- Header ----------
 
 
 
49
  col1, col2 = st.columns([0.15, 0.85])
50
  with col1:
51
+ if LOGO.exists(): st.image(str(LOGO), width=100)
 
52
  with col2:
53
+ st.markdown("## 🧬 MedGenesis AI")
54
+ st.write("*Unified PubMed, ArXiv, OpenFDA, UMLS, NCBI, DisGeNET, ClinicalTrials & GPT-4o*")
55
 
56
  st.markdown("---")
57
+ query = st.text_input("πŸ” Biomedical research question:", placeholder="e.g. CRISPR glioblastoma")
58
 
59
+ # ------------- Search -------------
60
+ if st.button("Run Search πŸš€") and query:
61
+ with st.spinner("Collecting literature & biomedical data…"):
62
  results = asyncio.run(orchestrate_search(query))
63
+ st.success("Completed!")
64
 
65
+ # -------- Tabs ---------
66
+ tabs = st.tabs([
67
+ "πŸ“ Results", "🧬 Genes & Variants", "πŸ’Š Clinical Trials",
68
+ "πŸ—ΊοΈ Graph", "πŸ“Š Visuals"
69
+ ])
70
 
71
+ # -- Results ----------
72
  with tabs[0]:
73
+ st.header("πŸ“š Top Papers")
74
  for i, p in enumerate(results["papers"], 1):
75
  st.markdown(f"**{i}. [{p['title']}]({p['link']})** \n*{p['authors']}* ({p['source']})")
76
+ st.markdown(f"<span style='color:gray'>{p['summary']}</span>", unsafe_allow_html=True)
77
+
78
  if st.button("Save to Workspace"):
79
+ save_query(query, results); st.success("Saved!")
80
+
81
  df = pd.DataFrame(results["papers"])
82
+ st.download_button("CSV", df.to_csv(index=False), "results.csv", "text/csv")
83
+ st.download_button("PDF", generate_pdf(results["papers"]), "results.pdf", "application/pdf")
84
+
85
  st.subheader("🧠 UMLS Concepts")
86
  for c in results["umls"]:
87
  if c.get("cui"):
88
+ st.markdown(f"- **{c['name']}** (`{c['cui']}`)")
89
+
90
  st.subheader("πŸ’Š Drug Safety (OpenFDA)")
91
  for d in results["drug_safety"]:
92
  st.json(d)
93
+
94
+ st.subheader("πŸ€– AI Summary")
95
  st.info(results["ai_summary"])
96
 
97
+ # -- Genes & Variants ----------
98
  with tabs[1]:
99
+ st.header("🧬 Gene Associations (NCBI / DisGeNET)")
100
+ for g in results["genes"]:
101
+ st.write(f"- **{g.get('name', g.get('geneid'))}** – {g.get('description','')}")
102
+ if results["gene_disease"]:
103
+ st.markdown("#### DisGeNET Disease β†’ Gene links")
104
+ st.json(results["gene_disease"][:15])
105
+ if results["mesh_definitions"]:
106
+ st.markdown("#### MeSH Definitions")
107
+ for d in results["mesh_definitions"]:
108
+ if d: st.write(f"- {d}")
109
+
110
+ # -- Clinical Trials ----------
111
+ with tabs[2]:
112
+ st.header("πŸ’Š Registered Clinical Trials")
113
+ for t in results["clinical_trials"]:
114
+ st.markdown(f"**{t['NCTId'][0]}** – {t['BriefTitle'][0]}")
115
+ st.write(f"Condition: {', '.join(t['Condition'])} | Phase: {t.get('Phase',[None])[0]} | Status: {t['OverallStatus'][0]}")
116
+
117
+ # -- Graph ----------
118
+ with tabs[3]:
119
+ search_term = st.text_input("Highlight node containing:", key="graphsearch")
120
  try:
121
+ nodes, edges, cfg = build_agraph(results["papers"], results["umls"], results["drug_safety"])
122
+ if search_term:
123
+ pat = re.compile(re.escape(search_term), re.I)
124
+ for n in nodes:
125
+ if pat.search(n.label): n.color, n.size = "#f1c40f", max(n.size, 30)
126
+ else: n.color = "#ddd"
127
+ agraph(nodes=nodes, edges=edges, config=cfg)
 
 
 
128
  except Exception as e:
129
+ st.error(f"Graph error: {e}")
130
 
131
+ # -- Visualizations ----------
132
+ with tabs[4]:
133
+ yrs = [p["published"] for p in results["papers"] if p.get("published")]
134
+ if yrs: st.plotly_chart(px.histogram(yrs, nbins=10, title="Publication Year"))
 
 
135
 
136
+ # -- Follow-up Q&A ----------
137
+ st.markdown("---")
138
+ q = st.text_input("Ask follow-up:", key="follow")
139
+ if st.button("Ask AI"):
140
+ ans = asyncio.run(answer_ai_question(q, context=query))
141
+ st.write(ans["answer"])
 
 
142
 
143
+ else:
144
+ st.info("Enter a question and press **Run Search πŸš€**")
145
 
146
+ # ------------- Run -------------
147
  if __name__ == "__main__":
148
  render_ui()