hassan773 commited on
Commit
c63dce6
Β·
verified Β·
1 Parent(s): 10233fe

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +73 -92
app.py CHANGED
@@ -19,50 +19,29 @@ if not GROQ_API_KEY:
19
 
20
  st.set_page_config(page_title="IntelliCare Portal | Hassan Naseer", layout="wide", page_icon="πŸ₯")
21
 
22
- # --- 2. PREMIUM CSS (CARD NAVIGATION & STICKY UI) ---
23
  st.markdown("""
24
  <style>
25
- /* SOLID BLUE SIDEBAR */
26
  [data-testid="stSidebar"] { background: #1e3a8a !important; }
27
  [data-testid="stSidebar"] * { color: #ffffff !important; }
28
-
29
- /* REMOVE DEFAULT RADIO CIRCLES */
30
  [data-testid="stSidebar"] .stRadio > div { display: none; }
31
-
32
- /* PREMIUM CARD-STYLE NAVIGATION BUTTONS */
33
  div.stButton > button, div.stDownloadButton > button {
34
- background-color: #2563eb !important;
35
- color: white !important;
36
- border: 2px solid #3b82f6 !important;
37
- border-radius: 12px !important;
38
- transition: all 0.3s ease-in-out !important;
39
- font-weight: bold !important;
40
- width: 100% !important;
41
  margin-bottom: 10px !important;
42
  }
43
- div.stButton > button:hover {
44
- background-color: #1e40af !important;
45
- border-color: #60a5fa !important;
46
- box-shadow: 0 0 10px #3b82f6 !important;
47
- }
48
 
49
- /* STICKY INPUT PADDING FIX */
50
  .main .block-container { padding-bottom: 180px; }
51
-
52
- /* ANALYTICS CARDS */
53
- .metric-card {
54
- background: white; border-radius: 12px; padding: 20px;
55
- border-left: 5px solid #2563eb; box-shadow: 0 4px 15px rgba(0,0,0,0.05);
56
- color: #1e293b; margin-bottom: 15px;
57
- }
58
-
59
- /* CHAT BUBBLES */
60
  .user-msg { background: #3b82f6; color: white; padding: 15px; border-radius: 15px 15px 2px 15px; margin-bottom: 10px; margin-left: 15%; }
61
  .ai-msg { background: #f1f5f9; color: #1e293b; padding: 15px; border-radius: 15px 15px 15px 2px; margin-bottom: 10px; margin-right: 15%; border: 1px solid #e2e8f0; }
62
  </style>
63
  """, unsafe_allow_html=True)
64
 
65
- # --- 3. DATABASE UTILS ---
66
  USER_DB, CALL_LOG_DB, CALL_SIGNAL_DB, FEEDBACK_DB, RX_DB = "users_secure.csv", "call_history.csv", "active_calls.csv", "feedback.csv", "prescriptions.csv"
67
 
68
  def hash_pass(pwd): return hashlib.sha256(str.encode(pwd)).hexdigest()
@@ -77,7 +56,7 @@ if "active_doc" not in st.session_state: st.session_state.active_doc = ""
77
  if "audio_key" not in st.session_state: st.session_state.audio_key = 0
78
  if "nav" not in st.session_state: st.session_state.nav = "Home"
79
 
80
- # --- 4. AUTHENTICATION (RESTORING ALL TABS) ---
81
  if not st.session_state.logged_in:
82
  st.markdown("<h1 style='text-align: center; color: #1e3a8a;'>πŸ₯ IntelliCare Portal</h1>", unsafe_allow_html=True)
83
  c2 = st.columns([1, 2, 1])[1]
@@ -97,18 +76,15 @@ if not st.session_state.logged_in:
97
  nr = st.selectbox("Role", ["Patient", "Doctor"])
98
  if st.button("Register Account"):
99
  df = load_db(USER_DB, ["username", "password", "role"])
