hassan773 commited on
Commit
79c130e
Β·
verified Β·
1 Parent(s): 57c1cdb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +49 -120
app.py CHANGED
@@ -17,82 +17,19 @@ if not GROQ_API_KEY:
17
  st.error("⚠️ API Key Missing! Please set it in your environment.")
18
  st.stop()
19
 
20
- st.set_page_config(page_title="IntelliCare Portal | Hassan Naseer", layout="wide", page_icon="πŸ₯")
21
-
22
- # --- 2. ADVANCED CSS: THE STATIC FRAME ENGINE ---
23
- def inject_static_frame():
24
- st.markdown("""
25
- <style>
26
- @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap');
27
-
28
- /* 1. LOCK THE ENTIRE PAGE: No page-level scrolling allowed */
29
- html, body, [data-testid="stAppViewContainer"] {
30
- overflow: hidden !important;
31
- height: 100vh;
32
- font-family: 'Poppins', sans-serif;
33
- }
34
-
35
- /* 2. STATIC SIDEBAR: Locked 100% */
36
- [data-testid="stSidebar"] {
37
- background: linear-gradient(180deg, #0f172a 0%, #1e3a8a 100%);
38
- position: fixed;
39
- height: 100vh;
40
- z-index: 1000;
41
- }
42
- [data-testid="stSidebar"] * { color: #f8fafc !important; }
43
-
44
- /* 3. THE SCROLLABLE CHAT BOARD: The only area that allows scrolling */
45
- .chat-board-container {
46
- height: 60vh; /* Fixed height for the chat area */
47
- overflow-y: auto;
48
- padding: 20px;
49
- background: #ffffff;
50
- border-radius: 15px;
51
- border: 1px solid #e2e8f0;
52
- display: flex;
53
- flex-direction: column;
54
- margin-top: 10px;
55
- }
56
-
57
- /* 4. STATIC PROMPT BAR: Fixed to bottom, never moves */
58
- div[data-testid="stChatInput"] {
59
- position: fixed !important;
60
- bottom: 40px !important;
61
- left: 20% !important; /* Sidebar width adjustment */
62
- width: 70% !important;
63
- z-index: 999 !important;
64
- border-radius: 30px !important;
65
- border: 2px solid #3b82f6 !important;
66
- background: white !important;
67
- box-shadow: 0 -5px 20px rgba(0,0,0,0.05) !important;
68
- }
69
-
70
- /* Professional Message Bubbles */
71
- .user-msg {
72
- background: #3b82f6; color: white; padding: 15px;
73
- border-radius: 20px 20px 0 20px; align-self: flex-end;
74
- margin-bottom: 12px; max-width: 80%;
75
- }
76
- .ai-msg {
77
- background: #f8fafc; color: #1e293b; padding: 15px;
78
- border-radius: 20px 20px 20px 0; align-self: flex-start;
79
- margin-bottom: 12px; max-width: 80%; border: 1px solid #e2e8f0;
80
- }
81
- .voice-btn { background: none; border: none; cursor: pointer; float: right; font-size: 1.1rem; }
82
- </style>
83
-
84
- <script>
85
- function speak(text) {
86
- window.speechSynthesis.cancel();
87
- const msg = new SpeechSynthesisUtterance(text);
88
- window.speechSynthesis.speak(msg);
89
- }
90
- </script>
91
- """, unsafe_allow_html=True)
92
-
93
- inject_static_frame()
94
-
95
- # --- 3. DATABASE & SESSION UTILS ---
96
  USER_DB, HISTORY_DB = "users_secure.csv", "clinical_history.csv"
97
  def hash_pass(pwd): return hashlib.sha256(str.encode(pwd)).hexdigest()
98
  def load_db(file, cols):
@@ -103,16 +40,15 @@ if "logged_in" not in st.session_state: st.session_state.logged_in = False
103
  if "msgs" not in st.session_state: st.session_state.msgs = []
104
  if "active_doc" not in st.session_state: st.session_state.active_doc = None
105
 
106
- # --- 4. ACCOUNT & PORTAL AUTHENTICATION ---
107
-
108
  if not st.session_state.logged_in:
109
- st.markdown("<h1 style='text-align: center; color: #1e3a8a; padding-top: 50px;'>πŸ₯ INTELLICARE PORTAL</h1>", unsafe_allow_html=True)
110
- c2 = st.columns([1, 2, 1])[1]
111
  with c2:
112
- tab1, tab2 = st.tabs(["πŸ” Login", "✨ Create Account"])
113
  with tab1:
114
  u, p = st.text_input("Username"), st.text_input("Password", type="password")
