hassan773 commited on
Commit
65d6a46
Β·
verified Β·
1 Parent(s): 1e7063c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +78 -105
app.py CHANGED
@@ -6,10 +6,6 @@ import hashlib
6
  from datetime import datetime
7
  from groq import Groq
8
  import pdfplumber
9
- import plotly.graph_objects as go
10
- import folium
11
- from streamlit_folium import st_folium
12
- from streamlit_geolocation import streamlit_geolocation
13
 
14
  # --- 1. CORE SYSTEM CONFIGURATION ---
15
  GROQ_API_KEY = os.environ.get("GROQ_API_KEY")
@@ -19,36 +15,27 @@ if not GROQ_API_KEY:
19
 
20
  st.set_page_config(page_title="IntelliCare Portal | Hassan Naseer", layout="wide", page_icon="πŸ₯")
21
 
22
- # --- 2. BEAUTIFUL CHAT BUBBLE CSS (Simple Layout, Premium Chat) ---
23
  st.markdown("""
24
  <style>
25
- /* User Message: Beautiful Blue Gradient */
26
  .user-msg {
27
  background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
28
- color: white;
29
- padding: 15px;
30
- border-radius: 18px 18px 2px 18px;
31
- margin-bottom: 15px;
32
- margin-left: 20%;
33
- box-shadow: 0 4px 10px rgba(37, 99, 235, 0.2);
34
  }
35
- /* AI Message: Professional Soft Background */
36
  .ai-msg {
37
- background: #f1f5f9;
38
- color: #1e293b;
39
- padding: 15px;
40
- border-radius: 18px 18px 18px 2px;
41
- margin-bottom: 15px;
42
- margin-right: 20%;
43
- border: 1px solid #e2e8f0;
44
- box-shadow: 0 2px 5px rgba(0,0,0,0.05);
45
  }
46
  </style>
47
  """, unsafe_allow_html=True)
48
 
49
- # --- 3. DATA PERSISTENCE & UTILS ---
50
  USER_DB = "users_secure.csv"
51
- HISTORY_DB = "clinical_history.csv"
 
52
 
53
  def hash_pass(pwd): return hashlib.sha256(str.encode(pwd)).hexdigest()
54
 
@@ -56,10 +43,16 @@ def load_db(file, cols):
56
  if os.path.exists(file): return pd.read_csv(file)
57
  return pd.DataFrame(columns=cols)
58
 
59
- def save_history(user, text, role):
60
- df = load_db(HISTORY_DB, ["Time", "User", "Message", "Role"])
61
- new_entry = pd.DataFrame([{"Time": datetime.now().strftime("%Y-%m-%d %H:%M"), "User": user, "Message": text, "Role": role}])
62
- pd.concat([df, new_entry]).to_csv(HISTORY_DB, index=False)
 
 
 
 
 
 
63
 
64
  # Session State Initialization
65
  if "logged_in" not in st.session_state: st.session_state.logged_in = False
@@ -67,10 +60,10 @@ if "msgs" not in st.session_state: st.session_state.msgs = []
67
  if "active_doc" not in st.session_state: st.session_state.active_doc = None
68
  if "last_voice_hash" not in st.session_state: st.session_state.last_voice_hash = None
69
 
70
- # --- 4. AUTHENTICATION (Account Creation & Login) ---
71
  if not st.session_state.logged_in:
72
  st.markdown("<h1 style='text-align: center;'>πŸ₯ IntelliCare Portal</h1>", unsafe_allow_html=True)
73
- c1, c2, c3 = st.columns([1, 2, 1])
74
  with c2:
75
  tab1, tab2 = st.tabs(["πŸ” Login", "πŸ“ Create Account"])
76
  with tab1:
@@ -82,16 +75,13 @@ if not st.session_state.logged_in:
82
  st.session_state.logged_in, st.session_state.username = True, u
83
  st.session_state.role = match.iloc[0]['role']
84
  st.rerun()
85
- else:
86
- st.error("Invalid credentials.")
87
  with tab2:
88
  nu, np, nr = st.text_input("New ID"), st.text_input("New Pass", type="password"), st.selectbox("Role", ["Patient", "Doctor"])