100
- if not df[df['username'] == nu].empty: st.error("User already exists!")
101
- else:
102
- pd.concat([df, pd.DataFrame([{"username": nu, "password": hash_pass(np), "role": nr}])]).to_csv(USER_DB, index=False)
103
- st.success("Registration Successful! Please Login.")
104
  st.stop()
105
 
106
- # --- 5. SIDEBAR (MODERN CARD NAVIGATION & CLEAR CHAT) ---
107
  with st.sidebar:
108
  st.markdown(f"### πŸ‘€ {st.session_state.username} ({st.session_state.role})")
109
- lang = st.radio("🌐 Language", ["English", "Urdu"], label_visibility="collapsed")
110
  st.divider()
111
-
112
  if st.session_state.role == "Patient":
113
  if st.button("πŸ’¬ AI Chat"): st.session_state.nav = "πŸ’¬ AI Chat"
114
  if st.button("πŸ’Š My Prescriptions"): st.session_state.nav = "πŸ’Š Prescriptions"
@@ -121,48 +97,62 @@ with st.sidebar:
121
  if st.button("πŸ–₯️ Consultation Desk"): st.session_state.nav = "πŸ–₯️ Desk"
122
  if st.button("✍️ Issue Prescription"): st.session_state.nav = "✍️ Prescription"
123
  if st.button("πŸ“‚ AI Summarizer"): st.session_state.nav = "πŸ“‚ Summarizer"
124
-
125
  st.divider()
126
  if st.button("πŸ—‘οΈ Clear Chat"):
127
  st.session_state.msgs, st.session_state.active_doc = [], ""
128
  st.rerun()
129
  if st.button("πŸšͺ Logout"): st.session_state.logged_in = False; st.rerun()
130
 
131
- # --- 6. DOCTOR CONTENT ---
132
  if st.session_state.nav == "πŸ“Š Analytics":
133
- st.markdown("### πŸ“Š Physician Practice Insights")
134
- c1, c2, c3 = st.columns(3)
135
- with c1: st.markdown('<div class="metric-card"><b>Registered Patients</b><br><h2>84</h2></div>', unsafe_allow_html=True)
136
- with c2: st.markdown('<div class="metric-card"><b>Avg. Rating</b><br><h2>4.9/5</h2></div>', unsafe_allow_html=True)
137
- with c3: st.markdown('<div class="metric-card"><b>Pending Reports</b><br><h2>12</h2></div>', unsafe_allow_html=True)
138
- st.plotly_chart(go.Figure(go.Indicator(mode="gauge+number", value=75, title={'text': "Consultation Capacity"})))
139
 
140
- elif st.session_state.nav == "✍️ Prescription":
141
- st.markdown("### ✍️ Draft Digital Prescription")
142
- user_db = load_db(USER_DB, ["username", "role"])
143
- patients = user_db[user_db['role'] == "Patient"]['username'].tolist()
144
- with st.form("rx"):
145
- target = st.selectbox("Select Patient", patients)
146
- meds = st.text_area("Instructions")
147
- if st.form_submit_button("Issue Prescription"):
148
- pd.concat([load_db(RX_DB, ["Date", "Doctor", "Patient", "Notes"]), pd.DataFrame([{"Date": datetime.now().strftime("%Y-%m-%d"), "Doctor": st.session_state.username, "Patient": target, "Notes": meds}])]).to_csv(RX_DB, index=False)
149
- st.success(f"Prescription sent to {target}!")
150
-
151
- # --- 7. PATIENT CONTENT (FIXED STICKY CHAT & VOICE) ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
  elif st.session_state.nav == "πŸ’¬ AI Chat":
153
- st.markdown("### πŸ’¬ Clinical AI Assistant")
154
- up = st.file_uploader("Upload PDF Report", type=['pdf'])
155
- if up:
156
- with pdfplumber.open(up) as f:
157
  st.session_state.active_doc = " ".join([p.extract_text() for p in f.pages if p.extract_text()])