115
- if st.button("SIGN IN"):
116
  db = load_db(USER_DB, ["username", "password", "role"])
117
  match = db[(db['username'] == u) & (db['password'] == hash_pass(p))]
118
  if not match.empty:
@@ -121,90 +57,83 @@ if not st.session_state.logged_in:
121
  st.rerun()
122
  with tab2:
123
  nu, np, nr = st.text_input("New ID"), st.text_input("New Pass", type="password"), st.selectbox("I am a:", ["Patient", "Doctor"])
124
- if st.button("REGISTER"):
125
  df = load_db(USER_DB, ["username", "password", "role"])
126
  if nu not in df['username'].values:
127
  pd.concat([df, pd.DataFrame([{"username": nu, "password": hash_pass(np), "role": nr}])]).to_csv(USER_DB, index=False)
128
- st.success("Account Ready! Log in.")
129
  st.stop()
130
 
131
- # --- 5. STATIC DASHBOARD SIDEBAR ---
132
  with st.sidebar:
133
- st.markdown(f"### πŸ‘€ {st.session_state.username}\n**{st.session_state.role} Mode**")
134
- if st.button("πŸšͺ Logout Session"): st.session_state.logged_in = False; st.rerun()
135
  st.divider()
136
  if st.session_state.role == "Patient":
137
- nav = st.radio("Dashboard Navigation", ["πŸ’¬ AI Chat Board", "πŸ§ͺ Health Lab", "πŸ“ Nearby Clinics", "πŸ“ž Video Consult"])
138
  else:
139
- nav = st.radio("Dashboard Navigation", ["πŸ–₯️ Consultation Desk", "πŸ“‹ Patient Records"])
140
 
141
- # --- 6. PORTAL MODULES ---
142
- if nav == "πŸ’¬ AI Chat Board":
143
- st.markdown("### πŸ’¬ Clinical Intelligence Assistant")
144
-
145
- # INDEPENDENT SCROLL AREA: Only this box scrolls when chat is long
146
- st.markdown('<div class="chat-board-container">', unsafe_allow_html=True)
147
- if not st.session_state.msgs:
148
- st.markdown('<div class="ai-msg">Portal Active. Input your symptoms or clinical reports.</div>', unsafe_allow_html=True)
149
 
 
150
  for m in st.session_state.msgs:
151
  bubble = "user-msg" if m["role"] == "user" else "ai-msg"
152
- icon = f'<button class="voice-btn" onclick="speak(\'{m["content"].replace("'", "")}\')">πŸ”Š</button>' if m["role"] == "assistant" else ""
153
- st.markdown(f'<div class="{bubble}">{icon}{m["content"]}</div>', unsafe_allow_html=True)
154
- st.markdown('</div>', unsafe_allow_html=True)
155
 
156
- # STATIC INPUT CONTROLS (Always visible at bottom)
157
  st.divider()
158
- col1, col2, col3 = st.columns([1, 8, 1])
 
 
159
  with col1:
160
- with st.popover("βž•"):
161
- up = st.file_uploader("Upload Medical PDF", type=['pdf'])
162
- if up:
163
- with pdfplumber.open(up) as f:
164
- st.session_state.active_doc = " ".join([p.extract_text() for p in f.pages])
165
- st.success("PDF Analyzed.")
166
  with col2:
167
- q = st.chat_input("Enter clinical query...")
168
- with col3:
169
- v = st.audio_input("🎀", label_visibility="collapsed")
170
 
171
- # AI RESPONSE ENGINE
172
  final_q = q if q else (v if v else None)
173
  if final_q:
174
  if hasattr(final_q, 'getvalue'):
175
  final_q = Groq(api_key=GROQ_API_KEY).audio.transcriptions.create(file=("a.wav", final_q.getvalue()), model="whisper-large-v3", response_format="text")
176
  st.session_state.msgs.append({"role": "user", "content": final_q})
177
- sys_p = "Medical Assistant. Analyze documents if present. Strictly clinical advice only."
178
- ctx = f"PDF_DATA: {st.session_state.active_doc}"
179
- ans = Groq(api_key=GROQ_API_KEY).chat.completions.create(model="llama-3.3-70b-versatile", messages=[{"role": "system", "content": sys_p}, {"role": "system", "content": ctx}] + st.session_state.msgs)
180
  st.session_state.msgs.append({"role": "assistant", "content": ans.choices[0].message.content})
181
  st.rerun()
182
 
183
  elif nav == "πŸ§ͺ Health Lab":
