hassan773 commited on
Commit
eac66c7
Β·
verified Β·
1 Parent(s): 1058fbd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +120 -55
app.py CHANGED
@@ -11,123 +11,188 @@ import folium
11
  from streamlit_folium import st_folium
12
  from streamlit_geolocation import streamlit_geolocation
13
 
14
- # --- 1. SYSTEM CONFIG ---
15
  GROQ_API_KEY = os.environ.get("GROQ_API_KEY")
16
  if not GROQ_API_KEY:
17
- st.error("⚠️ API Key Missing!")
18
  st.stop()
19
 
20
- st.set_page_config(page_title="IntelliCare | Hassan Naseer", layout="wide", page_icon="πŸ₯")
21
 
22
- # --- 2. CSS ---
23
  st.markdown("""
24
  <style>
25
  [data-testid="stSidebar"] { background: #1e3a8a !important; }
26
  [data-testid="stSidebar"] * { color: #ffffff !important; }
27
- div.stButton > button { background-color: #1e3a8a !important; color: white !important; }
28
- .user-msg { background: #3b82f6; color: white; padding: 12px; border-radius: 15px 15px 2px 15px; margin-bottom: 10px; margin-left: 25%; }
29
- .ai-msg { background: #f1f5f9; color: #1e293b; padding: 12px; border-radius: 15px 15px 15px 2px; margin-bottom: 10px; margin-right: 25%; border: 1px solid #e2e8f0; }
 
 
 
 
 
 
 
 
 
 
30
  </style>
31
  """, unsafe_allow_html=True)
32
 
33
- # --- 3. CORE LOGIC ---
34
  USER_DB, CALL_LOG_DB, CALL_SIGNAL_DB = "users_secure.csv", "call_history.csv", "active_calls.csv"
35
  def hash_pass(pwd): return hashlib.sha256(str.encode(pwd)).hexdigest()
36
  def load_db(file, cols):
37
  if os.path.exists(file): return pd.read_csv(file)
38
  return pd.DataFrame(columns=cols)
39
 
 
40
  if "logged_in" not in st.session_state: st.session_state.logged_in = False
41
  if "msgs" not in st.session_state: st.session_state.msgs = []
42
  if "active_doc" not in st.session_state: st.session_state.active_doc = ""
43
  if "last_voice_hash" not in st.session_state: st.session_state.last_voice_hash = None
 
44
 
45
  # --- 4. AUTHENTICATION ---
46
  if not st.session_state.logged_in:
47
- st.markdown("<h1 style='text-align: center;'>πŸ₯ IntelliCare Portal</h1>", unsafe_allow_html=True)
48
  c2 = st.columns([1, 2, 1])[1]
49
  with c2:
50
- t1, t2 = st.tabs(["πŸ” Login", "πŸ“ Register"])
51
- with t1:
52
  u, p = st.text_input("Username"), st.text_input("Password", type="password")
53
  if st.button("Sign In"):
54
  db = load_db(USER_DB, ["username", "password", "role"])
55
- m = db[(db['username'] == u) & (db['password'] == hash_pass(p))]
56
- if not m.empty:
57
- st.session_state.logged_in, st.session_state.username, st.session_state.role = True, u, m.iloc[0]['role']
 
58
  st.rerun()
59
- with t2:
60
- nu, np, nr = st.text_input("New ID"), st.text_input("New Pass", type="password"), st.selectbox("Role", ["Patient", "Doctor"])
61
- if st.button("Create Account"):
 
62
  df = load_db(USER_DB, ["username", "password", "role"])
63
- if nu not in df['username'].values:
64
- pd.concat([df, pd.DataFrame([{"username": nu, "password": hash_pass(np), "role": nr}])]).to_csv(USER_DB, index=False)
65
- st.success("Registered!")
66
  st.stop()
67
 
68
- # --- 5. SIDEBAR ---
69
  with st.sidebar:
70
  st.markdown(f"### πŸ‘€ {st.session_state.username}")
71
  lang = st.radio("🌐 Language", ["English", "Urdu"])
