| import streamlit as st |
| import pandas as pd |
| import plotly.express as px |
| import os |
| from openai import OpenAI |
| import bcrypt |
| from supabase import create_client, Client |
|
|
| |
| supabase_url = st.secrets["SUPABASE_URL"] |
| supabase_key = st.secrets["SUPABASE_KEY"] |
| supabase: Client = create_client(supabase_url, supabase_key) |
|
|
| |
| client = OpenAI(api_key=st.secrets["OPENAI_API_KEY"]) |
|
|
| |
| if 'user' not in st.session_state: |
| st.session_state.user = None |
| if 'user_type' not in st.session_state: |
| st.session_state.user_type = None |
|
|
| def load_data(username=None): |
| if username: |
| response = supabase.table('entries').select('*').eq('username', username).execute() |
| else: |
| response = supabase.table('entries').select('*').execute() |
| return pd.DataFrame(response.data) |
|
|
| def load_user_data(): |
| response = supabase.table('users').select('*').execute() |
| return pd.DataFrame(response.data) |
|
|
| def save_data(entry): |
| supabase.table('entries').insert(entry).execute() |
|
|
| def save_user_data(username, hashed_password, user_type): |
| supabase.table('users').insert({ |
| 'username': username, |
| 'password': hashed_password, |
| 'user_type': user_type |
| }).execute() |
|
|
| def get_user(username): |
| response = supabase.table('users').select('*').eq('username', username).execute() |
| return pd.DataFrame(response.data) |
|
|
| def get_gpt_analysis(entry_text, system_prompt): |
| try: |
| response = client.chat.completions.create( |
| model="gpt-4o-mini", |
| messages=[ |
| {"role": "system", "content": system_prompt}, |
| {"role": "user", "content": entry_text} |
| ] |
| ) |
| return response.choices[0].message.content |
| except Exception as e: |
| st.error(f"Error in GPT analysis: {str(e)}") |
| return "Analysis unavailable at this time." |
|
|
| def hash_password(password): |
| return bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8') |
|
|
| def verify_password(stored_password, provided_password): |
| return bcrypt.checkpw(provided_password.encode('utf-8'), stored_password.encode('utf-8')) |
|
|
| def auth(): |
| if st.session_state.user is None: |
| st.subheader("Welcome to the HeadPeace 🧠") |
| |
| |
| with st.expander("How to Use This App", expanded=True): |
| st.markdown(""" |
| **For Patients:** |
| 1. Register for an account or log in if you already have one. |
| 2. Once logged in, you can: |
| - Add new migraine entries |
| - View your past entries |
| - See a dashboard with visualizations of your migraine patterns |
| 3. Regularly log your migraines for the most accurate insights. |
| |
| **Tips for Effective Use:** |
| - Be consistent in logging migraines |
| - Include as much detail as possible in each entry |
| - Regularly review the dashboard to identify patterns |
| - Discuss app insights with your healthcare provider |
| """) |
| tabs = st.tabs(["Login", "Register"]) |
| |
| with tabs[0]: |
| st.subheader("Login") |
| login_username = st.text_input("Username", key="login_username") |
| login_password = st.text_input("Password", type="password", key="login_password") |
| login_button = st.button("Login") |
| |
| if login_button: |
| user_data = get_user(login_username) |
| if not user_data.empty and verify_password(user_data.iloc[0]['password'], login_password): |
| st.session_state.user = login_username |
| st.session_state.user_type = user_data.iloc[0]['user_type'] |
| st.success("Logged in successfully!") |
| st.rerun() |
| else: |
| st.error("Invalid username or password.") |
| |
| with tabs[1]: |
| st.subheader("Register") |
| reg_username = st.text_input("Choose a Username", key="reg_username") |
| reg_password = st.text_input("Choose a Password", type="password", key="reg_password") |
| confirm_password = st.text_input("Confirm Password", type="password", key="confirm_password") |
| user_type = st.selectbox("User Type", ["Patient", "Doctor"]) |
|
|
| doctor_code = "" |
| if user_type == "Doctor": |
| doctor_code = st.text_input("Enter Doctor Registration Code", type="password") |
|
|
| register_button = st.button("Register") |
| |
| if register_button: |
| existing_user = get_user(reg_username) |
| if not existing_user.empty: |
| st.error("Username already exists. Please choose a different one.") |
| elif reg_password != confirm_password: |
| st.error("Passwords do not match.") |
| elif len(reg_password) < 8: |
| st.error("Password must be at least 8 characters long.") |
| elif user_type == "Doctor" and doctor_code != st.secrets["DOCTOR_CODE"]: |
| st.error("Invalid doctor registration code.") |
| else: |
| hashed_password = hash_password(reg_password) |
| save_user_data(reg_username, hashed_password, user_type) |
| st.session_state.user = reg_username |
| st.session_state.user_type = user_type |
| st.success("Registered successfully!") |
| st.rerun() |
| else: |
| st.sidebar.write(f"Logged in as {st.session_state.user} ({st.session_state.user_type})") |
| if st.sidebar.button("Logout"): |
| st.session_state.user = None |
| st.session_state.user_type = None |
| st.rerun() |
|
|
| def main(): |
| st.set_page_config(page_title="HeadPeace by Yashogamya", page_icon="yashogamya.png", layout="wide") |
| header = st.container() |
|
|
| |
| col1, col2 = header.columns([1, 1]) |
|
|
| with col1: |
| st.title("HeadPeace by Yashogamya") |
|
|
| with col2: |
| st.image("yashogamya.png", width=200) |
|
|
| |
| st.markdown(""" |
| <style> |
| [data-testid="stImage"] { |
| display: flex; |
| justify-content: center; |
| align-items: center; |
| height: 100%; |
| } |
| </style> |
| """, unsafe_allow_html=True) |
|
|
| auth() |
|
|
| if st.session_state.user: |
| if st.session_state.user_type == "Patient": |
| patient_interface() |
| elif st.session_state.user_type == "Doctor": |
| doctor_interface() |
|
|
| def patient_interface(): |
| menu = st.sidebar.selectbox("Menu", ["Add Entry", "View Entries", "Dashboard"]) |
|
|
| if menu == "Add Entry": |
| add_entry() |
| elif menu == "View Entries": |
| view_entries(is_doctor=False) |
| elif menu == "Dashboard": |
| display_dashboard(is_doctor=False) |
|
|
| def doctor_interface(): |
| menu = st.sidebar.selectbox("Menu", ["View All Entries", "Patient Dashboard"]) |
|
|
| if menu == "View All Entries": |
| view_entries(is_doctor=True) |
| elif menu == "Patient Dashboard": |
| display_dashboard(is_doctor=True) |
|
|
| def add_entry(): |
| st.header("Add New Headache Entry") |
| with st.sidebar: |
| st.subheader("How to Add an Entry") |
| st.markdown(""" |
| 1. **Date**: Select the date of your migraine. |
| 2. **Pain Level**: Rate your pain from 1 (mild) to 10 (severe). |
| 3. **Duration**: Choose how long your migraine lasted. |
| 4. **Triggers**: Select all factors that may have triggered your migraine. |
| 5. **Symptoms**: Check all symptoms you experienced. |
| 6. **Medications**: List any medications you took. |
| 7. **Notes**: Add any additional observations or comments. |
| 8. **Submit**: Click 'Submit Entry' when you're done. |
| |
| Tips: |
| - Be as accurate and detailed as possible. |
| - If you're unsure about a trigger or symptom, it's okay to leave it unchecked. |
| - Use the notes section to mention any unusual circumstances or effects. |
| """) |
| with st.form("migraine_entry"): |
| date = st.date_input("Date") |
| pain_level = st.slider("Pain Level", 1, 10) |
| duration = st.selectbox("Duration", ["Less than 1 hour", "1-4 hours", "4-8 hours", "8-24 hours", "More than 24 hours"]) |
| |
| triggers = st.multiselect("Triggers", [ |
| "Stress", "Lack of Sleep", "Dehydration", "Skipped Meals", |
| "Alcohol", "Caffeine", "Chocolate", "Aged Cheeses", |
| "Processed Meats", "Artificial Sweeteners", "MSG", |
| "Weather Changes", "Barometric Pressure Changes", |
| "Bright Lights", "Loud Noises", "Strong Smells", |
| "Screen Time", "Reading", "Physical Exertion", |
| "Hormonal Changes", "Medication Overuse", |
| "Travel", "Altitude Changes", "Other" |
| ]) |
| |
| symptoms = st.multiselect("Symptoms", [ |
| "Throbbing Pain", "Pulsating Pain", "One-sided Pain", |
| "Nausea", "Vomiting", "Sensitivity to Light", |
| "Sensitivity to Sound", "Sensitivity to Smells", |
| "Blurred Vision", "Visual Aura", "Blind Spots", |
| "Zigzag Lines in Vision", "Tingling or Numbness", |
| "Difficulty Speaking", "Weakness", "Dizziness", |
| "Vertigo", "Neck Stiffness", "Confusion", |
| "Mood Changes", "Food Cravings", "Frequent Urination", |
| "Fatigue", "Yawning", "Other" |
| ]) |
| |
| medications = st.text_input("Medications taken") |
| notes = st.text_area("Additional Notes") |
| |
| submitted = st.form_submit_button("Submit Entry") |
| if submitted: |
| entry_text = f"Date: {date}\nPain Level: {pain_level}\nDuration: {duration}\nTriggers: {', '.join(triggers)}\nSymptoms: {', '.join(symptoms)}\nMedications: {medications}\nNotes: {notes}" |
| |
| with st.spinner("Analyzing your entry..."): |
| doctor_analysis = get_gpt_analysis(entry_text, "You are a neurologist specializing in migraine management. Provide a technical analysis of the patient's migraine diary entry, including potential correlations, patterns, and suggestions for the treating physician. Keep it short and to the point the doctor is busy.") |
| patient_advice = get_gpt_analysis(entry_text, "You are a supportive health coach specializing in migraine management. Provide friendly, easy-to-understand advice for the patient based on their migraine diary entry. Include actionable tips for managing their condition and potential lifestyle adjustments.") |
|
|
| new_entry = { |
| 'username': st.session_state.user, |
| 'entry_date': date.isoformat(), |
| 'pain_level': pain_level, |
| 'duration': duration, |
| 'triggers': ', '.join(triggers), |
| 'symptoms': ', '.join(symptoms), |
| 'medications': medications, |
| 'notes': notes, |
| 'doctor_analysis': doctor_analysis, |
| 'patient_advice': patient_advice |
| } |
| save_data(new_entry) |
| st.success("Entry added successfully!") |
| st.subheader("Advice for You:") |
| st.write(patient_advice) |
|
|
| def view_entries(is_doctor): |
| st.header("Migraine Entries") |
| with st.sidebar: |
| st.subheader("How to Use Entries View") |
| if is_doctor: |
| st.markdown(""" |
| 1. **Browse Entries**: Scroll through all patient entries. |
| 2. **Expand Details**: Click on an entry to see full details. |
| 3. **Analysis**: Read the doctor's analysis for each entry. |
| 4. **Patient History**: Use this view to track patient progress over time. |
| |
| Tips: |
| - Look for patterns in triggers and symptoms across patients. |
| - Use this information to inform treatment plans and discussions. |
| """) |
| else: |
| st.markdown(""" |
| 1. **Your History**: Browse through your past migraine entries. |
| 2. **Expand Details**: Click on an entry to see full details. |
| 3. **Advice**: Read the personalized advice for each entry. |
| 4. **Track Progress**: Use this view to see how your migraines change over time. |
| |
| Tips: |
| - Look for patterns in your triggers and symptoms. |
| - Discuss recurring patterns with your doctor. |
| - Use the advice to make lifestyle adjustments. |
| """) |
| if is_doctor: |
| user_entries = load_data() |
| st.subheader("All Patient Entries") |
| else: |
| user_entries = load_data(st.session_state.user) |
| st.subheader("Your Entries") |
| |
| user_entries = user_entries.sort_values(by='entry_date', ascending=False) |
| |
| if not user_entries.empty: |
| for _, entry in user_entries.iterrows(): |
| with st.expander(f"Entry for {entry['username']} on {entry['entry_date']} - Pain Level: {entry['pain_level']}"): |
| st.write(f"Duration: {entry['duration']}") |
| st.write(f"Triggers: {entry['triggers']}") |
| st.write(f"Symptoms: {entry['symptoms']}") |
| st.write(f"Medications: {entry['medications']}") |
| st.write(f"Notes: {entry['notes']}") |
| if is_doctor: |
| st.write("Doctor's Analysis:", entry['doctor_analysis']) |
| else: |
| st.write("Advice for Patient:", entry['patient_advice']) |
| else: |
| st.info("No entries found.") |
|
|
| def display_dashboard(is_doctor): |
| st.header("Headache Dashboard") |
| with st.sidebar: |
| st.subheader("How to Use the Dashboard") |
| if is_doctor: |
| st.markdown(""" |
| 1. **Select Patient**: Choose a patient from the dropdown to view their data. |
| 2. **Pain Level Trend**: Observe how pain levels change over time. |
| 3. **Common Triggers**: Identify the most frequent migraine triggers. |
| 4. **Common Symptoms**: See the most reported symptoms. |
| 5. **Statistics**: Review key metrics at a glance. |
| 6. **Recent Entries**: Check the latest migraine reports. |
| |
| Tips: |
| - Use these insights to tailor treatment plans. |
| - Discuss observed patterns with your patients. |
| - Look for correlations between triggers, symptoms, and pain levels. |
| """) |
| else: |
| st.markdown(""" |
| 1. **Pain Level Trend**: See how your pain levels have changed over time. |
| 2. **Common Triggers**: Identify your most frequent migraine triggers. |
| 3. **Common Symptoms**: Review your most reported symptoms. |
| 4. **Statistics**: Get a quick overview of your migraine patterns. |
| 5. **Recent Entries**: Review your latest migraine reports. |
| |
| Tips: |
| - Use the pain level trend to track the effectiveness of treatments. |
| - Pay attention to your common triggers and try to avoid them. |
| - Discuss any patterns you notice with your doctor. |
| - Use insights from the dashboard to make informed lifestyle choices. |
| """) |
| |
| if is_doctor: |
| st.subheader("Select Patient") |
| all_users = load_data()['username'].unique() |
| selected_user = st.selectbox("Choose a patient", all_users) |
| user_entries = load_data(selected_user) |
| else: |
| user_entries = load_data(st.session_state.user) |
|
|
| if not user_entries.empty: |
| col1, col2 = st.columns(2) |
| |
| with col1: |
| st.subheader("Pain Level Over Time") |
| fig = px.line(user_entries, x='entry_date', y='pain_level', title='Pain Level Over Time') |
| st.plotly_chart(fig, use_container_width=True) |
|
|
| with col2: |
| st.subheader("Common Triggers") |
| all_triggers = ', '.join(user_entries['triggers'].dropna()).split(', ') |
| trigger_counts = pd.Series(all_triggers).value_counts().head(5) |
| fig = px.bar(x=trigger_counts.index, y=trigger_counts.values, labels={'x': 'Trigger', 'y': 'Count'}) |
| st.plotly_chart(fig, use_container_width=True) |
|
|
| col1, col2 = st.columns(2) |
|
|
| with col1: |
| st.subheader("Common Symptoms") |
| all_symptoms = ', '.join(user_entries['symptoms'].dropna()).split(', ') |
| symptom_counts = pd.Series(all_symptoms).value_counts().head(5) |
| fig = px.bar(x=symptom_counts.index, y=symptom_counts.values, labels={'x': 'Symptom', 'y': 'Count'}) |
| st.plotly_chart(fig, use_container_width=True) |
|
|
| st.subheader("Migraine Statistics") |
| col1, col2, col3, col4 = st.columns(4) |
| col1.metric("Total Entries", len(user_entries)) |
| col2.metric("Average Pain Level", f"{user_entries['pain_level'].mean():.2f}") |
| col3.metric("Most Common Trigger", trigger_counts.index[0] if not trigger_counts.empty else "N/A") |
| col4.metric("Most Common Symptom", symptom_counts.index[0] if not symptom_counts.empty else "N/A") |
|
|
| st.subheader("Recent Entries") |
| st.dataframe(user_entries[['entry_date', 'pain_level', 'duration', 'triggers', 'symptoms']].sort_values(by='entry_date', ascending=False).head()) |
| else: |
| st.info("No entries found.") |
|
|
| if __name__ == "__main__": |
| main() |