158
-
159
  for m in st.session_state.msgs:
160
  st.markdown(f'<div class="{"user-msg" if m["role"]=="user" else "ai-msg"}">{m["content"]}</div>', unsafe_allow_html=True)
161
-
162
- st.write("---")
163
- v = st.audio_input("🎀 Voice Query", key=f"v_{st.session_state.audio_key}")
164
- q = st.chat_input("Ask health query...") # Sticky input box
165
-
166
  if q or v:
167
  final_q = q if q else Groq(api_key=GROQ_API_KEY).audio.transcriptions.create(file=("a.wav", v.getvalue()), model="whisper-large-v3", response_format="text")
168
  st.session_state.msgs.append({"role": "user", "content": final_q})
@@ -171,41 +161,32 @@ elif st.session_state.nav == "πŸ’¬ AI Chat":
171
  st.session_state.audio_key += 1
172
  st.rerun()
173
 
174
- elif st.session_state.nav == "πŸ’Š Prescriptions":
175
- rx = load_db(RX_DB, ["Date", "Doctor", "Patient", "Notes"])
176
- st.dataframe(rx[rx['Patient'] == st.session_state.username], use_container_width=True)
177
-
178
  elif st.session_state.nav == "πŸ§ͺ Health Lab":
 
179
  tool = st.selectbox("Tool", ["βš–οΈ BMI Analyzer", "🩸 Glucose Tracker"])
180
  if tool == "βš–οΈ BMI Analyzer":
181
 
182
- w, h = st.number_input("Weight", 70), st.number_input("Height", 175)
183
  bmi = round(w / ((h/100)**2), 1)
184
- st.metric("BMI", bmi)
185
- st.plotly_chart(go.Figure(go.Indicator(mode="gauge+number", value=bmi)))
186
-
187
- # --- 8. SHARED TOOLS ---
188
- elif st.session_state.nav == "πŸ“ Clinics":
189
- loc = streamlit_geolocation()
190
- if loc.get("latitude"):
191
- st_folium(folium.Map(location=[loc["latitude"], loc["longitude"]], zoom_start=14), width="100%")
192
 
193
  elif st.session_state.nav == "πŸ“ž Video":
194
- docs = load_db(USER_DB, ["username", "role"])[load_db(USER_DB, ["username", "role"])['role'] == "Doctor"]['username'].tolist()
 
195
  target = st.selectbox("Select Specialist", docs)
196
  if st.button("Start Call"):
197
  room = f"IntelliCare-{st.session_state.username}-{target}"
198
  pd.DataFrame([{"Caller": st.session_state.username, "Receiver": target, "RoomID": room, "Status": "Active"}]).to_csv(CALL_SIGNAL_DB, index=False)
199
  st.session_state.p_room = room
200
  if "p_room" in st.session_state:
201
- st.components.v1.html(f'<iframe src="https://meet.jit.si/{st.session_state.p_room}" width="100%" height="650px"></iframe>', height=650)
202
-
203
- elif st.session_state.nav == "⭐ Feedback":
204
- docs = load_db(USER_DB, ["username", "role"])[load_db(USER_DB, ["username", "role"])['role'] == "Doctor"]['username'].tolist()
205
- with st.form("fb"):
206
- target = st.selectbox("Doctor", docs)
207
- r = st.slider("Rating", 1, 5, 5)
208
- c = st.text_area("Comment")
209
- if st.form_submit_button("Submit"):
210
- pd.concat([load_db(FEEDBACK_DB, ["Time", "Patient", "Doctor", "Rating", "Comment"]), pd.DataFrame([{"Time": datetime.now().strftime("%Y-%m-%d"), "Patient": st.session_state.username, "Doctor": target, "Rating": r, "Comment": c}])]).to_csv(FEEDBACK_DB, index=False)
211
- st.success("Feedback Sent!")
 
