mgbam commited on
Commit
a4f7e5c
Β·
verified Β·
1 Parent(s): b8feebb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +80 -136
app.py CHANGED
@@ -1,10 +1,8 @@
1
- # app.py β€” MedGenesis AI (CPU edition)
2
 
3
  import asyncio, re
4
  from pathlib import Path
5
- import streamlit as st
6
- import pandas as pd
7
- import plotly.express as px
8
  from fpdf import FPDF
9
  from streamlit_agraph import agraph
10
 
@@ -14,165 +12,111 @@ from mcp.knowledge_graph import build_agraph
14
  from mcp.graph_metrics import build_nx, get_top_hubs, get_density
15
  from mcp.alerts import check_alerts
16
 
17
- ROOT = Path(__file__).parent
18
- LOGO = ROOT / "assets" / "logo.png"
19
-
20
- # ---------------------------------------------------------------------
21
- def pdf_from_papers(papers):
22
- pdf = FPDF(); pdf.add_page(); pdf.set_font("Arial", size=12)
23
- pdf.cell(200, 10, "MedGenesis AI β€” Results", ln=True, align="C"); pdf.ln(8)
24
- for i, p in enumerate(papers, 1):
25
- pdf.set_font("Arial", "B", 12)
26
- pdf.multi_cell(0, 8, f"{i}. {p['title']}")
27
- pdf.set_font("Arial", "", 9)
28
- pdf.multi_cell(0, 6, f"{p['authors']}\n{p['summary']}\n{p['link']}\n")
29
- pdf.ln(2)
30
  return pdf.output(dest="S").encode("latin-1")
31
 
32
- # ---------------------------------------------------------------------
33
- def sidebar_workspace():
34
  with st.sidebar:
35
  st.header("πŸ—‚οΈ Workspace")
36
- ws = get_workspace()
37
- if not ws:
38
- st.info("Run a search and click **Save** to build your workspace.")
39
- return
40
- for i, item in enumerate(ws, 1):
41
  with st.expander(f"{i}. {item['query']}"):
42
- st.write("**AI Summary**:", item["result"]["ai_summary"])
43
- df = pd.DataFrame(item["result"]["papers"])
44
- st.download_button("πŸ“₯ CSV", df.to_csv(index=False),
45
- f"workspace_{i}.csv", "text/csv")
46
 
47
- # ---------------------------------------------------------------------
48
  def render_ui():
49
- st.set_page_config(page_title="MedGenesis AI", layout="wide")
 
50
 
51
- # πŸ”” quick alert check
52
- saved_q = [q["query"] for q in get_workspace()]
53
- if saved_q:
54
- try:
55
- alerts = asyncio.run(check_alerts(saved_q))
56
- if alerts:
57
- with st.sidebar:
58
- st.subheader("πŸ”” New Papers")
59
- for q, links in alerts.items():
60
- st.write(f"**{q}** – {len(links)} new")
61
- except Exception as e:
62
- st.sidebar.warning(f"Alert check failed: {e}")
63
-
64
- sidebar_workspace()
65
-
66
- # Header
67
- col1, col2 = st.columns([0.15, 0.85])
68
  with col1:
69
  if LOGO.exists(): st.image(str(LOGO), width=100)
70
  with col2:
71
  st.markdown("## 🧬 **MedGenesis AI**")
72
- st.caption("PubMedΒ·ArXivΒ·OpenFDAΒ·UMLSΒ·NCBIΒ·DisGeNETΒ·ClinicalTrialsΒ·GPT-4o")
73
 
74
- st.markdown("---")
75
- query = st.text_input("πŸ” Ask your biomedical question:",
76
- placeholder="e.g. CRISPR for glioblastoma")
77
 
78
- # -----------------------------------------------------------------
79
- if st.button("Run Search πŸš€") and query:
80
- with st.spinner("Synthesizing multi-source biomedical intel…"):
81
- res = asyncio.run(orchestrate_search(query))
82
- st.success("Ready!")
 
 
 
83
 
84
- tabs = st.tabs([
85
- "Results", "Genes", "Trials", "Graph", "Metrics", "Visuals"
86
- ])
 
 
87
 
88
- # ----------- RESULTS -----------------
 
 
89
  with tabs[0]:
90
- st.header("πŸ“š Literature")
91
- for i, p in enumerate(res["papers"], 1):
92
- st.markdown(f"**{i}. [{p['title']}]({p['link']})**  *{p['authors']}*")
93
- st.markdown(f"<span style='color:gray'>{p['summary']}</span>",
94
- unsafe_allow_html=True)
95
-
96
- colA, colB = st.columns(2)
97
- with colA:
98
- if st.button("πŸ’Ύ Save to Workspace"):
99
- save_query(query, res); st.success("Saved!")
100
- with colB:
101
- st.download_button("πŸ“₯ CSV", pd.DataFrame(res["papers"]).to_csv(index=False),
102
- "papers.csv", "text/csv")
103
-
104
- st.download_button("πŸ“„ PDF", pdf_from_papers(res["papers"]),
105
- "papers.pdf", "application/pdf")
106
-
107
- st.subheader("🧠 UMLS")
108
- for c in res["umls"]:
109
- if c.get("cui"): st.write(f"- **{c['name']}** ({c['cui']})")
110
-
111
- st.subheader("πŸ’Š OpenFDA Safety")
112
- for d in res["drug_safety"]: st.json(d)
113
-
114
- st.subheader("πŸ€– AI Summary")
115
  st.info(res["ai_summary"])
 
116
 
117
- # ----------- GENES & VARIANTS --------
118
  with tabs[1]:
119
- st.header("🧬 Gene Signals")
120
- for g in res["genes"]:
121
- st.write(f"- **{g.get('name', g.get('geneid'))}** – {g.get('description','')}")
122
- if res["gene_disease"]:
123
- st.markdown("### DisGeNET Links"); st.json(res["gene_disease"][:15])
124
- if res["mesh_defs"]:
125
- st.markdown("### MeSH Definitions")
126
- for d in res["mesh_defs"]: st.write("-", d)
127
-
128
- # ----------- TRIALS ------------------
129
  with tabs[2]:
130
- st.header("πŸ’Š Clinical Trials")
131
- if not res["clinical_trials"]:
132
- st.info("No trials retrieved (rate-limited or none found).")
133
- for t in res["clinical_trials"]:
134
- st.markdown(f"**{t['NCTId'][0]}** – {t['BriefTitle'][0]}")
135
- st.write(f"Phase: {t.get('Phase',[''])[0]} | Status: {t['OverallStatus'][0]}")
136
-
137
- # ----------- GRAPH -------------------
138
  with tabs[3]:
139
- st.header("πŸ—ΊοΈ Knowledge Graph")
140
- nodes, edges, cfg = build_agraph(res["papers"],
141
- res["umls"],
142
- res["drug_safety"])
143
- hl = st.text_input("Highlight node:", key="hl")
144
  if hl:
145
- pat = re.compile(re.escape(hl), re.I)
146
- for n in nodes:
147
- if pat.search(n.label): n.color, n.size = "#f1c40f", 30
148
- else: n.color = "#d3d3d3"
149
- agraph(nodes=nodes, edges=edges, config=cfg)
150
 
151
- # ----------- METRICS -----------------
152
  with tabs[4]:
153
- st.header("πŸ“ˆ Graph Metrics")
154
- G = build_nx([n.__dict__ for n in nodes], [e.__dict__ for e in edges])
155
- st.metric("Density", f"{get_density(G):.3f}")
156
- st.markdown("#### Hub Nodes")
157
- for nid, sc in get_top_hubs(G):
158
- lab = next((n.label for n in nodes if n.id == nid), nid)
159
- st.write(f"- **{lab}** – {sc:.3f}")
160
-
161
- # ----------- VISUALS -----------------
162
- with tabs[5]:
163
- years = [p["published"] for p in res["papers"] if p.get("published")]
164
- if years: st.plotly_chart(px.histogram(years, nbins=12, title="Publication Year"))
165
-
166
- # -------- Follow-up AI ---------------
167
- st.markdown("---")
168
- follow = st.text_input("Ask follow-up question:")
169
- if st.button("Ask AI"):
170
- st.write(asyncio.run(answer_ai_question(follow, context=query))["answer"])
171
 
 
 
 
 
 
 
 
 
 
 
172
  else:
173
  st.info("Enter a question and press **Run Search πŸš€**")
174
 
175
-
176
- # ---------------------------------------------------------------------
177
- if __name__ == "__main__":
178
  render_ui()
 
1
+ # app.py – MedGenesis AI (CPU-only, dual-LLM)
2
 
3
  import asyncio, re
4
  from pathlib import Path
5
+ import streamlit as st, pandas as pd, plotly.express as px
 
 
6
  from fpdf import FPDF
7
  from streamlit_agraph import agraph
8
 
 
12
  from mcp.graph_metrics import build_nx, get_top_hubs, get_density
13
  from mcp.alerts import check_alerts
14
 
15
+ ROOT = Path(__file__).parent
16
+ LOGO = ROOT / "assets" / "logo.png"
17
+
18
+ # ────────────────────────────────────────────────────────────────
19
+ def _pdf(papers):
20
+ pdf=FPDF(); pdf.add_page(); pdf.set_font("Arial",size=11)
21
+ for i,p in enumerate(papers,1):
22
+ pdf.multi_cell(0,7,f"{i}. {p['title']} – {p['authors']}\n{p['summary']}\n{p['link']}\n")
23
+ pdf.ln(1)
 
 
 
 
24
  return pdf.output(dest="S").encode("latin-1")
25
 
