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)