hassan773 commited on
Commit
1e7063c
Β·
verified Β·
1 Parent(s): 5a8227f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +95 -84
app.py CHANGED
@@ -11,77 +11,65 @@ import folium
11
  from streamlit_folium import st_folium
12
  from streamlit_geolocation import streamlit_geolocation
13
 
14
- # --- 1. CORE SYSTEM CONFIG ---
15
  GROQ_API_KEY = os.environ.get("GROQ_API_KEY")
16
  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. PREMIUM CSS ENGINE (Beautiful Bubbles & Static Frame) ---
23
- def inject_premium_design():
24
- st.markdown("""
25
- <style>
26
- @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap');
27
- html, body, [class*="css"] { font-family: 'Poppins', sans-serif; }
28
-
29
- /* 1. Dashboard Static Frame */
30
- [data-testid="stSidebar"] {
31
- background: linear-gradient(180deg, #0f172a 0%, #1e3a8a 100%);
32
- }
33
-
34
- /* 2. Chat Board Styling */
35
- .chat-container {
36
- height: 60vh;
37
- overflow-y: auto;
38
- padding: 20px;
39
- background: #f8fafc;
40
- border-radius: 15px;
41
- border: 1px solid #e2e8f0;
42
- display: flex;
43
- flex-direction: column;
44
- }
45
-
46
- /* 3. Beautiful Message Bubbles */
47
- .user-bubble {
48
  background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
49
- color: white; padding: 15px; border-radius: 20px 20px 0 20px;
50
- align-self: flex-end; margin-bottom: 12px; max-width: 80%;
51
- box-shadow: 0 4px 15px rgba(37,99,235,0.2);
52
- }
53
- .ai-bubble {
54
- background: #ffffff; color: #1e293b; padding: 15px;
55
- border-radius: 20px 20px 20px 0; align-self: flex-start;
56
- margin-bottom: 12px; max-width: 80%; border: 1px solid #e2e8f0;
57
- box-shadow: 0 4px 15px rgba(0,0,0,0.05);
58
  }
59
-
60
- /* 4. Fixed Gemini Prompt Styling */
61
- div[data-testid="stChatInput"] {
62
- border-radius: 25px !important;
63
- border: 2px solid #3b82f6 !important;
 
 
 
 
 
64
  }
65
- </style>
66
- """, unsafe_allow_html=True)
67
 
68
- inject_premium_design()
 
 
69
 
70
- # --- 3. DATA PERSISTENCE & SESSION ---
71
- USER_DB, HISTORY_DB = "users_secure.csv", "clinical_history.csv"
72
  def hash_pass(pwd): return hashlib.sha256(str.encode(pwd)).hexdigest()
 
73
  def load_db(file, cols):
74
  if os.path.exists(file): return pd.read_csv(file)
75
  return pd.DataFrame(columns=cols)
76
 
 
 
 
 
 
 
77
  if "logged_in" not in st.session_state: st.session_state.logged_in = False
78
  if "msgs" not in st.session_state: st.session_state.msgs = []
79
  if "active_doc" not in st.session_state: st.session_state.active_doc = None
80
  if "last_voice_hash" not in st.session_state: st.session_state.last_voice_hash = None
81
 
82
- # --- 4. AUTHENTICATION (Login & Account Creation) ---
83
  if not st.session_state.logged_in:
84
- st.markdown("<h1 style='text-align: center; color: #1e3a8a;'>πŸ₯ INTELLICARE PORTAL</h1>", unsafe_allow_html=True)
85
  c1, c2, c3 = st.columns([1, 2, 1])
86
  with c2:
87
  tab1, tab2 = st.tabs(["πŸ” Login", "πŸ“ Create Account"])
@@ -94,88 +82,111 @@ if not st.session_state.logged_in:
94
  st.session_state.logged_in, st.session_state.username = True, u
95
  st.session_state.role = match.iloc[0]['role']
96
  st.rerun()
 
 
97
  with tab2:
98
  nu, np, nr = st.text_input("New ID"), st.text_input("New Pass", type="password"), st.selectbox("Role", ["Patient", "Doctor"])
99
  if st.button("Register Account"):
100
  df = load_db(USER_DB, ["username", "password", "role"])
101
- if nu in df['username'].values: st.warning("User exists.")
102
  else:
103
  pd.concat([df, pd.DataFrame([{"username": nu, "password": hash_pass(np), "role": nr}])]).to_csv(USER_DB, index=False)
104
- st.success("Account Created! Please Login.")
105
  st.stop()
106
 
107
  # --- 5. SIDEBAR NAVIGATION ---
108
  with st.sidebar:
109
  st.markdown(f"### πŸ‘€ {st.session_state.username} ({st.session_state.role})")
110
- if st.button("Logout Session"): st.session_state.logged_in = False; st.rerun()
111
  st.divider()