19
 
20
  st.set_page_config(page_title="IntelliCare Portal | Hassan Naseer", layout="wide", page_icon="πŸ₯")
21
 
22
+ # --- 2. PREMIUM CSS ---
23
  st.markdown("""
24
  <style>
 
25
  [data-testid="stSidebar"] { background: #1e3a8a !important; }
26
  [data-testid="stSidebar"] * { color: #ffffff !important; }
 
 
27
  [data-testid="stSidebar"] .stRadio > div { display: none; }
28
+
 
29
  div.stButton > button, div.stDownloadButton > button {
30
+ background-color: #2563eb !important; color: white !important;
31
+ border: 2px solid #3b82f6 !important; border-radius: 12px !important;
32
+ transition: 0.3s; font-weight: bold !important; width: 100% !important;
 
 
 
 
33
  margin-bottom: 10px !important;
34
  }
35
+ div.stButton > button:hover { background-color: #1e40af !important; border-color: #60a5fa !important; box-shadow: 0 0 10px #3b82f6 !important; }
 
 
 
 
36
 
 
37
  .main .block-container { padding-bottom: 180px; }
38
+ .metric-card { background: white; border-radius: 12px; padding: 20px; border-left: 5px solid #2563eb; box-shadow: 0 4px 15px rgba(0,0,0,0.05); color: #1e293b; margin-bottom: 15px; }
 
 
 
 
 
 
 
 
39
  .user-msg { background: #3b82f6; color: white; padding: 15px; border-radius: 15px 15px 2px 15px; margin-bottom: 10px; margin-left: 15%; }
40
  .ai-msg { background: #f1f5f9; color: #1e293b; padding: 15px; border-radius: 15px 15px 15px 2px; margin-bottom: 10px; margin-right: 15%; border: 1px solid #e2e8f0; }
41
  </style>
42
  """, unsafe_allow_html=True)
43
 
44
+ # --- 3. DATABASE HANDLERS ---
45
  USER_DB, CALL_LOG_DB, CALL_SIGNAL_DB, FEEDBACK_DB, RX_DB = "users_secure.csv", "call_history.csv", "active_calls.csv", "feedback.csv", "prescriptions.csv"
46
 
47
  def hash_pass(pwd): return hashlib.sha256(str.encode(pwd)).hexdigest()
 
56
  if "audio_key" not in st.session_state: st.session_state.audio_key = 0
57
  if "nav" not in st.session_state: st.session_state.nav = "Home"
58
 
59
+ # --- 4. AUTHENTICATION ---
60
  if not st.session_state.logged_in:
61
  st.markdown("<h1 style='text-align: center; color: #1e3a8a;'>πŸ₯ IntelliCare Portal</h1>", unsafe_allow_html=True)
62
  c2 = st.columns([1, 2, 1])[1]
 
76
  nr = st.selectbox("Role", ["Patient", "Doctor"])
77
  if st.button("Register Account"):
78
  df = load_db(USER_DB, ["username", "password", "role"])
79
+ pd.concat([df, pd.DataFrame([{"username": nu, "password": hash_pass(np), "role": nr}])]).to_csv(USER_DB, index=False)
80
+ st.success("Registration Successful!")
 
 
81
  st.stop()
82
 
83
+ # --- 5. SIDEBAR ---
84
  with st.sidebar:
85
  st.markdown(f"### πŸ‘€ {st.session_state.username} ({st.session_state.role})")
86
+ lang = st.radio("Language", ["English", "Urdu"], label_visibility="collapsed")
87
  st.divider()
 
88
  if st.session_state.role == "Patient":
89
  if st.button("πŸ’¬ AI Chat"): st.session_state.nav = "πŸ’¬ AI Chat"
90
  if st.button("πŸ’Š My Prescriptions"): st.session_state.nav = "πŸ’Š Prescriptions"
 
