Pontonkid commited on
Commit
f26d6dc
·
verified ·
1 Parent(s): 981f4cc

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +114 -99
src/streamlit_app.py CHANGED
@@ -38,7 +38,7 @@ model = genai.GenerativeModel('gemini-2.5-pro')
38
  # 1. DATABASE SYSTEM
39
  # -----------------------------------------------------------------------------
40
  def init_db():
41
- conn = sqlite3.connect('medivio_final_v8.db')
42
  c = conn.cursor()
43
  c.execute('''CREATE TABLE IF NOT EXISTS users (email TEXT PRIMARY KEY, password TEXT, joined_date TEXT)''')
44
  c.execute('''CREATE TABLE IF NOT EXISTS history (id INTEGER PRIMARY KEY AUTOINCREMENT, email TEXT, type TEXT, summary TEXT, risk_level TEXT, date TEXT)''')
@@ -48,7 +48,7 @@ def init_db():
48
  def hash_pass(password): return hashlib.sha256(str.encode(password)).hexdigest()
49
 
50
  def register_user(email, password):
51
- conn = sqlite3.connect('medivio_final_v8.db')
52
  try:
53
  conn.execute("INSERT INTO users VALUES (?, ?, ?)", (email, hash_pass(password), datetime.now().strftime("%Y-%m-%d")))
54
  conn.commit()
@@ -57,20 +57,20 @@ def register_user(email, password):
57
  finally: conn.close()
58
 
59
  def login_user(email, password):
60
- conn = sqlite3.connect('medivio_final_v8.db')
61
  data = conn.execute("SELECT * FROM users WHERE email=? AND password=?", (email, hash_pass(password))).fetchall()
62
  conn.close()
63
  return data
64
 
65
  def add_history(email, type, summary, risk):
66
- conn = sqlite3.connect('medivio_final_v8.db')
67
  conn.execute("INSERT INTO history (email, type, summary, risk_level, date) VALUES (?, ?, ?, ?, ?)",
68
  (email, type, summary[:100], risk, datetime.now().strftime("%Y-%m-%d")))
69
  conn.commit()
70
  conn.close()
71
 
72
  def get_user_stats(email):
73
- conn = sqlite3.connect('medivio_final_v8.db')
74
  history = conn.execute("SELECT type, date FROM history WHERE email=? ORDER BY id DESC LIMIT 10", (email,)).fetchall()
75
  last_scan = history[0][1] if history else "New User"
76
  conn.close()
@@ -99,16 +99,15 @@ st.markdown("""
99
  color: #f8fafc;
100
  }
101
 
102
- .feature-card {
 
103
  background: rgba(255, 255, 255, 0.03);
104
  border: 1px solid rgba(255, 255, 255, 0.05);
105
  border-radius: 16px;
106
- padding: 30px;
107
- text-align: center;
108
- backdrop-filter: blur(10px);
109
- margin-bottom: 20px;
110
  }
111
 
 
112
  .result-card {
113
  background: #0f172a;
114
  border-radius: 12px;
@@ -227,88 +226,102 @@ def show_landing():
227
  </div>
228
  """, unsafe_allow_html=True)
229
 
 
230
  st.markdown("<br><br><br><br>", unsafe_allow_html=True)
231
- st.markdown("""
232
- <div style='text-align:center; font-size:0.8rem; color:#475569; border-top:1px solid #1e293b; padding-top:20px;'>
233
- <b>Disclaimer:</b> Medivio is an AI-powered analysis tool. It does not provide medical diagnosis.
234
- Always consult a qualified healthcare professional for medical advice.
235
- </div>
236
- """, unsafe_allow_html=True)
237
 
238
- # --- ABOUT (CLEAN TEXT ONLY) ---
239
  def show_about():
240
  if st.button("← Back"): go_to('landing')
241
  st.markdown("<br>", unsafe_allow_html=True)
242
 
243
- st.markdown("<h1 style='text-align:center; color:#3b82f6;'>About Medivio</h1>", unsafe_allow_html=True)
 