89
  if st.button("Register Account"):
90
  df = load_db(USER_DB, ["username", "password", "role"])
91
- if nu in df['username'].values: st.warning("User already exists.")
92
- else:
93
  pd.concat([df, pd.DataFrame([{"username": nu, "password": hash_pass(np), "role": nr}])]).to_csv(USER_DB, index=False)
94
- st.success("Account Registered! Please Login.") #
95
  st.stop()
96
 
97
  # --- 5. SIDEBAR NAVIGATION ---
@@ -100,93 +90,76 @@ with st.sidebar:
100
  if st.button("Logout"): st.session_state.logged_in = False; st.rerun()
101
  st.divider()
102
  if st.session_state.role == "Patient":
103
- nav = st.radio("Menu", ["πŸ’¬ AI Chat", "πŸ§ͺ Health Lab", "πŸ“ Nearby Clinics", "πŸ“ž Video Consult", "πŸ“œ My History"])
104
  else:
105
- nav = st.radio("Menu", ["πŸ–₯️ Consultation Desk", "πŸ“‹ Patient Archive", "πŸ“œ Session Logs"])
106
 
107
- # --- 6. AI CHAT MODULE (BEAUTIFUL BACKGROUNDS & LEFT ICONS) ---
108
  if nav == "πŸ’¬ AI Chat":
109
  st.markdown("### πŸ’¬ Clinical AI Assistant")
110
-
111
- # Render Beautiful Chat
112
  for m in st.session_state.msgs:
113
- div_class = "user-msg" if m["role"] == "user" else "ai-msg"
114
- st.markdown(f'<div class="{div_class}">{m["content"]}</div>', unsafe_allow_html=True)
115
-
116
  st.divider()
117
- # MIC AND PLUS ON LEFT OF PROMPT
118
- col_v, col_up, col_q = st.columns([0.6, 0.6, 8.8])
119
- with col_v:
120
- v = st.audio_input("🎀", label_visibility="collapsed", key=f"mic_{len(st.session_state.msgs)}")
121
- with col_up:
122
  with st.popover("βž•"):
123
- up = st.file_uploader("Upload Medical PDF", type=['pdf'])
124
  if up:
125
  with pdfplumber.open(up) as f:
126
  st.session_state.active_doc = " ".join([p.extract_text() for p in f.pages if p.extract_text()])
127
- st.success("PDF Context Extracted!") #
128
- with col_q:
129
- q = st.chat_input("Enter clinical query...")
130
-
131
- # Stable Processing Logic
132
- final_q = None
133
- if q: final_q = q
134
- elif v:
135
- v_hash = hashlib.md5(v.getvalue()).hexdigest()
136
- if v_hash != st.session_state.last_voice_hash:
137
- try:
138
- final_q = Groq(api_key=GROQ_API_KEY).audio.transcriptions.create(file=("a.wav", v.getvalue()), model="whisper-large-v3", response_format="text")
139
- st.session_state.last_voice_hash = v_hash
140
- except: st.error("Mic error. Please try again.")
141
-
142
  if final_q:
143
  st.session_state.msgs.append({"role": "user", "content": final_q})
144
- save_history(st.session_state.username, final_q, "Patient") #
145
- sys_p = "You are a Medical AI. Answer clinical queries. Use PDF data if present. Refuse non-medical topics."
146
- 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)
147
  st.session_state.msgs.append({"role": "assistant", "content": ans.choices[0].message.content})
148
- save_history(st.session_state.username, ans.choices[0].message.content, "AI") #
149
  st.rerun()
150
 