97
  if st.button("πŸ–₯️ Consultation Desk"): st.session_state.nav = "πŸ–₯️ Desk"
98
  if st.button("✍️ Issue Prescription"): st.session_state.nav = "✍️ Prescription"
99
  if st.button("πŸ“‚ AI Summarizer"): st.session_state.nav = "πŸ“‚ Summarizer"
100
+
101
  st.divider()
102
  if st.button("πŸ—‘οΈ Clear Chat"):
103
  st.session_state.msgs, st.session_state.active_doc = [], ""
104
  st.rerun()
105
  if st.button("πŸšͺ Logout"): st.session_state.logged_in = False; st.rerun()
106
 
107
+ # --- 6. DOCTOR PORTAL (LIVE ANALYTICS) ---
108
  if st.session_state.nav == "πŸ“Š Analytics":
109
+ st.markdown("### πŸ“Š Live Physician Practice Analytics")
110
+ u_db = load_db(USER_DB, ["username", "role"])
111
+ f_db = load_db(FEEDBACK_DB, ["Doctor", "Rating"])
112
+ total_patients = len(u_db[u_db['role'] == 'Patient'])
113
+ my_rating = f_db[f_db['Doctor'] == st.session_state.username]['Rating'].mean() if not f_db.empty else 5.0
 
114
 
115
+ c1, c2, c3 = st.columns(3)
116
+ with c1: st.markdown(f'<div class="metric-card"><b>Registered Patients</b><br><h2>{total_patients}</h2></div>', unsafe_allow_html=True)
117
+ with c2: st.markdown(f'<div class="metric-card"><b>Average Rating</b><br><h2>{my_rating:.1f}/5</h2></div>', unsafe_allow_html=True)
118
+ with c3: st.markdown('<div class="metric-card"><b>Server Status</b><br><h2>Online</h2></div>', unsafe_allow_html=True)
119
+
120
+ g1, g2 = st.columns(2)
121
+ with g1:
122
+ st.plotly_chart(go.Figure(go.Indicator(mode="gauge+number", value=total_patients, gauge={'axis': {'range': [0, 100]}, 'bar': {'color': "#1e3a8a"}}, title={'text': "Total Patient Registry"})), use_container_width=True)
123
+ with g2:
124
+ st.plotly_chart(go.Figure(data=[go.Pie(labels=['Patients', 'Doctors'], values=[total_patients, len(u_db[u_db['role'] == 'Doctor'])], hole=.4)]), use_container_width=True)
125
+
126
+ elif st.session_state.nav == "πŸ–₯️ Desk":
127
+ st.markdown("### πŸ–₯️ Consultation Desk")
128
+ sig = load_db(CALL_SIGNAL_DB, ["Caller", "Receiver", "RoomID", "Status"])
129
+ active = sig[(sig['Receiver'] == st.session_state.username) & (sig['Status'] == 'Active')]
130
+ if not active.empty:
131
+ st.info(f"πŸ”” Incoming Request: **{active.iloc[0]['Caller']}**")
132
+ if st.button("βœ… Join Consultation"): st.session_state.d_room = active.iloc[0]['RoomID']
133
+ if "d_room" in st.session_state:
134
+ st.components.v1.html(f'<iframe src="https://meet.jit.si/{st.session_state.d_room}" width="100%" height="650px" allow="camera; microphone; fullscreen; display-capture"></iframe>', height=700)
135
+
136
+ elif st.session_state.nav == "πŸ“‚ Summarizer":
137
+ st.markdown("### πŸ“‚ AI Clinical Summarizer")
138
+ up_s = st.file_uploader("Upload Report (PDF)", type=['pdf'])
139
+ if up_s:
140
+ with pdfplumber.open(up_s) as f:
141
+ text_s = " ".join([p.extract_text() for p in f.pages if p.extract_text()])
142
+ if st.button("πŸš€ Process Clinical Summary"):
143
+ res = Groq(api_key=GROQ_API_KEY).chat.completions.create(model="llama-3.3-70b-versatile", messages=[{"role": "system", "content": "You are a physician. Summarize this report for a doctor's review."}, {"role": "user", "content": text_s}])
144
+ st.info(res.choices[0].message.content)
145
+
146
+ # --- 7. PATIENT CONTENT & TOOLS ---
147
  elif st.session_state.nav == "πŸ’¬ AI Chat":