244
 
 
245
  st.markdown("""
246
- <div style='max-width: 700px; margin: 0 auto; font-size: 1.1rem; line-height: 1.8; color: #cbd5e1;'>
247
- <p style='text-align: center;'>
248
- Medivio is an intelligent interface for your health. It acts as a secure bridge between
249
- complex medical data—like X-Rays, MRI scans, and doctor's notes—and clear human understanding.
250
- </p>
 
 
 
 
 
 
 
 
 
 
251
 
252
- <hr style='border-color: #334155; margin: 30px 0;'>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253
 
254
- <h3 style='color:white;'>Mission</h3>
255
- <p>
256
- To democratize access to medical information. We believe everyone should be able to
257
- understand their own health records instantly, without waiting days for an appointment.
258
- </p>
259
 
260
- <h3 style='color:white;'>Technology</h3>
261
- <p>
262
- Medivio leverages <b>Google Gemini 1.5 Pro</b>, a multimodal AI model capable of processing
263
- vision (images) and text simultaneously. This allows for context-aware analysis that
264
- mimics the reasoning of a medical professional.
265
- </p>
266
- </div>
267
- """, unsafe_allow_html=True)
268
 
269
  # --- AUTH ---
270
  def show_auth():
271
  c1, c2, c3 = st.columns([1,1,1])
272
  with c2:
273
  st.markdown("<br><br>", unsafe_allow_html=True)
274
- st.markdown("<div class='feature-card' style='text-align:left; padding:40px;'>", unsafe_allow_html=True)
275
 
276
- if st.session_state.auth_mode == 'login':
277
- st.markdown("<h2 style='text-align:center; margin-bottom:10px;'>Member Login</h2>", unsafe_allow_html=True)
278
- email = st.text_input("Email", key="l_e")
279
- pw = st.text_input("Password", type="password", key="l_p")
280
- st.markdown("<br>", unsafe_allow_html=True)
281
- if st.button("Sign In"):
282
- if login_user(email, pw):
283
- st.session_state.logged_in=True
284
- st.session_state.user_email=email
285
- go_to('dashboard')
286
- else: st.error("Invalid Credentials")
287
-
288
- st.markdown("<hr style='border-color:rgba(255,255,255,0.1)'>", unsafe_allow_html=True)
289
- if st.button("Create Account", type="secondary"):
290
- st.session_state.auth_mode = 'register'
291
- st.rerun()
292
 
293
- else:
294
- st.markdown("<h2 style='text-align:center; margin-bottom:10px;'>Create Account</h2>", unsafe_allow_html=True)
295
- re = st.text_input("Email", key="r_e")
296
- rp = st.text_input("Password", type="password", key="r_p")
297
- st.markdown("<br>", unsafe_allow_html=True)
298
- if st.button("Sign Up"):
299
- if register_user(re, rp):
300
- st.success("Account created! Please sign in.")
301
- time.sleep(1.5)
 
 
 
 
 
 
 
 
 
 
 
302
  st.session_state.auth_mode = 'login'
303
  st.rerun()
304
- else: st.error("Email already used.")
305
-
306
- st.markdown("<hr style='border-color:rgba(255,255,255,0.1)'>", unsafe_allow_html=True)
307
- if st.button("Back to Login", type="secondary"):
308
- st.session_state.auth_mode = 'login'
309
- st.rerun()
310
-
311
- st.markdown("</div>", unsafe_allow_html=True)
312
 
313
  # --- DASHBOARD ---
314
  def show_dashboard():
@@ -345,31 +358,32 @@ def show_dashboard():
345
  st.title("Diagnostic Interface")
346
 
347
  if st.session_state.analysis_result is None:
348
- st.markdown("<div class='feature-card' style='text-align:left;'>", unsafe_allow_html=True)
349
- img_files = st.file_uploader("Upload Medical Scans (X-Ray, MRI, CT)", type=['png','jpg','jpeg'], accept_multiple_files=True)
350
- c1, c2 = st.columns([2, 1])
351
- with c1: txt_context = st.text_area("Patient Symptoms / Clinical Context", height=100, placeholder="E.g. Patient has chest pain for 3 weeks...")
352
- with c2: mode = st.selectbox("Analysis Mode", ["Radiologist Expert", "Simple Explanation"])
353
-
354
- st.markdown("<br>", unsafe_allow_html=True)
355
- if st.button("Run Analysis"):
356
- if not img_files and not txt_context: st.error("Please upload an image or provide text.")
357
- else:
358
- with st.spinner("Processing Multi-Modal Data..."):
359
- pil_images = [Image.open(x) for x in img_files] if img_files else []
360
- res = get_gemini_analysis(pil_images, txt_context, mode)
361
- st.session_state.analysis_result = res
362
- st.session_state.analysis_images = pil_images
363
-
364
- parts = res.split("|||")
365
- if len(parts) >= 5:
366
- title = parts[0].strip().replace("Part 1:", "").replace("**", "").strip()
367
- risk_lvl = parts[3].strip()
368
- add_history(st.session_state.user_email, title, res, risk_lvl)
369
- else:
370
- add_history(st.session_state.user_email, "Analysis", res, "Unknown")
371
- st.rerun()
372
- st.markdown("</div>", unsafe_allow_html=True)
 
373
 
374
  else:
375
  res = st.session_state.analysis_result
@@ -384,16 +398,17 @@ def show_dashboard():
384
  parts = res.split("|||")
385
  if len(parts) >= 5:
386
  title, obs, risks, severity, actions = parts[0], parts[1], parts[2], parts[3], parts[4]
 
387
  sev_clean = severity.strip().lower()
388
  bar_class = "risk-fill-low"
389
  color = "#22c55e"
390
  if "medium" in sev_clean: bar_class = "risk-fill-med"; color = "#eab308"
391
  if "high" in sev_clean: bar_class = "risk-fill-high"; color = "#ef4444"
392
 
 
393
  st.markdown(f"""
394
- <div class='feature-card' style='text-align:left; border-color:{color};'>
395
- <h4 style='margin:0; color:{color}'>SEVERITY SCORE: {severity.upper()}</h4>
396
- <div class='risk-bar' style='background:rgba(255,255,255,0.1)'><div class='{bar_class}'></div></div>
397
  </div>
398
  """, unsafe_allow_html=True)
399
 
 
38
  # 1. DATABASE SYSTEM
39
  # -----------------------------------------------------------------------------
40
  def init_db():
41
+ conn = sqlite3.connect('medivio_v9.db')
42
  c = conn.cursor()
43
  c.execute('''CREATE TABLE IF NOT EXISTS users (email TEXT PRIMARY KEY, password TEXT, joined_date TEXT)''')
44
  c.execute('''CREATE TABLE IF NOT EXISTS history (id INTEGER PRIMARY KEY AUTOINCREMENT, email TEXT, type TEXT, summary TEXT, risk_level TEXT, date TEXT)''')
 
48
  def hash_pass(password): return hashlib.sha256(str.encode(password)).hexdigest()
49
 
50
  def register_user(email, password):
51
+ conn = sqlite3.connect('medivio_v9.db')
52
  try:
53
  conn.execute("INSERT INTO users VALUES (?, ?, ?)", (email, hash_pass(password), datetime.now().strftime("%Y-%m-%d")))
54
  conn.commit()
 
57
  finally: conn.close()
58
 
59
  def login_user(email, password):
60
+ conn = sqlite3.connect('medivio_v9.db')
61
  data = conn.execute("SELECT * FROM users WHERE email=? AND password=?", (email, hash_pass(password))).fetchall()
62
  conn.close()
63
  return data
64
 
65
  def add_history(email, type, summary, risk):
66
+ conn = sqlite3.connect('medivio_v9.db')
67
  conn.execute("INSERT INTO history (email, type, summary, risk_level, date) VALUES (?, ?, ?, ?, ?)",
68
  (email, type, summary[:100], risk, datetime.now().strftime("%Y-%m-%d")))
69
  conn.commit()
70
  conn.close()
71
 
