| | 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 |
| |
|
| | |
| | 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="π₯") |
| |
|
| | |
| | st.markdown(""" |
| | <style> |
| | [data-testid="stSidebar"] { background: #1e3a8a !important; } |
| | [data-testid="stSidebar"] * { color: #ffffff !important; } |
| | [data-testid="stSidebar"] .stRadio > div { display: none; } |
| | |
| | div.stButton > button, div.stDownloadButton > button { |
| | background-color: #2563eb !important; color: white !important; |
| | border: 2px solid #3b82f6 !important; border-radius: 12px !important; |
| | transition: 0.3s; font-weight: bold !important; width: 100% !important; |
| | margin-bottom: 10px !important; |
| | } |
| | div.stButton > button:hover { background-color: #1e40af !important; border-color: #60a5fa !important; box-shadow: 0 0 10px #3b82f6 !important; } |
| | |
| | .main .block-container { padding-bottom: 180px; } |
| | .metric-card { background: white; border-radius: 12px; padding: 20px; border-left: 5px solid #2563eb; box-shadow: 0 4px 15px rgba(0,0,0,0.05); color: #1e293b; margin-bottom: 15px; } |
| | .user-msg { background: #3b82f6; color: white; padding: 15px; border-radius: 15px 15px 2px 15px; margin-bottom: 10px; margin-left: 15%; } |
| | .ai-msg { background: #f1f5f9; color: #1e293b; padding: 15px; border-radius: 15px 15px 15px 2px; margin-bottom: 10px; margin-right: 15%; border: 1px solid #e2e8f0; } |
| | </style> |
| | """, unsafe_allow_html=True) |
| |
|
| | |
| | USER_DB, CALL_LOG_DB, CALL_SIGNAL_DB, FEEDBACK_DB, RX_DB = "users_secure.csv", "call_history.csv", "active_calls.csv", "feedback.csv", "prescriptions.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) |
| |
|
| | |
| | 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 "audio_key" not in st.session_state: st.session_state.audio_key = 0 |
| | if "nav" not in st.session_state: st.session_state.nav = "Home" |
| |
|
| | |
| | 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, st.session_state.role = True, u, match.iloc[0]['role'] |
| | st.session_state.nav = "π Analytics" if st.session_state.role == "Doctor" else "π¬ AI Chat" |
| | 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 Account"): |
| | 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("Registration Successful!") |
| | st.stop() |
| |
|
| | |
| | with st.sidebar: |
| | st.markdown(f"### π€ {st.session_state.username} ({st.session_state.role})") |
| | lang = st.radio("Language", ["English", "Urdu"], label_visibility="collapsed") |
| | st.divider() |
| | if st.session_state.role == "Patient": |
| | if st.button("π¬ AI Chat"): st.session_state.nav = "π¬ AI Chat" |
| | if st.button("π My Prescriptions"): st.session_state.nav = "π Prescriptions" |
| | if st.button("π§ͺ Health Lab"): st.session_state.nav = "π§ͺ Health Lab" |
| | if st.button("π Nearby Clinics"): st.session_state.nav = "π Clinics" |
| | if st.button("π Video Call"): st.session_state.nav = "π Video" |
| | if st.button("β Give Feedback"): st.session_state.nav = "β Feedback" |
| | else: |
| | if st.button("π Clinical Analytics"): st.session_state.nav = "π Analytics" |
| | if st.button("π₯οΈ Consultation Desk"): st.session_state.nav = "π₯οΈ Desk" |
| | if st.button("βοΈ Issue Prescription"): st.session_state.nav = "βοΈ Prescription" |
| | if st.button("π AI Summarizer"): st.session_state.nav = "π Summarizer" |
| | |
| | st.divider() |
| | 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() |
| |
|
| | |
| | if st.session_state.nav == "π Analytics": |
| | st.markdown("### π Live Physician Practice Analytics") |
| | u_db = load_db(USER_DB, ["username", "role"]) |
| | f_db = load_db(FEEDBACK_DB, ["Doctor", "Rating"]) |
| | total_patients = len(u_db[u_db['role'] == 'Patient']) |
| | my_rating = f_db[f_db['Doctor'] == st.session_state.username]['Rating'].mean() if not f_db.empty else 5.0 |
| |
|
| | c1, c2, c3 = st.columns(3) |
| | with c1: st.markdown(f'<div class="metric-card"><b>Registered Patients</b><br><h2>{total_patients}</h2></div>', unsafe_allow_html=True) |
| | with c2: st.markdown(f'<div class="metric-card"><b>Average Rating</b><br><h2>{my_rating:.1f}/5</h2></div>', unsafe_allow_html=True) |
| | with c3: st.markdown('<div class="metric-card"><b>Server Status</b><br><h2>Online</h2></div>', unsafe_allow_html=True) |
| |
|
| | g1, g2 = st.columns(2) |
| | with g1: |
| | st.plotly_chart(go.Figure(go.Indicator(mode="gauge+number", value=total_patients, gauge={'axis': {'range': [0, 100]}, 'bar': {'color': "#1e3a8a"}}, title={'text': "Total Patient Registry"})), use_container_width=True) |
| | with g2: |
| | st.plotly_chart(go.Figure(data=[go.Pie(labels=['Patients', 'Doctors'], values=[total_patients, len(u_db[u_db['role'] == 'Doctor'])], hole=.4)]), use_container_width=True) |
| |
|
| | elif st.session_state.nav == "π₯οΈ Desk": |
| | st.markdown("### π₯οΈ Consultation Desk") |
| | sig = load_db(CALL_SIGNAL_DB, ["Caller", "Receiver", "RoomID", "Status"]) |
| | active = sig[(sig['Receiver'] == st.session_state.username) & (sig['Status'] == 'Active')] |
| | if not active.empty: |
| | st.info(f"π Incoming Request: **{active.iloc[0]['Caller']}**") |
| | if st.button("β
Join Consultation"): st.session_state.d_room = active.iloc[0]['RoomID'] |
| | 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="650px" allow="camera; microphone; fullscreen; display-capture"></iframe>', height=700) |
| |
|
| | elif st.session_state.nav == "π Summarizer": |
| | st.markdown("### π AI Clinical Summarizer") |
| | up_s = st.file_uploader("Upload Report (PDF)", type=['pdf']) |
| | if up_s: |
| | with pdfplumber.open(up_s) as f: |
| | text_s = " ".join([p.extract_text() for p in f.pages if p.extract_text()]) |
| | if st.button("π Process Clinical Summary"): |
| | res = Groq(api_key=GROQ_API_KEY).chat.completions.create(model="llama-3.3-70b-versatile", messages=[{"role": "system", "content": "You are a physician. Summarize this report for a doctor's review."}, {"role": "user", "content": text_s}]) |
| | st.info(res.choices[0].message.content) |
| |
|
| | |
| | elif st.session_state.nav == "π¬ AI Chat": |
| | up_p = st.file_uploader("Upload Report", type=['pdf']) |
| | if up_p: |
| | with pdfplumber.open(up_p) as f: |
| | st.session_state.active_doc = " ".join([p.extract_text() for p in f.pages if p.extract_text()]) |
| | 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) |
| | v = st.audio_input("π€", key=f"v_{st.session_state.audio_key}") |
| | q = st.chat_input("Ask health query...") |
| | if q or v: |
| | final_q = q if q else Groq(api_key=GROQ_API_KEY).audio.transcriptions.create(file=("a.wav", v.getvalue()), model="whisper-large-v3", response_format="text") |
| | st.session_state.msgs.append({"role": "user", "content": final_q}) |
| | ans = Groq(api_key=GROQ_API_KEY).chat.completions.create(model="llama-3.3-70b-versatile", messages=[{"role": "system", "content": f"Medical AI. Context: {st.session_state.active_doc}"}] + st.session_state.msgs) |
| | st.session_state.msgs.append({"role": "assistant", "content": ans.choices[0].message.content}) |
| | st.session_state.audio_key += 1 |
| | st.rerun() |
| |
|
| | elif st.session_state.nav == "π§ͺ Health Lab": |
| | st.markdown("### π§ͺ Personal Health Lab") |
| | tool = st.selectbox("Tool", ["βοΈ BMI Analyzer", "π©Έ Glucose Tracker"]) |
| | if tool == "βοΈ BMI Analyzer": |
| | |
| | w, h = st.number_input("Weight (kg)", 70), st.number_input("Height (cm)", 175) |
| | bmi = round(w / ((h/100)**2), 1) |
| | st.plotly_chart(go.Figure(go.Indicator(mode="gauge+number", value=bmi, title={'text': "Current BMI"})), use_container_width=True) |
| |
|
| | elif st.session_state.nav == "π Video": |
| | u_db = load_db(USER_DB, ["username", "role"]) |
| | docs = u_db[u_db['role'] == "Doctor"]['username'].tolist() |
| | target = st.selectbox("Select Specialist", docs) |
| | if st.button("Start Call"): |
| | room = f"IntelliCare-{st.session_state.username}-{target}" |
| | pd.DataFrame([{"Caller": st.session_state.username, "Receiver": target, "RoomID": room, "Status": "Active"}]).to_csv(CALL_SIGNAL_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="650px" allow="camera; microphone; fullscreen; display-capture"></iframe>', height=700) |
| |
|
| | elif st.session_state.nav == "βοΈ Prescription": |
| | u_db = load_db(USER_DB, ["username", "role"]) |
| | patients = u_db[u_db['role'] == "Patient"]['username'].tolist() |
| | with st.form("rx"): |
| | target = st.selectbox("Select Patient", patients) |
| | meds = st.text_area("Prescription Notes") |
| | if st.form_submit_button("Send"): |
| | pd.concat([load_db(RX_DB, ["Date", "Doctor", "Patient", "Notes"]), pd.DataFrame([{"Date": datetime.now().strftime("%Y-%m-%d"), "Doctor": st.session_state.username, "Patient": target, "Notes": meds}])]).to_csv(RX_DB, index=False) |
| | st.success("Sent!") |