184
- st.markdown("### πŸ§ͺ Health Diagnostics")
185
- tool = st.selectbox("Tool Selection", ["BMI Analyzer", "Glucose Tracker", "ECG Sim"])
186
  if tool == "BMI Analyzer":
187
 
188
  w, h = st.number_input("Weight (kg)", 70), st.number_input("Height (cm)", 175)
189
  bmi = round(w / ((h/100)**2), 1)
 
190
  st.plotly_chart(go.Figure(go.Indicator(mode="gauge+number", value=bmi, gauge={'bar':{'color':"#10b981"}})))
191
  elif tool == "Glucose Tracker":
192
 
193
  st.area_chart(pd.DataFrame(np.random.randn(20, 1).cumsum() + 100))
194
- elif tool == "ECG Sim":
195
 
196
  hr = st.slider("BPM", 40, 180, 72)
197
  y = np.sin(2 * np.pi * (hr/60) * np.linspace(0, 2, 200))
198
  st.plotly_chart(go.Figure(data=go.Scatter(y=y, mode='lines', line=dict(color='#ff4b4b'))))
199
 
200
  elif nav == "πŸ“ Nearby Clinics":
201
- st.markdown("### πŸ“ Specialist Hospital Finder")
202
  loc = streamlit_geolocation()
203
  if loc.get("latitude"):
204
  m = folium.Map(location=[loc["latitude"], loc["longitude"]], zoom_start=14)
205
  st_folium(m, width=1000, height=500)
206
 
207
  elif nav == "πŸ“ž Video Consult":
208
- st.markdown("### πŸ“ž Specialist Live Call")
209
  if st.button("Start Meeting"):
210
  st.components.v1.html(f'<iframe src="https://meet.jit.si/IntelliCare-{st.session_state.username}" width="100%" height="600px"></iframe>', height=650)
 
17
  st.error("⚠️ API Key Missing! Please set it in your environment.")
18
  st.stop()
19
 
20
+ st.set_page_config(page_title="IntelliCare Portal", layout="wide", page_icon="πŸ₯")
21
+
22
+ # --- 2. SIMPLE THEME ---
23
+ # Removed advanced CSS to return to the original simple look
24
+ st.markdown("""
25
+ <style>
26
+ .chat-bubble { padding: 15px; border-radius: 10px; margin-bottom: 10px; border: 1px solid #ddd; }
27
+ .user-msg { background-color: #e3f2fd; border-left: 5px solid #2196f3; }
28
+ .ai-msg { background-color: #f1f8e9; border-left: 5px solid #4caf50; }
29
+ </style>
30
+ """, unsafe_allow_html=True)
31
+
32
+ # --- 3. PERSISTENCE & UTILS ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  USER_DB, HISTORY_DB = "users_secure.csv", "clinical_history.csv"
34
  def hash_pass(pwd): return hashlib.sha256(str.encode(pwd)).hexdigest()
35
  def load_db(file, cols):
 
40
  if "msgs" not in st.session_state: st.session_state.msgs = []
41
  if "active_doc" not in st.session_state: st.session_state.active_doc = None
42
 
43
+ # --- 4. AUTHENTICATION (Account Creation & Login) ---
 
44
  if not st.session_state.logged_in:
45
+ st.markdown("<h1 style='text-align: center;'>πŸ₯ IntelliCare Portal</h1>", unsafe_allow_html=True)
46
+ c1, c2, c3 = st.columns([1, 2, 1])
47
  with c2:
48
+ tab1, tab2 = st.tabs(["πŸ” Login", "πŸ“ Create Account"])
49
  with tab1:
50
  u, p = st.text_input("Username"), st.text_input("Password", type="password")
51
+ if st.button("Sign In"):
52
  db = load_db(USER_DB, ["username", "password", "role"])
53
  match = db[(db['username'] == u) & (db['password'] == hash_pass(p))]
54
  if not match.empty:
 
57
  st.rerun()
58
  with tab2:
59
  nu, np, nr = st.text_input("New ID"), st.text_input("New Pass", type="password"), st.selectbox("I am a:", ["Patient", "Doctor"])
60
+ if st.button("Register Account"):
61
  df = load_db(USER_DB, ["username", "password", "role"])
62
  if nu not in df['username'].values:
63
  pd.concat([df, pd.DataFrame([{"username": nu, "password": hash_pass(np), "role": nr}])]).to_csv(USER_DB, index=False)
64
+ st.success("Registered! You can now log in.")
65
  st.stop()
66
 
67
+ # --- 5. SIDEBAR NAVIGATION ---
68
  with st.sidebar:
69
+ st.markdown(f"### πŸ‘€ {st.session_state.username}")
70
+ if st.button("Logout"): st.session_state.logged_in = False; st.rerun()
71
  st.divider()
72
  if st.session_state.role == "Patient":
73
+ nav = st.radio("Menu", ["πŸ’¬ AI Chat", "πŸ§ͺ Health Lab", "πŸ“ Nearby Clinics", "πŸ“ž Video Consult"])
74
  else:
75
+ nav = st.radio("Menu", ["πŸ–₯️ Consultation Desk", "πŸ“‹ Patient Records"])
76
 
77
+ # --- 6. PORTAL FEATURES ---
78
+ if nav == "πŸ’¬ AI Chat":
79
+ st.markdown("### πŸ’¬ Clinical AI Assistant")
 
 
 
 
 
80
 
81
+ # Simple Chat Display
82
  for m in st.session_state.msgs:
83
  bubble = "user-msg" if m["role"] == "user" else "ai-msg"
84
+ st.markdown(f'<div class="chat-bubble {bubble}">{m["content"]}</div>', unsafe_allow_html=True)
 
 
85
 
86
+ # Simple Input Section
87
  st.divider()
88
+ q = st.chat_input("Ask a medical question...")
89
+
90
+ col1, col2 = st.columns([1, 5])
91
  with col1:
92
+ up = st.file_uploader("βž• Attach PDF", type=['pdf'])
93
+ if up:
94
+ with pdfplumber.open(up) as f:
95
+ st.session_state.active_doc = " ".join([p.extract_text() for p in f.pages])
96
+ st.success("PDF Loaded")
 
97
  with col2:
98
+ v = st.audio_input("🎀 Voice Message")
 
 
99
 
 
100
  final_q = q if q else (v if v else None)
101
  if final_q:
102
  if hasattr(final_q, 'getvalue'):
103
  final_q = Groq(api_key=GROQ_API_KEY).audio.transcriptions.create(file=("a.wav", final_q.getvalue()), model="whisper-large-v3", response_format="text")
104
  st.session_state.msgs.append({"role": "user", "content": final_q})
105
+
106
+ sys_p = "Medical AI. Answer clinical queries. Use PDF if provided. Refuse non-medical topics."
107
+ ans = Groq(api_key=GROQ_API_KEY).chat.completions.create(model="llama-3.3-70b-versatile", messages=[{"role": "system", "content": sys_p}, {"role": "system", "content": f"CTX: {st.session_state.active_doc}"}] + st.session_state.msgs)
108
  st.session_state.msgs.append({"role": "assistant", "content": ans.choices[0].message.content})
109
  st.rerun()
110
 
111
  elif nav == "πŸ§ͺ Health Lab":
112
+ st.markdown("### πŸ§ͺ Health Tools")
113
+ tool = st.selectbox("Tool", ["BMI Analyzer", "Glucose Tracker", "ECG Simulator"])
114
  if tool == "BMI Analyzer":
115
 
116
  w, h = st.number_input("Weight (kg)", 70), st.number_input("Height (cm)", 175)
117
  bmi = round(w / ((h/100)**2), 1)
118
+ st.metric("Your BMI", bmi)
119
  st.plotly_chart(go.Figure(go.Indicator(mode="gauge+number", value=bmi, gauge={'bar':{'color':"#10b981"}})))
120
  elif tool == "Glucose Tracker":
121
 
122
  st.area_chart(pd.DataFrame(np.random.randn(20, 1).cumsum() + 100))
123
+ elif tool == "ECG Simulator":
124
 
125
  hr = st.slider("BPM", 40, 180, 72)
126
  y = np.sin(2 * np.pi * (hr/60) * np.linspace(0, 2, 200))
127
  st.plotly_chart(go.Figure(data=go.Scatter(y=y, mode='lines', line=dict(color='#ff4b4b'))))
128
 
129
  elif nav == "πŸ“ Nearby Clinics":
130
+ st.markdown("### πŸ“ Specialist Hospital Locator")
131
  loc = streamlit_geolocation()
132
  if loc.get("latitude"):
133
  m = folium.Map(location=[loc["latitude"], loc["longitude"]], zoom_start=14)
134
  st_folium(m, width=1000, height=500)
135
 
136
  elif nav == "πŸ“ž Video Consult":
137
+ st.markdown("### πŸ“ž Live Doctor Session")
138
  if st.button("Start Meeting"):
139
  st.components.v1.html(f'<iframe src="https://meet.jit.si/IntelliCare-{st.session_state.username}" width="100%" height="600px"></iframe>', height=650)