72
 
73
- # PERMANENT DOWNLOAD BUTTON
74
- chat_history_text = "\n".join([f"{m['role'].upper()}: {m['content']}" for m in st.session_state.msgs])
75
- st.download_button(
76
- label="πŸ“₯ Download Full Chat PDF/Text",
77
- data=chat_history_text,
78
- file_name=f"IntelliCare_Chat_{datetime.now().strftime('%Y%m%d')}.txt",
79
- mime="text/plain"
80
- )
81
 
82
- if st.button("πŸ—‘οΈ Clear Chat"):
83
  st.session_state.msgs, st.session_state.active_doc = [], ""
84
  st.rerun()
 
85
  st.divider()
86
- nav = st.radio("Menu", ["πŸ’¬ Chat", "πŸ§ͺ Lab", "πŸ“ Maps", "πŸ“ž Video"]) if st.session_state.role == "Patient" else st.radio("Menu", ["πŸ–₯️ Desk", "πŸ“œ Logs"])
 
 
 
 
87
 
88
- # --- 6. CHAT MODULE (FIXED INPUT BAR & PDF TEXT) ---
89
- if nav == "πŸ’¬ Chat":
90
  st.markdown("### πŸ’¬ Clinical Intelligence Assistant")
91
-
92
- # 1. Permanent PDF Reader UI
93
- with st.expander("πŸ“„ Upload Medical PDF / Prescription"):
94
- up = st.file_uploader("Drop PDF here", type=['pdf'], label_visibility="collapsed")
95
  if up:
96
  with pdfplumber.open(up) as f:
97
  st.session_state.active_doc = " ".join([p.extract_text() for p in f.pages if p.extract_text()])
98
- st.success("βœ… Prescription/Report Analyzed!")
99
 
100
- # 2. Display Chat
101
  for m in st.session_state.msgs:
102
- st.markdown(f'<div class="{"user-msg" if m["role"] == "user" else "ai-msg"}">{m["content"]}</div>', unsafe_allow_html=True)
103
 
104
- # 3. FIXED INPUT BAR (Always visible)
105
  st.divider()
106
- c_v, c_q = st.columns([1, 9])
107
- with c_v: v = st.audio_input("🎀", key="permanent_mic", label_visibility="collapsed")
108
- with c_q: q = st.chat_input("Ask about your report or prescription...")
 
109
 
110
  final_q = q if q else None
111
- if v and not final_q: # Voice-to-Text Logic
112
  vh = hashlib.md5(v.getvalue()).hexdigest()
113
  if vh != st.session_state.last_voice_hash:
114
  final_q = Groq(api_key=GROQ_API_KEY).audio.transcriptions.create(file=("a.wav", v.getvalue()), model="whisper-large-v3", response_format="text")
115
  st.session_state.last_voice_hash = vh
 
116
 
117
  if final_q:
118
  st.session_state.msgs.append({"role": "user", "content": final_q})
119
- # AI Logic: PDF Text + Voice/Text
120
- sys_p = f"Medical Assistant. Language: {lang}. If PDF exists, read and explain it like a human doctor. Focus on prescriptions and reports."
121
- 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"PDF_CONTENT: {st.session_state.active_doc}"}] + st.session_state.msgs)
122
  st.session_state.msgs.append({"role": "assistant", "content": ans.choices[0].message.content})
123
  st.rerun()
124
 
125
- # --- 7. OTHER FEATURES ---
126
- elif nav == "πŸ§ͺ Lab":
127
- st.plotly_chart(go.Figure(go.Indicator(mode="gauge+number", value=22, title={'text': "BMI Gauge"})))
128
- elif nav == "πŸ“ Maps":
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
  loc = streamlit_geolocation()
130
  if loc.get("latitude"):
