Pontonkid commited on
Commit
2f68045
·
verified ·
1 Parent(s): b9a5217

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +59 -50
src/streamlit_app.py CHANGED
@@ -13,8 +13,8 @@ from streamlit_lottie import st_lottie
13
  # 0. CONFIGURATION
14
  # -----------------------------------------------------------------------------
15
  st.set_page_config(
16
- page_title="SHINUI | Advanced Medical AI",
17
- page_icon="🧬",
18
  layout="wide",
19
  initial_sidebar_state="expanded"
20
  )
@@ -35,10 +35,10 @@ genai.configure(api_key=GOOGLE_API_KEY)
35
  model = genai.GenerativeModel('gemini-2.5-pro')
36
 
37
  # -----------------------------------------------------------------------------
38
- # 1. DATABASE SYSTEM
39
  # -----------------------------------------------------------------------------
40
  def init_db():
41
- conn = sqlite3.connect('shinui_v5.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('shinui_v5.db')
52
  try:
53
  conn.execute("INSERT INTO users VALUES (?, ?, ?)", (email, hash_pass(password), datetime.now().strftime("%Y-%m-%d")))
54
  conn.commit()
@@ -57,23 +57,21 @@ def register_user(email, password):
57
  finally: conn.close()
58
 
59
  def login_user(email, password):
60
- conn = sqlite3.connect('shinui_v5.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('shinui_v5.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 %H:%M")))
69
  conn.commit()
70
  conn.close()
71
 
72
  def get_user_stats(email):
73
- conn = sqlite3.connect('shinui_v5.db')
74
- # Get last 5 items for history list
75
- history = conn.execute("SELECT type, date FROM history WHERE email=? ORDER BY id DESC LIMIT 5", (email,)).fetchall()
76
- # Get last login date (simplified logic: using last scan date or join date)
77
  last_scan = history[0][1] if history else "New User"
78
  conn.close()
79
  return history, last_scan
@@ -84,7 +82,7 @@ init_db()
84
  # 2. SESSION STATE & CSS
85
  # -----------------------------------------------------------------------------
86
  if 'page' not in st.session_state: st.session_state.page = 'landing'
87
- if 'auth_mode' not in st.session_state: st.session_state.auth_mode = 'login' # Toggles Login/Register view
88
  if 'logged_in' not in st.session_state: st.session_state.logged_in = False
89
  if 'user_email' not in st.session_state: st.session_state.user_email = ""
90
  if 'analysis_result' not in st.session_state: st.session_state.analysis_result = None
@@ -131,10 +129,11 @@ st.markdown("""
131
 
132
  .history-item {
133
  font-size: 0.85rem;
134
- padding: 8px;
135
  border-bottom: 1px solid rgba(255,255,255,0.05);
136
  display: flex;
137
  justify-content: space-between;
 
138
  }
139
  .history-date { color: #64748b; font-size: 0.75rem; }
140
 
@@ -150,14 +149,16 @@ def get_gemini_analysis(images, text_context, mode):
150
  if mode == "Radiologist Expert": role = "a senior radiologist. Use precise technical terminology."
151
  elif mode == "Simple Explanation": role = "a compassionate doctor explaining to a patient. Use simple analogies."
152
 
 
153
  prompt = [
154
- f"You are SHINUI, {role}.",
155
  f"Analyze these medical images and context: '{text_context}'.",
156
- "Strictly format your output into 4 parts separated by '|||'.",
157
- "Part 1: Clinical Findings (What is seen?)",
158
- "Part 2: Risk Assessment (Low/Medium/High)",
159
- "Part 3: Severity Score (Just the word: Low, Medium, or High)",
160
- "Part 4: Recommended Actions",
 
161
  "Do not use Markdown headers. Just raw text for each section."
162
  ]
163
  content = prompt + images
@@ -165,15 +166,14 @@ def get_gemini_analysis(images, text_context, mode):
165
  response = model.generate_content(content)
166
  return response.text
167
  except Exception as e:
168
- return f"Error|||System Error|||Low|||{str(e)}"
169
 
170
  def chat_with_scan(user_query):
171
- # Context-Aware Prompt
172
  prev_findings = st.session_state.analysis_result
173
  images = st.session_state.analysis_images
174
 
175
  context_prompt = [
176
- "You are SHINUI. You have ALREADY analyzed this patient's scan.",
177
  f"Here is your previous analysis summary: {prev_findings}",
178
  "The user is asking a follow-up question. Do NOT re-analyze the whole image from scratch unless asked.",
179
  "Answer the specific question based on the findings above.",
@@ -201,16 +201,17 @@ def do_sign_out():
201
  # 4. PAGES
202
  # -----------------------------------------------------------------------------
203
 
204
- # --- LANDING ---
205
  def show_landing():
206
  c1, c2 = st.columns([1, 6])
207
- with c1: st.markdown("<h3 style='color:#3b82f6; margin:0;'>SHINUI</h3>", unsafe_allow_html=True)
208
  st.markdown("<br><br>", unsafe_allow_html=True)
209
 
210
  col1, col2 = st.columns([1.3, 1])
211
  with col1:
212
- st.markdown("<h1 style='font-size: 4rem; line-height: 1.1; margin-bottom:20px;'>Medical Clarity.<br><span style='background: -webkit-linear-gradient(0deg, #3b82f6, #a855f7); -webkit-background-clip: text; -webkit-text-fill-color: transparent;'>Simplified.</span></h1>", unsafe_allow_html=True)
213
- st.markdown("<p style='color:#94a3b8; font-size:1.2rem; line-height:1.6;'>The advanced AI assistant that translates complex medical scans and notes into clear, actionable insights.</p>", unsafe_allow_html=True)
 
214
 
215
  b1, b2 = st.columns([1,1.5])
216
  with b1:
@@ -229,22 +230,22 @@ def show_landing():
229
  st.markdown("<br><br><br><br>", unsafe_allow_html=True)
230
  st.markdown("""
231
  <div style='text-align:center; font-size:0.8rem; color:#475569; border-top:1px solid #1e293b; padding-top:20px;'>
232
- <b>Disclaimer:</b> SHINUI is an AI-powered analysis tool. It does not provide medical diagnosis.
233
  Always consult a qualified healthcare professional for medical advice.
234
  </div>
235
  """, unsafe_allow_html=True)
236
 
237
- # --- ABOUT ---
238
  def show_about():
239
  if st.button("← Back"): go_to('landing')
240
  st.markdown("<br>", unsafe_allow_html=True)
241
 
242
  st.markdown("""
243
  <div style='max-width: 700px; margin: 0 auto; text-align: center;'>
244
- <h1 style='color:#3b82f6;'>About SHINUI</h1>
245
  <p style='font-size:1.1rem; line-height:1.8; color:#cbd5e1; margin-bottom:30px;'>
246
- SHINUI is an AI interface designed to interpret medical data.
247
- It acts as a bridge between raw diagnostic information (like X-rays and MRI scans)
248
  and human understanding.
249
  </p>
250
 
@@ -268,7 +269,7 @@ def show_about():
268
  </div>
269
  """, unsafe_allow_html=True)
270
 
271
- # --- AUTH (Combined Login/Register with State Switch) ---
272
  def show_auth():
273
  c1, c2, c3 = st.columns([1,1,1])
274
  with c2:
@@ -299,9 +300,9 @@ def show_auth():
299
  st.markdown("<br>", unsafe_allow_html=True)
300
  if st.button("Sign Up"):
301
  if register_user(re, rp):
302
- st.success("Account created!")
303
- time.sleep(1)
304
- st.session_state.auth_mode = 'login' # AUTO-SWITCH TO LOGIN
305
  st.rerun()
306
  else: st.error("Email already used.")
307
 
@@ -327,17 +328,15 @@ def show_dashboard():
327
  st.rerun()
328
 
329
  st.markdown("---")
330
- # FIX: Small "Last active" text on top of history
331
  st.markdown(f"<div style='font-size:0.75rem; color:#64748b; margin-bottom:10px;'>Last active: {last_active}</div>", unsafe_allow_html=True)
332
- st.markdown("##### Recent Scans")
333
 
334
  if history_data:
335
- for h_type, h_date in history_data:
336
- # FIX: Clean list - Title and Date only
337
  st.markdown(f"""
338
  <div class='history-item'>
339
- <span>{h_type}</span>
340
- <span class='history-date'>{h_date.split(' ')[0]}</span>
341
  </div>
342
  """, unsafe_allow_html=True)
343
  else:
@@ -348,7 +347,6 @@ def show_dashboard():
348
 
349
  st.title("Diagnostic Interface")
350
 
351
- # INPUT SECTION
352
  if st.session_state.analysis_result is None:
353
  st.markdown("<div class='feature-card' style='text-align:left;'>", unsafe_allow_html=True)
354
  img_files = st.file_uploader("Upload Medical Scans (X-Ray, MRI, CT)", type=['png','jpg','jpeg'], accept_multiple_files=True)
@@ -357,7 +355,7 @@ def show_dashboard():
357
  with c2: mode = st.selectbox("Analysis Mode", ["Radiologist Expert", "Simple Explanation"])
358
 
359
  st.markdown("<br>", unsafe_allow_html=True)
360
- if st.button("Run SHINUI Analysis"):
361
  if not img_files and not txt_context: st.error("Please upload an image or provide text.")
362
  else:
363
  with st.spinner("Processing Multi-Modal Data..."):
@@ -365,13 +363,20 @@ def show_dashboard():
365
  res = get_gemini_analysis(pil_images, txt_context, mode)
366
  st.session_state.analysis_result = res
367
  st.session_state.analysis_images = pil_images
 
 
368
  parts = res.split("|||")
369
- risk_lvl = parts[2].strip() if len(parts) > 2 else "Unknown"
370
- add_history(st.session_state.user_email, "Multi-Scan", res, risk_lvl)
 
 
 
 
 
 
371
  st.rerun()
372
  st.markdown("</div>", unsafe_allow_html=True)
373
 
374
- # RESULT SECTION
375
  else:
376
  res = st.session_state.analysis_result
377
  images = st.session_state.analysis_images
@@ -381,9 +386,11 @@ def show_dashboard():
381
  if st.button("💬 Chat with Scan"): go_to('chat')
382
 
383
  st.markdown("---")
 
384
  parts = res.split("|||")
385
- if len(parts) >= 4:
386
- obs, risks, severity, actions = parts[0], parts[1], parts[2], parts[3]
 
387
  sev_clean = severity.strip().lower()
388
  bar_class = "risk-fill-low"
389
  color = "#22c55e"
@@ -397,6 +404,8 @@ def show_dashboard():
397
  </div>
398
  """, unsafe_allow_html=True)
399
 
 
 
400
  c1, c2 = st.columns(2)
401
  with c1:
402
  st.markdown(f"<div class='result-card' style='border-color:#3b82f6'><h4 style='color:#3b82f6'>🔍 Findings</h4>{obs}</div>", unsafe_allow_html=True)
@@ -433,7 +442,7 @@ def show_chat():
433
  # 5. ROUTING
434
  # -----------------------------------------------------------------------------
435
  if st.session_state.page == 'landing': show_landing()
436
- elif st.session_state.page == 'login': show_auth() # Single Auth Page with logic
437
  elif st.session_state.page == 'dashboard':
438
  if st.session_state.logged_in: show_dashboard()
439
  else: go_to('login')
 
13
  # 0. CONFIGURATION
14
  # -----------------------------------------------------------------------------
15
  st.set_page_config(
16
+ page_title="Medivio | Medical Clarity",
17
+ page_icon="⚕️",
18
  layout="wide",
19
  initial_sidebar_state="expanded"
20
  )
 
35
  model = genai.GenerativeModel('gemini-2.5-pro')
36
 
37
  # -----------------------------------------------------------------------------
38
+ # 1. DATABASE SYSTEM (Renamed to Medivio)
39
  # -----------------------------------------------------------------------------
40
  def init_db():
41
+ conn = sqlite3.connect('medivio.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.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.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.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.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()
77
  return history, last_scan
 
82
  # 2. SESSION STATE & CSS
83
  # -----------------------------------------------------------------------------
84
  if 'page' not in st.session_state: st.session_state.page = 'landing'
85
+ if 'auth_mode' not in st.session_state: st.session_state.auth_mode = 'login'
86
  if 'logged_in' not in st.session_state: st.session_state.logged_in = False
87
  if 'user_email' not in st.session_state: st.session_state.user_email = ""
88
  if 'analysis_result' not in st.session_state: st.session_state.analysis_result = None
 
129
 
130
  .history-item {
131
  font-size: 0.85rem;
132
+ padding: 10px;
133
  border-bottom: 1px solid rgba(255,255,255,0.05);
134
  display: flex;
135
  justify-content: space-between;
136
+ color: #cbd5e1;
137
  }
138
  .history-date { color: #64748b; font-size: 0.75rem; }
139
 
 
149
  if mode == "Radiologist Expert": role = "a senior radiologist. Use precise technical terminology."
150
  elif mode == "Simple Explanation": role = "a compassionate doctor explaining to a patient. Use simple analogies."
151
 
152
+ # Prompt Updated for Medivio
153
  prompt = [
154
+ f"You are Medivio, {role}.",
155
  f"Analyze these medical images and context: '{text_context}'.",
156
+ "Strictly format your output into 5 parts separated by '|||'.",
157
+ "Part 1: A Short, Descriptive Title (Max 4 words, e.g. 'Chest X-Ray Normal', 'Skin Rash Check')",
158
+ "Part 2: Clinical Findings (What is seen?)",
159
+ "Part 3: Risk Assessment (Low/Medium/High)",
160
+ "Part 4: Severity Score (Just the word: Low, Medium, or High)",
161
+ "Part 5: Recommended Actions",
162
  "Do not use Markdown headers. Just raw text for each section."
163
  ]
164
  content = prompt + images
 
166
  response = model.generate_content(content)
167
  return response.text
168
  except Exception as e:
169
+ return f"Error|||System Error|||Low|||Low|||{str(e)}"
170
 
171
  def chat_with_scan(user_query):
 
172
  prev_findings = st.session_state.analysis_result
173
  images = st.session_state.analysis_images
174
 
175
  context_prompt = [
176
+ "You are Medivio. You have ALREADY analyzed this patient's scan.",
177
  f"Here is your previous analysis summary: {prev_findings}",
178
  "The user is asking a follow-up question. Do NOT re-analyze the whole image from scratch unless asked.",
179
  "Answer the specific question based on the findings above.",
 
201
  # 4. PAGES
202
  # -----------------------------------------------------------------------------
203
 
204
+ # --- LANDING (UPDATED TEXT) ---
205
  def show_landing():
206
  c1, c2 = st.columns([1, 6])
207
+ with c1: st.markdown("<h3 style='color:#3b82f6; margin:0;'>MEDIVIO</h3>", unsafe_allow_html=True)
208
  st.markdown("<br><br>", unsafe_allow_html=True)
209
 
210
  col1, col2 = st.columns([1.3, 1])
211
  with col1:
212
+ # Option 4 Text Implementation
213
+ st.markdown("<h1 style='font-size: 4rem; line-height: 1.1; margin-bottom:20px;'>Upload your medical report.<br><span style='background: -webkit-linear-gradient(0deg, #3b82f6, #a855f7); -webkit-background-clip: text; -webkit-text-fill-color: transparent;'>Get answers in seconds.</span></h1>", unsafe_allow_html=True)
214
+ st.markdown("<p style='color:#94a3b8; font-size:1.2rem; line-height:1.6;'>AI that translates scans, labs, and clinical notes into language you understand.</p>", unsafe_allow_html=True)
215
 
216
  b1, b2 = st.columns([1,1.5])
217
  with b1:
 
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 (REMOVED TECH JARGON) ---
239
  def show_about():
240
  if st.button("← Back"): go_to('landing')
241
  st.markdown("<br>", unsafe_allow_html=True)
242
 
243
  st.markdown("""
244
  <div style='max-width: 700px; margin: 0 auto; text-align: center;'>
245
+ <h1 style='color:#3b82f6;'>About Medivio</h1>
246
  <p style='font-size:1.1rem; line-height:1.8; color:#cbd5e1; margin-bottom:30px;'>
247
+ Medivio is an AI interface designed to interpret medical data.
248
+ It acts as a bridge between raw diagnostic information (like X-Rays and MRI scans)
249
  and human understanding.
250
  </p>
251
 
 
269
  </div>
270
  """, unsafe_allow_html=True)
271
 
272
+ # --- AUTH ---
273
  def show_auth():
274
  c1, c2, c3 = st.columns([1,1,1])
275
  with c2:
 
300
  st.markdown("<br>", unsafe_allow_html=True)
301
  if st.button("Sign Up"):
302
  if register_user(re, rp):
303
+ st.success("Account created! Please sign in.")
304
+ time.sleep(1.5)
305
+ st.session_state.auth_mode = 'login'
306
  st.rerun()
307
  else: st.error("Email already used.")
308
 
 
328
  st.rerun()
329
 
330
  st.markdown("---")
 
331
  st.markdown(f"<div style='font-size:0.75rem; color:#64748b; margin-bottom:10px;'>Last active: {last_active}</div>", unsafe_allow_html=True)
332
+ st.markdown("##### History")
333
 
334
  if history_data:
335
+ for h_title, h_date in history_data:
 
336
  st.markdown(f"""
337
  <div class='history-item'>
338
+ <span>{h_title}</span>
339
+ <span class='history-date'>{h_date}</span>
340
  </div>
341
  """, unsafe_allow_html=True)
342
  else:
 
347
 
348
  st.title("Diagnostic Interface")
349
 
 
350
  if st.session_state.analysis_result is None:
351
  st.markdown("<div class='feature-card' style='text-align:left;'>", unsafe_allow_html=True)
352
  img_files = st.file_uploader("Upload Medical Scans (X-Ray, MRI, CT)", type=['png','jpg','jpeg'], accept_multiple_files=True)
 
355
  with c2: mode = st.selectbox("Analysis Mode", ["Radiologist Expert", "Simple Explanation"])
356
 
357
  st.markdown("<br>", unsafe_allow_html=True)
358
+ if st.button("Run Analysis"):
359
  if not img_files and not txt_context: st.error("Please upload an image or provide text.")
360
  else:
361
  with st.spinner("Processing Multi-Modal Data..."):
 
363
  res = get_gemini_analysis(pil_images, txt_context, mode)
364
  st.session_state.analysis_result = res
365
  st.session_state.analysis_images = pil_images
366
+
367
+ # PARSE (Title is Part 1)
368
  parts = res.split("|||")
369
+
370
+ if len(parts) >= 5:
371
+ title = parts[0].strip().replace("Part 1:", "").replace("**", "").strip()
372
+ risk_lvl = parts[3].strip()
373
+ add_history(st.session_state.user_email, title, res, risk_lvl)
374
+ else:
375
+ add_history(st.session_state.user_email, "Scan Analysis", res, "Unknown")
376
+
377
  st.rerun()
378
  st.markdown("</div>", unsafe_allow_html=True)
379
 
 
380
  else:
381
  res = st.session_state.analysis_result
382
  images = st.session_state.analysis_images
 
386
  if st.button("💬 Chat with Scan"): go_to('chat')
387
 
388
  st.markdown("---")
389
+
390
  parts = res.split("|||")
391
+ if len(parts) >= 5:
392
+ title, obs, risks, severity, actions = parts[0], parts[1], parts[2], parts[3], parts[4]
393
+
394
  sev_clean = severity.strip().lower()
395
  bar_class = "risk-fill-low"
396
  color = "#22c55e"
 
404
  </div>
405
  """, unsafe_allow_html=True)
406
 
407
+ st.markdown(f"### {title}")
408
+
409
  c1, c2 = st.columns(2)
410
  with c1:
411
  st.markdown(f"<div class='result-card' style='border-color:#3b82f6'><h4 style='color:#3b82f6'>🔍 Findings</h4>{obs}</div>", unsafe_allow_html=True)
 
442
  # 5. ROUTING
443
  # -----------------------------------------------------------------------------
444
  if st.session_state.page == 'landing': show_landing()
445
+ elif st.session_state.page == 'login': show_auth()
446
  elif st.session_state.page == 'dashboard':
447
  if st.session_state.logged_in: show_dashboard()
448
  else: go_to('login')