148
+ up_p = st.file_uploader("Upload Report", type=['pdf'])
149
+ if up_p:
150
+ with pdfplumber.open(up_p) as f:
 
151
  st.session_state.active_doc = " ".join([p.extract_text() for p in f.pages if p.extract_text()])
 
152
  for m in st.session_state.msgs:
153
  st.markdown(f'<div class="{"user-msg" if m["role"]=="user" else "ai-msg"}">{m["content"]}</div>', unsafe_allow_html=True)
154
+ v = st.audio_input("🎀", key=f"v_{st.session_state.audio_key}")
155
+ q = st.chat_input("Ask health query...")
 
 
 
156
  if q or v:
157
  final_q = q if q else Groq(api_key=GROQ_API_KEY).audio.transcriptions.create(file=("a.wav", v.getvalue()), model="whisper-large-v3", response_format="text")
158
  st.session_state.msgs.append({"role": "user", "content": final_q})
 
161
  st.session_state.audio_key += 1
162
  st.rerun()
163
 
 
 
 
 
164
  elif st.session_state.nav == "πŸ§ͺ Health Lab":
165
+ st.markdown("### πŸ§ͺ Personal Health Lab")
166
  tool = st.selectbox("Tool", ["βš–οΈ BMI Analyzer", "🩸 Glucose Tracker"])
167
  if tool == "βš–οΈ BMI Analyzer":
168
 
169
+ w, h = st.number_input("Weight (kg)", 70), st.number_input("Height (cm)", 175)
170
  bmi = round(w / ((h/100)**2), 1)
171
+ st.plotly_chart(go.Figure(go.Indicator(mode="gauge+number", value=bmi, title={'text': "Current BMI"})), use_container_width=True)
 
 
 
 
 
 
 
172
 
173
  elif st.session_state.nav == "πŸ“ž Video":
174
+ u_db = load_db(USER_DB, ["username", "role"])
175
+ docs = u_db[u_db['role'] == "Doctor"]['username'].tolist()
176
  target = st.selectbox("Select Specialist", docs)
177
  if st.button("Start Call"):
178
  room = f"IntelliCare-{st.session_state.username}-{target}"
179
  pd.DataFrame([{"Caller": st.session_state.username, "Receiver": target, "RoomID": room, "Status": "Active"}]).to_csv(CALL_SIGNAL_DB, index=False)
180
  st.session_state.p_room = room
181
  if "p_room" in st.session_state:
182
+ st.components.v1.html(f'<iframe src="https://meet.jit.si/{st.session_state.p_room}" width="100%" height="650px" allow="camera; microphone; fullscreen; display-capture"></iframe>', height=700)
183
+
184
+ elif st.session_state.nav == "✍️ Prescription":
185
+ u_db = load_db(USER_DB, ["username", "role"])
186
+ patients = u_db[u_db['role'] == "Patient"]['username'].tolist()
187
+ with st.form("rx"):
188
+ target = st.selectbox("Select Patient", patients)
189
+ meds = st.text_area("Prescription Notes")
190
+ if st.form_submit_button("Send"):
191
+ pd.concat([load_db(RX_DB, ["Date", "Doctor", "Patient", "Notes"]), pd.DataFrame([{"Date": datetime.now().strftime("%Y-%m-%d"), "Doctor": st.session_state.username, "Patient": target, "Notes": meds}])]).to_csv(RX_DB, index=False)
192
+ st.success("Sent!")