131
- st_folium(folium.Map(location=[loc["latitude"], loc["longitude"]], zoom_start=14), width=1000)
132
- elif nav == "πŸ“ž Video":
133
- st.write("Specialist Call Section")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 check your environment variables.")
18
  st.stop()
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
+ div.stButton > button {
28
+ background-color: #1e3a8a !important; color: white !important;
29
+ border: 1px solid #3b82f6 !important; transition: none !important;
30
+ }
31
+ .user-msg {
32
+ background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
33
+ color: white; padding: 15px; border-radius: 18px 18px 2px 18px;
34
+ margin-bottom: 15px; margin-left: 20%; box-shadow: 0 4px 10px rgba(37,99,235,0.2);
35
+ }
36
+ .ai-msg {
37
+ background: #f1f5f9; color: #1e293b; padding: 15px; border-radius: 18px 18px 18px 2px;
38
+ margin-bottom: 15px; margin-right: 20%; border: 1px solid #e2e8f0;
39
+ }
40
  </style>
41
  """, unsafe_allow_html=True)
42
 
43
+ # --- 3. DATA UTILS ---
44
  USER_DB, CALL_LOG_DB, CALL_SIGNAL_DB = "users_secure.csv", "call_history.csv", "active_calls.csv"
45
  def hash_pass(pwd): return hashlib.sha256(str.encode(pwd)).hexdigest()
46
  def load_db(file, cols):
47
  if os.path.exists(file): return pd.read_csv(file)
48
  return pd.DataFrame(columns=cols)
49
 
50
+ # Session State Initialization
51
  if "logged_in" not in st.session_state: st.session_state.logged_in = False
52
  if "msgs" not in st.session_state: st.session_state.msgs = []
53
  if "active_doc" not in st.session_state: st.session_state.active_doc = ""
54
  if "last_voice_hash" not in st.session_state: st.session_state.last_voice_hash = None
55
+ if "audio_key" not in st.session_state: st.session_state.audio_key = 0 # To reset Mic
56
 
57
  # --- 4. AUTHENTICATION ---
58
  if not st.session_state.logged_in:
59
+ st.markdown("<h1 style='text-align: center; color: #1e3a8a;'>πŸ₯ IntelliCare Portal</h1>", unsafe_allow_html=True)
60
  c2 = st.columns([1, 2, 1])[1]
61
  with c2:
62
+ tab1, tab2 = st.tabs(["πŸ” Login", "πŸ“ Create Account"])
63
+ with tab1:
64
  u, p = st.text_input("Username"), st.text_input("Password", type="password")
65
  if st.button("Sign In"):
66
  db = load_db(USER_DB, ["username", "password", "role"])
67
+ match = db[(db['username'] == u) & (db['password'] == hash_pass(p))]
68
+ if not match.empty:
69
+ st.session_state.logged_in, st.session_state.username = True, u
70
+ st.session_state.role = match.iloc[0]['role']
71
  st.rerun()
72
+ with tab2:
73
+ nu, np = st.text_input("New ID"), st.text_input("New Pass", type="password")
74
+ nr = st.selectbox("Role", ["Patient", "Doctor"])
75
+ if st.button("Register"):
76
  df = load_db(USER_DB, ["username", "password", "role"])
77
+ pd.concat([df, pd.DataFrame([{"username": nu, "password": hash_pass(np), "role": nr}])]).to_csv(USER_DB, index=False)
78
+ st.success("Registered!")
 
79
  st.stop()
80
 
81
+ # --- 5. SIDEBAR NAVIGATION ---
82
  with st.sidebar:
83
  st.markdown(f"### πŸ‘€ {st.session_state.username}")
84
  lang = st.radio("🌐 Language", ["English", "Urdu"])
85
 
86
+ # PERMANENT DOWNLOAD
87
+ chat_txt = "\n".join([f"{m['role']}: {m['content']}" for m in st.session_state.msgs])
88
+ st.download_button("πŸ“₯ Download History", data=chat_txt, file_name="chat.txt")
 
 
 
 
 
89
 
90
+ if st.button("πŸ—‘οΈ Clear Chat"):
91
  st.session_state.msgs, st.session_state.active_doc = [], ""
92
  st.rerun()
93
+ if st.button("πŸšͺ Logout"): st.session_state.logged_in = False; st.rerun()
94
  st.divider()
95
+
96
+ if st.session_state.role == "Patient":
97
+ nav = st.radio("Menu", ["πŸ’¬ AI Chat", "πŸ§ͺ Health Lab", "πŸ“ Nearby Clinics", "πŸ“ž Video Consult", "πŸ“œ History"])
98
+ else:
99
+ nav = st.radio("Menu", ["πŸ–₯️ Consultation Desk", "πŸ“œ Call Logs"])
100
 
101
+ # --- 6. AI CHAT MODULE (FIXED MIC & INPUT) ---
102
+ if nav == "πŸ’¬ AI Chat":
103
  st.markdown("### πŸ’¬ Clinical Intelligence Assistant")
104
+ with st.expander("πŸ“„ Upload Report/Prescription"):
105
+ up = st.file_uploader("Drop PDF", type=['pdf'], label_visibility="collapsed")
 
 
106
  if up:
107
  with pdfplumber.open(up) as f:
108
  st.session_state.active_doc = " ".join([p.extract_text() for p in f.pages if p.extract_text()])
109
+ st.success("βœ… Analysis Ready!")
110
 
 
111
  for m in st.session_state.msgs:
112
+ st.markdown(f'<div class="{"user-msg" if m["role"]=="user" else "ai-msg"}">{m["content"]}</div>', unsafe_allow_html=True)
113
 
 
114
  st.divider()
115
+ col_v, col_q = st.columns([1, 9])
116
+ with col_v: # FIXED MIC RESET
117
+ v = st.audio_input("🎀", key=f"mic_{st.session_state.audio_key}", label_visibility="collapsed")
118
+ with col_q: q = st.chat_input("Ask about your health...")
119
 
120
  final_q = q if q else None
121
+ if v and not final_q:
122
  vh = hashlib.md5(v.getvalue()).hexdigest()
123
  if vh != st.session_state.last_voice_hash:
124
  final_q = Groq(api_key=GROQ_API_KEY).audio.transcriptions.create(file=("a.wav", v.getvalue()), model="whisper-large-v3", response_format="text")
125
  st.session_state.last_voice_hash = vh
126
+ st.session_state.audio_key += 1 # Forces Mic refresh
127
 
128
  if final_q:
129
  st.session_state.msgs.append({"role": "user", "content": final_q})
130
+ sys_p = f"Professional Medical Assistant. Language: {lang}. Analyze the PDF text provided. Refuse non-medical tasks."
131
+ 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"PDF: {st.session_state.active_doc}"}] + st.session_state.msgs)
 
132
  st.session_state.msgs.append({"role": "assistant", "content": ans.choices[0].message.content})
133
  st.rerun()
134
 
135
+ # --- 7. DIAGNOSTIC TOOLS (3 TOOLS RESTORED) ---
136
+ elif nav == "πŸ§ͺ Health Lab":
137
+ st.markdown("### πŸ§ͺ Interactive Clinical Lab")
138
+ tool = st.selectbox("Select Diagnostic Tool", ["βš–οΈ BMI Analyzer", "🩸 Glucose Tracker", "πŸ«€ Heart Rate Sim"])
139
+
140
+ if tool == "βš–οΈ BMI Analyzer":
141
+
142
+ w, h = st.number_input("Weight (kg)", 30, 200, 70), st.number_input("Height (cm)", 100, 250, 175)
143
+ bmi = round(w / ((h/100)**2), 1)
144
+ st.metric("Your BMI", bmi)
145
+ st.plotly_chart(go.Figure(go.Indicator(mode="gauge+number", value=bmi, gauge={'axis': {'range': [10, 40]}, 'bar': {'color': "#3b82f6"}})), use_container_width=True)
146
+
147
+ elif tool == "🩸 Glucose Tracker":
148
+
149
+ st.write("Recent Blood Sugar Levels (mg/dL)")
150
+ df = pd.DataFrame({'Time': range(1, 11), 'Level': np.random.randint(80, 150, 10)})
151
+ st.plotly_chart(go.Figure(data=go.Scatter(x=df['Time'], y=df['Level'], mode='lines+markers', line=dict(color='#2563eb'))), use_container_width=True)
152
+
153
+ elif tool == "πŸ«€ Heart Rate Sim":
154
+
155
+ bpm = st.slider("Select Current BPM", 40, 180, 72)
156
+ st.metric("Heart Rate", f"{bpm} BPM")
157
+ t = np.linspace(0, 2, 1000)
158
+ heart_wave = np.sin(2 * np.pi * (bpm/60) * t) + 0.1 * np.random.normal(0, 1, 1000)
159
+ st.plotly_chart(go.Figure(data=go.Scatter(x=t, y=heart_wave, line=dict(color='#ef4444'))), use_container_width=True)
160
+
161
+ # --- 8. MAPS & VIDEO CALLS (RESTORED) ---
162
+ elif nav == "πŸ“ Nearby Clinics":
163
+ st.markdown("### πŸ“ Specialist Hospital Locator")
164
  loc = streamlit_geolocation()
165
  if loc.get("latitude"):
166
+ m = folium.Map(location=[loc["latitude"], loc["longitude"]], zoom_start=14)
167
+ folium.Marker([loc["latitude"], loc["longitude"]], popup="You").add_to(m)
168
+ st_folium(m, width=1000, height=500)
169
+
170
+ elif nav == "πŸ“ž Video Consult":
171
+ db = load_db(USER_DB, ["username", "role"])
172
+ docs = db[db['role'] == 'Doctor']['username'].tolist()
173
+ sel_doc = st.selectbox("Select Specialist", docs)
174
+ if st.button("Request Video Consultation"):
175
+ room = f"IntelliCare-{st.session_state.username}-{sel_doc}"
176
+ pd.DataFrame([{"Caller": st.session_state.username, "Receiver": sel_doc, "RoomID": room, "Status": "Active"}]).to_csv(CALL_SIGNAL_DB, index=False)
177
+ pd.concat([load_db(CALL_LOG_DB, ["Time", "Caller", "Receiver", "RoomID"]), pd.DataFrame([{"Time": datetime.now().strftime("%Y-%m-%d %H:%M"), "Caller": st.session_state.username, "Receiver": sel_doc, "RoomID": room}])]).to_csv(CALL_LOG_DB, index=False)
178
+ st.session_state.p_room = room
179
+ if "p_room" in st.session_state:
180
+ st.components.v1.html(f'<iframe src="https://meet.jit.si/{st.session_state.p_room}" width="100%" height="600px"></iframe>', height=650)
181
+
182
+ elif nav == "πŸ–₯️ Consultation Desk":
183
+ signals = load_db(CALL_SIGNAL_DB, ["Caller", "Receiver", "RoomID"])
184
+ my_calls = signals[signals['Receiver'] == st.session_state.username]
185
+ if not my_calls.empty:
186
+ st.info(f"πŸ”” Request from {my_calls.iloc[0]['Caller']}")
187
+ c1, c2 = st.columns(2)
188
+ with c1:
189
+ if st.button("βœ… Accept"): st.session_state.d_room = my_calls.iloc[0]['RoomID']
190
+ with c2:
191
+ if st.button("❌ Decline"):
192
+ load_db(CALL_SIGNAL_DB, ["Caller", "Receiver", "RoomID", "Status"])[load_db(CALL_SIGNAL_DB, ["Caller", "Receiver", "RoomID", "Status"])['Receiver'] != st.session_state.username].to_csv(CALL_SIGNAL_DB, index=False)
193
+ st.rerun()
194
+ if "d_room" in st.session_state:
195
+ st.components.v1.html(f'<iframe src="https://meet.jit.si/{st.session_state.d_room}" width="100%" height="600px"></iframe>', height=650)
196
+
197
+ elif nav in ["πŸ“œ History", "πŸ“œ Call Logs"]:
198
+ st.dataframe(load_db(CALL_LOG_DB, ["Time", "Caller", "Receiver", "RoomID"]), use_container_width=True)