112
  if st.session_state.role == "Patient":
113
- nav = st.radio("Menu", ["πŸ’¬ AI Chat", "πŸ§ͺ Health Lab", "πŸ“ Nearby Clinics", "πŸ“ž Video Consult", "πŸ“œ History"])
114
  else:
115
- nav = st.radio("Menu", ["πŸ–₯️ Consultation Desk", "πŸ“‹ Patient Records"])
116
 
117
- # --- 6. AI CHAT MODULE (PREMIUM DESIGN) ---
118
  if nav == "πŸ’¬ AI Chat":
119
- st.markdown("### πŸ’¬ Clinical Intelligence Assistant")
120
 
121
- # Beautiful Chat History Dashboard
122
- st.markdown('<div class="chat-container">', unsafe_allow_html=True)
123
  for m in st.session_state.msgs:
124
- bubble_type = "user-bubble" if m["role"] == "user" else "ai-bubble"
125
- st.markdown(f'<div class="{bubble_type}">{m["content"]}</div>', unsafe_allow_html=True)
126
- st.markdown('</div>', unsafe_allow_html=True)
127
 
128
- # UNIFIED INPUT: Mic & Plus on Left
129
  st.divider()
130
- col_v, col_up, col_q = st.columns([1, 1, 8])
131
- with col_v: v = st.audio_input("🎀", label_visibility="collapsed")
 
 
132
  with col_up:
133
  with st.popover("βž•"):
134
- up = st.file_uploader("Upload PDF", type=['pdf'])
135
  if up:
136
  with pdfplumber.open(up) as f:
137
  st.session_state.active_doc = " ".join([p.extract_text() for p in f.pages if p.extract_text()])
138
- st.success("PDF Context Loaded.")
139
- with col_q: q = st.chat_input("Ask a medical question...")
140
-
141
- # Stable Logic
142
- final_q = q if q else None
143
- if v and not final_q:
 
 
144
  v_hash = hashlib.md5(v.getvalue()).hexdigest()
145
  if v_hash != st.session_state.last_voice_hash:
146
- final_q = Groq(api_key=GROQ_API_KEY).audio.transcriptions.create(file=("a.wav", v.getvalue()), model="whisper-large-v3", response_format="text")
147
- st.session_state.last_voice_hash = v_hash
 
 
148
 
149
  if final_q:
150
  st.session_state.msgs.append({"role": "user", "content": final_q})
151
- sys_p = "Medical AI. Use PDF data if present. Provide clinical advice."
 
152
  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)
153
  st.session_state.msgs.append({"role": "assistant", "content": ans.choices[0].message.content})
 
154
  st.rerun()
155
 
156
  # --- 7. ADDITIONAL TOOLS ---
157
  elif nav == "πŸ§ͺ Health Lab":
158
- st.markdown("### πŸ§ͺ Health Tools")
159
- tool = st.selectbox("Tool", ["BMI Analyzer", "Glucose Tracker"])
160
  if tool == "BMI Analyzer":
161
 
162
- w, h = st.number_input("Weight (kg)", 70), st.number_input("Height (cm)", 175)
163
  bmi = round(w / ((h/100)**2), 1)
164
  st.metric("Your BMI", bmi)
165
  st.plotly_chart(go.Figure(go.Indicator(mode="gauge+number", value=bmi, gauge={'bar':{'color':"#10b981"}})))
166
  elif tool == "Glucose Tracker":
167
 
168
  st.area_chart(pd.DataFrame(np.random.randn(20, 1).cumsum() + 100))
 
 
 
 
 
 
 
 
 
 
 
 
169
 
170
  elif nav == "πŸ“ž Video Consult":
171
- st.markdown("### πŸ“ž Specialist Call")
172
  db = load_db(USER_DB, ["username", "role"])
173
- docs = db[db['role'] == 'Doctor']['username'].tolist() # Patient sees registered doctors
174
- sel_doc = st.selectbox("Select Doctor", docs)
175
  if st.button("Start Meeting"):
176
- st.components.v1.html(f'<iframe src="https://meet.jit.si/IntelliCare-{st.session_state.username}-{sel_doc}" width="100%" height="600px"></iframe>', height=650)
 
177
 
178
- elif nav == "πŸ“œ History":
179
- st.markdown("### πŸ“œ Session History")
180
  history = load_db(HISTORY_DB, ["Time", "User", "Message", "Role"])
181
- st.dataframe(history[history['User'] == st.session_state.username], use_container_width=True) #
 
 
 
 
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")
16
  if not GROQ_API_KEY:
17
+ st.error("⚠️ API Key Missing! Please set it in your environment secrets.")
18
  st.stop()
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
+
55
  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
66
  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"])
 
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 ---
98
  with st.sidebar:
99
  st.markdown(f"### πŸ‘€ {st.session_state.username} ({st.session_state.role})")
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) #