151
- # --- 7. ADDITIONAL TOOLS ---
152
- elif nav == "πŸ§ͺ Health Lab":
153
- st.markdown("### πŸ§ͺ Health Diagnostics")
154
- tool = st.selectbox("Select Tool", ["BMI Analyzer", "Glucose Tracker", "Heart Simulator"])
155
- if tool == "BMI Analyzer":
156
-
157
- w, h = st.number_input("Weight (kg)", 30, 200, 70), st.number_input("Height (cm)", 100, 250, 175)
158
- bmi = round(w / ((h/100)**2), 1)
159
- st.metric("Your BMI", bmi)
160
- st.plotly_chart(go.Figure(go.Indicator(mode="gauge+number", value=bmi, gauge={'bar':{'color':"#10b981"}})))
161
- elif tool == "Glucose Tracker":
162
-
163
- st.area_chart(pd.DataFrame(np.random.randn(20, 1).cumsum() + 100))
164
- elif tool == "Heart Simulator":
165
-
166
- hr = st.slider("BPM", 40, 180, 72)
167
- y = np.sin(2 * np.pi * (hr/60) * np.linspace(0, 2, 200))
168
- st.plotly_chart(go.Figure(data=go.Scatter(y=y, mode='lines', line=dict(color='#ff4b4b'))))
169
-
170
- elif nav == "πŸ“ Nearby Clinics":
171
- st.markdown("### πŸ“ Specialist Hospital Locator")
172
- loc = streamlit_geolocation()
173
- if loc.get("latitude"):
174
- m = folium.Map(location=[loc["latitude"], loc["longitude"]], zoom_start=14)
175
- st_folium(m, width=1000, height=500)
176
-
177
  elif nav == "πŸ“ž Video Consult":
178
- st.markdown("### πŸ“ž Specialist Live Call")
179
  db = load_db(USER_DB, ["username", "role"])
180
- doctors = db[db['role'] == 'Doctor']['username'].tolist() #
181
- sel_doc = st.selectbox("Select Registered Specialist", doctors)
182
- if st.button("Start Meeting"):
183
  room = f"IntelliCare-{st.session_state.username}-{sel_doc}"
184
- st.components.v1.html(f'<iframe src="https://meet.jit.si/{room}" width="100%" height="600px"></iframe>', height=650)
 
 
 
 
185
 
186
- elif nav in ["πŸ“œ My History", "πŸ“œ Session Logs", "πŸ“‹ Patient Archive"]:
187
- st.markdown("### πŸ“œ Clinical History Logs")
188
- history = load_db(HISTORY_DB, ["Time", "User", "Message", "Role"])
189
- if st.session_state.role == "Patient":
190
- st.dataframe(history[history['User'] == st.session_state.username], use_container_width=True) #
191
- else:
192
- st.dataframe(history, use_container_width=True) #
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  from datetime import datetime
7
  from groq import Groq
8
  import pdfplumber
 
 
 
 
9
 
10
  # --- 1. CORE SYSTEM CONFIGURATION ---
11
  GROQ_API_KEY = os.environ.get("GROQ_API_KEY")
 
15
 
16
  st.set_page_config(page_title="IntelliCare Portal | Hassan Naseer", layout="wide", page_icon="πŸ₯")
17
 
18
+ # --- 2. PREMIUM CHAT BUBBLE CSS ---
19
  st.markdown("""
20
  <style>
21
+ /* Beautiful Blue Gradient for Patient */
22
  .user-msg {
23
  background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
24
+ color: white; padding: 15px; border-radius: 18px 18px 2px 18px;
25
+ margin-bottom: 15px; margin-left: 20%; box-shadow: 0 4px 10px rgba(37, 99, 235, 0.2);
 
 
 
 
26
  }
27
+ /* Soft Professional Grey for AI Assistant */
28
  .ai-msg {
29
+ background: #f1f5f9; color: #1e293b; padding: 15px; border-radius: 18px 18px 18px 2px;
30
+ margin-bottom: 15px; margin-right: 20%; border: 1px solid #e2e8f0; box-shadow: 0 2px 5px rgba(0,0,0,0.05);
 
 
 
 
 
 
31
  }
32
  </style>
33
  """, unsafe_allow_html=True)
34
 
35
+ # --- 3. DATA PERSISTENCE & CALL LOGIC ---
36
  USER_DB = "users_secure.csv"
37
+ CALL_LOG_DB = "call_history.csv" # Tracks caller, receiver, and room
38
+ CALL_SIGNAL_DB = "active_calls.csv" # Real-time signaling for doctors
39
 