26
+ def _sidebar_workspace():
 
27
  with st.sidebar:
28
  st.header("πŸ—‚οΈ Workspace")
29
+ for i,item in enumerate(get_workspace(),1):
 
 
 
 
30
  with st.expander(f"{i}. {item['query']}"):
31
+ st.write(item["result"]["ai_summary"])
 
 
 
32
 
33
+ # ────────────────────────────────────────────────────────────────
34
  def render_ui():
35
+ st.set_page_config("MedGenesis AI", layout="wide")
36
+ _sidebar_workspace()
37
 
38
+ # ── Header
39
+ col1,col2 = st.columns([0.15,0.85])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  with col1:
41
  if LOGO.exists(): st.image(str(LOGO), width=100)
42
  with col2:
43
  st.markdown("## 🧬 **MedGenesis AI**")
44
+ st.caption("Multi-source biomedical assistant Β· OpenAI / Gemini LLMs")
45
 
46
+ llm = st.radio("Choose LLM Engine", ["openai","gemini"], horizontal=True)
47
+ query = st.text_input("Enter biomedical question…",
48
+ placeholder="e.g. CRISPR glioblastoma therapy")
49
 
50
+ # πŸ”” Alert check
51
+ if get_workspace():
52
+ try:
53
+ news = asyncio.run(check_alerts([q["query"] for q in get_workspace()]))
54
+ if news:
55
+ st.sidebar.subheader("πŸ”” New Papers")
56
+ for q, lnks in news.items(): st.sidebar.write(f"**{q}** – {len(lnks)} new")
57
+ except Exception: pass
58
 
59
+ # ── Run
60
+ if st.button("Run Search πŸš€") and query:
61
+ with st.spinner("Gathering literature & biomedical data…"):
62
+ res = asyncio.run(orchestrate_search(query, llm))
63
+ st.success(f"Completed with **{res['llm_used'].title()}**")
64
 
65
+ # Tabs
66
+ tabs = st.tabs(["Results","Genes","Trials","Graph","Metrics","Visuals"])
67
+ # 1) Results
68
  with tabs[0]:
69
+ for i,p in enumerate(res["papers"],1):
70
+ st.markdown(f"**{i}. [{p['title']}]({p['link']})** – *{p['authors']}*")
71
+ st.write(p["summary"])
72
+ st.download_button("πŸ“₯ CSV", pd.DataFrame(res["papers"]).to_csv(index=False),
73
+ "papers.csv","text/csv")
74
+ st.download_button("πŸ“„ PDF", _pdf(res["papers"]), "papers.pdf","application/pdf")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  st.info(res["ai_summary"])
76
+ if st.button("Save to Workspace"): save_query(query,res); st.success("Saved!")
77
 
78
+ # 2) Genes
79
  with tabs[1]:
80
+ st.write("### Gene hits")
81
+ for g in res["genes"]: st.write("-", g.get("name",g.get("geneid")))
82
+
83
+ # 3) Trials
 
 
 
 
 
 
84
  with tabs[2]:
85
+ if res["clinical_trials"]:
86
+ for t in res["clinical_trials"]:
87
+ st.write(f"**{t['NCTId'][0]}** – {t['BriefTitle'][0]}")
88
+ else:
89
+ st.info("No trials (rate-limited or none found).")
90
+
91
+ # 4) Graph
 
92
  with tabs[3]:
93
+ nodes,edges,cfg = build_agraph(res["papers"],res["umls"],res["drug_safety"])
94
+ hl = st.text_input("Highlight node…", key="hl")
 
 
 
95
  if hl:
96
+ pat=re.compile(re.escape(hl),re.I)
97
+ for n in nodes:
98
+ n.color="#f1c40f" if pat.search(n.label) else "#d3d3d3"
99
+ agraph(nodes=nodes,edges=edges,config=cfg)
 
100
 
101
+ # 5) Metrics
102
  with tabs[4]:
103
+ G=build_nx([n.__dict__ for n in nodes],[e.__dict__ for e in edges])
104
+ st.metric("Density",f"{get_density(G):.3f}")
105
+ st.write("**Top hubs**")
106
+ for nid,sc in get_top_hubs(G): st.write(nid, f"{sc:.3f}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
 
108
+ # 6) Visuals
109
+ with tabs[5]:
110
+ yrs=[p["published"] for p in res["papers"] if p.get("published")]
111
+ if yrs: st.plotly_chart(px.histogram(yrs,title="Publication Year"))
112
+
113
+ # Follow-up Q-A
114
+ q2=st.text_input("Ask follow-up:")
115
+ if st.button("Ask AI"):
116
+ ans=asyncio.run(answer_ai_question(q2,context=query,llm=llm))
117
+ st.write(ans["answer"])
118
  else:
119
  st.info("Enter a question and press **Run Search πŸš€**")
120
 
121
+ if __name__=="__main__":
 
 
122
  render_ui()