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