40
  def hash_pass(pwd): return hashlib.sha256(str.encode(pwd)).hexdigest()
41
 
 
43
  if os.path.exists(file): return pd.read_csv(file)
44
  return pd.DataFrame(columns=cols)
45
 
46
+ def log_call(caller, receiver, room):
47
+ df = load_db(CALL_LOG_DB, ["Time", "Caller", "Receiver", "RoomID"])
48
+ new_call = pd.DataFrame([{"Time": datetime.now().strftime("%Y-%m-%d %H:%M"), "Caller": caller, "Receiver": receiver, "RoomID": room}])
49
+ pd.concat([df, new_call]).to_csv(CALL_LOG_DB, index=False)
50
+
51
+ def send_call_request(caller, receiver, room):
52
+ df = load_db(CALL_SIGNAL_DB, ["Caller", "Receiver", "RoomID", "Status"])
53
+ df = df[df['Receiver'] != receiver] # Clear previous request for this doctor
54
+ new_req = pd.DataFrame([{"Caller": caller, "Receiver": receiver, "RoomID": room, "Status": "Active"}])
55
+ pd.concat([df, new_req]).to_csv(CALL_SIGNAL_DB, index=False)
56
 
57
  # Session State Initialization
58
  if "logged_in" not in st.session_state: st.session_state.logged_in = False
 
60
  if "active_doc" not in st.session_state: st.session_state.active_doc = None
61
  if "last_voice_hash" not in st.session_state: st.session_state.last_voice_hash = None
62
 
63
+ # --- 4. AUTHENTICATION PORTAL ---
64
  if not st.session_state.logged_in:
65
  st.markdown("<h1 style='text-align: center;'>πŸ₯ IntelliCare Portal</h1>", unsafe_allow_html=True)
66
+ c2 = st.columns([1, 2, 1])[1]
67
  with c2:
68
  tab1, tab2 = st.tabs(["πŸ” Login", "πŸ“ Create Account"])
69
  with tab1:
 
75
  st.session_state.logged_in, st.session_state.username = True, u
76
  st.session_state.role = match.iloc[0]['role']
77
  st.rerun()
 
 
78
  with tab2:
79
  nu, np, nr = st.text_input("New ID"), st.text_input("New Pass", type="password"), st.selectbox("Role", ["Patient", "Doctor"])
80
  if st.button("Register Account"):
81
  df = load_db(USER_DB, ["username", "password", "role"])
82
+ if nu not in df['username'].values:
 
83
  pd.concat([df, pd.DataFrame([{"username": nu, "password": hash_pass(np), "role": nr}])]).to_csv(USER_DB, index=False)
84
+ st.success("Account created! Please log in.") #
85
  st.stop()
86
 
87
  # --- 5. SIDEBAR NAVIGATION ---
 
90
  if st.button("Logout"): st.session_state.logged_in = False; st.rerun()
91
  st.divider()
92
  if st.session_state.role == "Patient":
93
+ nav = st.radio("Menu", ["πŸ’¬ AI Chat", "πŸ“ž Video Consult", "πŸ§ͺ Health Lab", "πŸ“œ Call History"])
94
  else:
95
+ nav = st.radio("Menu", ["πŸ–₯️ Consultation Desk", "πŸ“œ Call Logs"])
96
 
97
+ # --- 6. PATIENT FEATURES ---
98
  if nav == "πŸ’¬ AI Chat":
99
  st.markdown("### πŸ’¬ Clinical AI Assistant")
 
 
100
  for m in st.session_state.msgs:
101
+ st.markdown(f'<div class="{"user-msg" if m["role"] == "user" else "ai-msg"}">{m["content"]}</div>', unsafe_allow_html=True)
102
+
 
103
  st.divider()
104
+ # MIC AND PLUS ON LEFT OF TEXT INPUT
105
+ cv, cp, cq = st.columns([0.6, 0.6, 8.8])
106
+ with cv: v = st.audio_input("🎀", key=f"v_{len(st.session_state.msgs)}", label_visibility="collapsed")
107
+ with cp:
 
108
  with st.popover("βž•"):
109
+ up = st.file_uploader("Upload PDF", type=['pdf'])
110
  if up:
111
  with pdfplumber.open(up) as f:
112
  st.session_state.active_doc = " ".join([p.extract_text() for p in f.pages if p.extract_text()])
113
+ st.success("PDF Extracted") #
114
+ with cq: q = st.chat_input("Enter clinical query...")
115
+
116
+ # Stable AI Processing
117
+ final_q = q if q else None
118
+ if v and not final_q:
119
+ vh = hashlib.md5(v.getvalue()).hexdigest()
120
+ if vh != st.session_state.last_voice_hash:
121
+ final_q = Groq(api_key=GROQ_API_KEY).audio.transcriptions.create(file=("a.wav", v.getvalue()), model="whisper-large-v3", response_format="text")
122
+ st.session_state.last_voice_hash = vh
 
 
 
 
 
123
  if final_q:
124
  st.session_state.msgs.append({"role": "user", "content": final_q})
125
+ ans = Groq(api_key=GROQ_API_KEY).chat.completions.create(model="llama-3.3-70b-versatile", messages=[{"role": "system", "content": "Medical AI"}, {"role": "system", "content": f"CTX: {st.session_state.active_doc}"}] + st.session_state.msgs)
 
 
126
  st.session_state.msgs.append({"role": "assistant", "content": ans.choices[0].message.content})
 
127
  st.rerun()
128
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
  elif nav == "πŸ“ž Video Consult":
130
+ st.markdown("### πŸ“ž Specialist Call Request")
131
  db = load_db(USER_DB, ["username", "role"])
132
+ docs = db[db['role'] == 'Doctor']['username'].tolist() # Visibility of registered doctors
133
+ sel_doc = st.selectbox("Select Specialist", docs)
134
+ if st.button("Send Request & Join Room"):
135
  room = f"IntelliCare-{st.session_state.username}-{sel_doc}"
136
+ send_call_request(st.session_state.username, sel_doc, room) # Alert Doctor
137
+ log_call(st.session_state.username, sel_doc, room) # Log History
138
+ st.session_state.pat_room = room
139
+ if "pat_room" in st.session_state:
140
+ st.components.v1.html(f'<iframe src="https://meet.jit.si/{st.session_state.pat_room}" width="100%" height="600px"></iframe>', height=650)
141
 
142
+ elif nav == "πŸ§ͺ Health Lab":
143
+ st.markdown("### πŸ§ͺ Diagnostics")
144
+ w, h = st.number_input("Weight (kg)", 70), st.number_input("Height (cm)", 175)
145
+ st.metric("BMI", round(w / ((h/100)**2), 1))
146
+
147
+ # --- 7. DOCTOR FEATURES ---
148
+ elif nav == "πŸ–₯️ Consultation Desk":
149
+ st.markdown("### πŸ–₯️ Clinical Desk")
150
+ signals = load_db(CALL_SIGNAL_DB, ["Caller", "Receiver", "RoomID"])
151
+ my_calls = signals[signals['Receiver'] == st.session_state.username]
152
+ if not my_calls.empty:
153
+ st.info(f"πŸ”” Call request from **{my_calls.iloc[0]['Caller']}**")
154
+ if st.button("βœ… Accept & Join"):
155
+ st.session_state.doc_room = my_calls.iloc[0]['RoomID']
156
+ else: st.write("Waiting for requests...")
157
+ if "doc_room" in st.session_state:
158
+ st.components.v1.html(f'<iframe src="https://meet.jit.si/{st.session_state.doc_room}" width="100%" height="600px"></iframe>', height=650)
159
+
160
+ # --- 8. CALL HISTORY PORTAL ---
161
+ elif nav in ["πŸ“œ Call History", "πŸ“œ Call Logs"]:
162
+ st.markdown("### πŸ“œ Professional Call Logs")
163
+ history = load_db(CALL_LOG_DB, ["Time", "Caller", "Receiver", "RoomID"]) # Call logs only
164
+ filter_col = 'Caller' if st.session_state.role == "Patient" else 'Receiver'
165
+ st.dataframe(history[history[filter_col] == st.session_state.username], use_container_width=True)