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("""
""", 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("
๐ฅ IntelliCare Portal
", 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'{m["content"]}
', 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'', 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'', height=650)
elif nav in ["๐ History", "๐ Call Logs"]:
st.dataframe(load_db(CALL_LOG_DB, ["Time", "Caller", "Receiver", "RoomID"]), use_container_width=True)