72
  def get_user_stats(email):
73
+ conn = sqlite3.connect('medivio_v9.db')
74
  history = conn.execute("SELECT type, date FROM history WHERE email=? ORDER BY id DESC LIMIT 10", (email,)).fetchall()
75
  last_scan = history[0][1] if history else "New User"
76
  conn.close()
 
99
  color: #f8fafc;
100
  }
101
 
102
+ /* Clean Card Style */
103
+ .stContainer {
104
  background: rgba(255, 255, 255, 0.03);
105
  border: 1px solid rgba(255, 255, 255, 0.05);
106
  border-radius: 16px;
107
+ padding: 20px;
 
 
 
108
  }
109
 
110
+ /* Result Cards */
111
  .result-card {
112
  background: #0f172a;
113
  border-radius: 12px;
 
226
  </div>
227
  """, unsafe_allow_html=True)
228
 
229
+ # PURE MARKDOWN FOOTER (No HTML Tags)
230
  st.markdown("<br><br><br><br>", unsafe_allow_html=True)
231
+ st.divider()
232
+ st.caption("Disclaimer: Medivio is an AI-powered analysis tool. It does not provide medical diagnosis. Always consult a qualified healthcare professional for medical advice.")
 
 
 
 
233
 
234
+ # --- ABOUT (FIXED: PURE STREAMLIT) ---
235
  def show_about():
236
  if st.button("← Back"): go_to('landing')
237
  st.markdown("<br>", unsafe_allow_html=True)
238
 
239
+ # Title
240
+ st.title("About Medivio")
241
 
242
+ # Intro Text (Native Markdown)
243
  st.markdown("""
244
+ Medivio is an intelligent interface for your health. It acts as a secure bridge between
245
+ complex medical data—like X-Rays, MRI scans, and doctor's notes—and clear human understanding.
246
+ """)
247
+
248
+ st.divider()
249
+
250
+ # Mission Section (Native Streamlit Columns)
251
+ col_a, col_b = st.columns(2)
252
+
253
+ with col_a:
254
+ st.subheader("Our Mission")
255
+ st.markdown("""
256
+ To democratize access to medical information. We believe everyone should be able to
257
+ understand their own health records instantly, without waiting days for an appointment.
258
+ """)
259
 
260
+ with col_b:
261
+ st.subheader("Technology")
262
+ st.markdown("""
263
+ Medivio leverages **Google Gemini 1.5 Pro**, a multimodal AI model capable of processing
264
+ vision (images) and text simultaneously. This allows for context-aware analysis that
265
+ mimics the reasoning of a medical professional.
266
+ """)
267
+
268
+ st.divider()
269
+
270
+ # Features (Native Columns, No HTML Injection)
271
+ st.subheader("How It Works")
272
+ f1, f2, f3 = st.columns(3)
273
+
274
+ with f1:
275
+ st.info("**1. Upload**\n\nDrag & Drop medical scans or paste clinical notes securely.")
276
 
277
+ with f2:
278
+ st.info("**2. Analyze**\n\nOur AI engine detects patterns, risks, and anomalies instantly.")
 
 
 
279
 
280
+ with f3:
281
+ st.success("**3. Understand**\n\nReceive a clear, jargon-free explanation of your health data.")
 
 
 
 
 
 
282
 
283
  # --- AUTH ---
284
  def show_auth():
285
  c1, c2, c3 = st.columns([1,1,1])
286
  with c2:
287
  st.markdown("<br><br>", unsafe_allow_html=True)
 
288
 
289
+ # Simple Container
290
+ with st.container():
291
+ if st.session_state.auth_mode == 'login':
292
+ st.markdown("<h2 style='text-align:center; margin-bottom:10px;'>Member Login</h2>", unsafe_allow_html=True)
293
+ email = st.text_input("Email", key="l_e")
294
+ pw = st.text_input("Password", type="password", key="l_p")
295
+ st.markdown("<br>", unsafe_allow_html=True)
296
+ if st.button("Sign In"):
297
+ if login_user(email, pw):
298
+ st.session_state.logged_in=True
299
+ st.session_state.user_email=email
300
+ go_to('dashboard')
301
+ else: st.error("Invalid Credentials")
 
 
 
302
 
303
+ st.markdown("---")
304
+ if st.button("Create Account", type="secondary"):
305
+ st.session_state.auth_mode = 'register'
306
+ st.rerun()
307
+
308
+ else:
309
+ st.markdown("<h2 style='text-align:center; margin-bottom:10px;'>Create Account</h2>", unsafe_allow_html=True)
310
+ re = st.text_input("Email", key="r_e")
311
+ rp = st.text_input("Password", type="password", key="r_p")
312
+ st.markdown("<br>", unsafe_allow_html=True)
313
+ if st.button("Sign Up"):
314
+ if register_user(re, rp):
315
+ st.success("Account created! Please sign in.")
316
+ time.sleep(1.5)
317
+ st.session_state.auth_mode = 'login'
318
+ st.rerun()
319
+ else: st.error("Email already used.")
320
+
321
+ st.markdown("---")
322
+ if st.button("Back to Login", type="secondary"):
323
  st.session_state.auth_mode = 'login'
324
  st.rerun()
 
 
 
 
 
 
 
 
325
 
326
  # --- DASHBOARD ---
327
  def show_dashboard():
 
358
  st.title("Diagnostic Interface")
359
 
360
  if st.session_state.analysis_result is None:
361
+ # Native Container for Upload
362
+ with st.container():
363
+ st.write("Upload your medical data below.")
364
+ img_files = st.file_uploader("Upload Medical Scans (X-Ray, MRI, CT)", type=['png','jpg','jpeg'], accept_multiple_files=True)
365
+ c1, c2 = st.columns([2, 1])
366
+ with c1: txt_context = st.text_area("Patient Symptoms / Clinical Context", height=100, placeholder="E.g. Patient has chest pain for 3 weeks...")
367
+ with c2: mode = st.selectbox("Analysis Mode", ["Radiologist Expert", "Simple Explanation"])
368
+
369
+ st.markdown("<br>", unsafe_allow_html=True)
370
+ if st.button("Run Analysis"):
371
+ if not img_files and not txt_context: st.error("Please upload an image or provide text.")
372
+ else:
373
+ with st.spinner("Processing Multi-Modal Data..."):
374
+ pil_images = [Image.open(x) for x in img_files] if img_files else []
375
+ res = get_gemini_analysis(pil_images, txt_context, mode)
376
+ st.session_state.analysis_result = res
377
+ st.session_state.analysis_images = pil_images
378
+
379
+ parts = res.split("|||")
380
+ if len(parts) >= 5:
381
+ title = parts[0].strip().replace("Part 1:", "").replace("**", "").strip()
382
+ risk_lvl = parts[3].strip()
383
+ add_history(st.session_state.user_email, title, res, risk_lvl)
384
+ else:
385
+ add_history(st.session_state.user_email, "Analysis", res, "Unknown")
386
+ st.rerun()
387
 
388
  else:
389
  res = st.session_state.analysis_result
 
398
  parts = res.split("|||")
399
  if len(parts) >= 5:
400
  title, obs, risks, severity, actions = parts[0], parts[1], parts[2], parts[3], parts[4]
401
+
402
  sev_clean = severity.strip().lower()
403
  bar_class = "risk-fill-low"
404
  color = "#22c55e"
405
  if "medium" in sev_clean: bar_class = "risk-fill-med"; color = "#eab308"
406
  if "high" in sev_clean: bar_class = "risk-fill-high"; color = "#ef4444"
407
 
408
+ # Severity Bar (HTML is required here for custom CSS visuals, but kept simple)
409
  st.markdown(f"""
410
+ <div style='background:rgba(255,255,255,0.05); padding:20px; border-radius:10px; border-left:5px solid {color};'>
411
+ <h4 style='margin:0; color:{color}'>SEVERITY: {severity.upper()}</h4>
 
412
  </div>
413
  """, unsafe_allow_html=True)
414