diff --git a/TalkHeal.py b/TalkHeal.py index ad99d30..ab67ce0 100644 --- a/TalkHeal.py +++ b/TalkHeal.py @@ -1,7 +1,12 @@ +# --- 0. IMPORTS --- +import uuid # standard library import import streamlit as st from auth.auth_utils import init_db from components.login_page import show_login_page - + emoji-mood-selector +# --- 1. PAGE CONFIG FIRST --- +from core.config import PAGE_CONFIG +st.set_page_config(**PAGE_CONFIG) st.set_page_config(page_title="TalkHeal", page_icon="πŸ’¬", layout="wide") # --- DB Initialization --- @@ -49,39 +54,56 @@ from core.config import configure_gemini, PAGE_CONFIG from core.utils import get_current_time, create_new_conversation from css.styles import apply_custom_css + +from core.config import configure_gemini, get_tone_prompt, get_selected_mood +from core.utils import save_conversations, load_conversations, get_current_time, create_new_conversation + from components.header import render_header from components.sidebar import render_sidebar from components.chat_interface import render_chat_interface, handle_chat_input from components.mood_dashboard import render_mood_dashboard from components.focus_session import render_focus_session +# --- 1. PAGE CONFIG & CSS --- +apply_custom_css() from components.emergency_page import render_emergency_page from components.profile import apply_global_font_size -# --- 1. INITIALIZE SESSION STATE --- -if "chat_history" not in st.session_state: - st.session_state.chat_history = [] -if "conversations" not in st.session_state: - st.session_state.conversations = load_conversations() -if "active_conversation" not in st.session_state: - st.session_state.active_conversation = -1 -# if "show_emergency_page" not in st.session_state: -# st.session_state.show_emergency_page = False -if "show_focus_session" not in st.session_state: - st.session_state.show_focus_session = False -if "show_mood_dashboard" not in st.session_state: - st.session_state.show_mood_dashboard = False -if "sidebar_state" not in st.session_state: - st.session_state.sidebar_state = "expanded" -if "mental_disorders" not in st.session_state: - st.session_state.mental_disorders = [ +# --- 2. SESSION STATE INITIALIZATION --- +default_values = { + "conversations": [], + "active_conversation": -1, + "send_chat_message": False, + "pre_filled_chat_input": "", + "selected_mood_context": "", + "current_mood_val": "", + "chat_history": [], + "show_emergency_page": False, + "show_focus_session": False, + "show_mood_dashboard": False, + "sidebar_state": "expanded", + "mental_disorders": [ + "Anxiety", "Depression", "Bipolar Disorder", "PTSD", + "OCD", "ADHD", "Eating Disorders", "Schizophrenia" + ] +} + +for key, value in default_values.items(): + if key not in st.session_state: + st.session_state[key] = value + "Depression & Mood Disorders", "Anxiety & Panic Disorders", "Bipolar Disorder", "PTSD & Trauma", "OCD & Related Disorders", "Eating Disorders", "Substance Use Disorders", "ADHD & Neurodevelopmental", "Personality Disorders", "Sleep Disorders" - ] -if "selected_tone" not in st.session_state: - st.session_state.selected_tone = "Compassionate Listener" + ], + "selected_tone": "Compassionate Listener", + "selected_mood": "πŸ™‚" +} + +for key, value in default_values.items(): + if key not in st.session_state: + st.session_state[key] = value # --- 2. SET PAGE CONFIG --- apply_global_font_size() @@ -99,29 +121,26 @@ "Mindfulness Guide": "You are a mindfulness guide β€” calm, slow, and grounding β€” focused on breathing, presence, and awareness." } -with st.sidebar: - st.header("🧠 Choose Your AI Tone") - selected_tone = st.selectbox( - "Select a personality tone:", - options=list(TONE_OPTIONS.keys()), - index=0 - ) - st.session_state.selected_tone = selected_tone +} -# --- 5. DEFINE FUNCTION TO GET TONE PROMPT --- -def get_tone_prompt(): - return TONE_OPTIONS.get(st.session_state.get("selected_tone", "Compassionate Listener"), TONE_OPTIONS["Compassionate Listener"]) +for key, val in default_values.items(): + if key not in st.session_state: + st.session_state[key] = val -# --- 6. RENDER SIDEBAR --- +# --- 3. GEMINI MODEL SETUP --- +model = configure_gemini() + +# --- 4. SIDEBAR --- render_sidebar() -# --- 7. PAGE ROUTING --- +# --- 5. MAIN LOGIC CONTAINER --- main_area = st.container() +# --- 6. Load or Start Conversation --- if not st.session_state.conversations: - saved_conversations = load_conversations() - if saved_conversations: - st.session_state.conversations = saved_conversations + saved = load_conversations() + if saved: + st.session_state.conversations = saved if st.session_state.active_conversation == -1: st.session_state.active_conversation = 0 else: @@ -129,102 +148,27 @@ def get_tone_prompt(): st.session_state.active_conversation = 0 st.rerun() -# --- 8. RENDER PAGE --- -# if st.session_state.get("show_emergency_page"): -# with main_area: -# render_emergency_page() -# else: -if st.session_state.get("show_focus_session"): - with main_area: +# --- 7. ROUTING --- +with main_area: + if st.session_state.get("show_emergency_page"): + render_emergency_page() + elif st.session_state.get("show_focus_session"): render_focus_session() -elif st.session_state.get("show_mood_dashboard"): - with main_area: + elif st.session_state.get("show_mood_dashboard"): render_mood_dashboard() -else: - with main_area: + else: render_header() st.markdown(f""" -
-

πŸ—£οΈ Current Chatbot Tone: {st.session_state['selected_tone']}

-
-""", unsafe_allow_html=True) - - # --- Mood Slider with Keyboard Navigation --- - def mood_slider(): - slider_html = """ -
- - -
Neutral
- - -
- """ - mood_value = st.components.v1.html(slider_html, height=100) - return mood_value - - # --- Mood Slider --- - st.subheader("😊 Track Your Mood") - mood_options = ['Very Sad', 'Sad', 'Neutral', 'Happy', 'Very Happy'] - mood = st.slider( - 'Select your mood', - min_value=1, max_value=5, value=3, step=1 -) - coping_tips = { - 1: "It’s okay to feel this way. Try some deep breathing exercises to find calm.", - 2: "Consider writing down your thoughts in the journal to process your feelings.", - 3: "A short walk or some light stretching might help you feel balanced.", - 4: "Great to hear you’re feeling happy! Share something positive in your journal.", - 5: "You’re shining today! Keep spreading that positivity with a kind act." -} - st.write(f"Selected mood: {mood_options[mood-1]}") - st.write(f"Coping tip: {coping_tips.get(mood, 'Let’s explore how you’re feeling.')}") - +
+

πŸ—£οΈ Current Chatbot Tone: {st.session_state['selected_tone']}

+

🧠 Mood Selected: {get_selected_mood()}

+
+ """, unsafe_allow_html=True) + render_chat_interface() - handle_chat_input(model, system_prompt=get_tone_prompt()) + handle_chat_input(model=model, system_prompt=get_tone_prompt()) -# --- 9. SCROLL SCRIPT --- +# --- 8. AUTO SCROLL SCRIPT --- st.markdown(""" -""", unsafe_allow_html=True) +""", unsafe_allow_html=True) + diff --git a/TalkHeal.py~ b/TalkHeal.py~ new file mode 100644 index 0000000..b8f4dfc --- /dev/null +++ b/TalkHeal.py~ @@ -0,0 +1,86 @@ +# --- 0. IMPORTS --- +import streamlit as st +import google.generativeai as genai + +# --- 1. FIRST COMMAND: PAGE CONFIG --- +from core.config import PAGE_CONFIG +st.set_page_config(**PAGE_CONFIG) + +# --- 2. CONTINUED IMPORTS --- +from core.utils import save_conversations, load_conversations, get_current_time, create_new_conversation +from core.config import configure_gemini, get_tone_prompt, get_selected_mood +from css.styles import apply_custom_css +from components.header import render_header +from components.sidebar import render_sidebar +from components.chat_interface import render_chat_interface, handle_chat_input +from components.emergency_page import render_emergency_page + +# --- 3. SESSION STATE INITIALIZATION --- +if "chat_history" not in st.session_state: + st.session_state.chat_history = [] +if "conversations" not in st.session_state: + st.session_state.conversations = load_conversations() +if "active_conversation" not in st.session_state: + st.session_state.active_conversation = -1 +if "show_emergency_page" not in st.session_state: + st.session_state.show_emergency_page = False +if "sidebar_state" not in st.session_state: + st.session_state.sidebar_state = "expanded" +if "mental_disorders" not in st.session_state: + st.session_state.mental_disorders = [ + "Depression & Mood Disorders", "Anxiety & Panic Disorders", "Bipolar Disorder", + "PTSD & Trauma", "OCD & Related Disorders", "Eating Disorders", + "Substance Use Disorders", "ADHD & Neurodevelopmental", "Personality Disorders", + "Sleep Disorders" + ] +if "selected_tone" not in st.session_state: + st.session_state.selected_tone = "Compassionate Listener" +if "selected_mood" not in st.session_state: + st.session_state.selected_mood = "πŸ™‚" # Default emoji mood + +# --- 4. STYLES & GEMINI SETUP --- +apply_custom_css() +model = configure_gemini() + +# --- 5. SIDEBAR --- +render_sidebar() + +# --- 6. MAIN PAGE ROUTING LOGIC --- +main_area = st.container() + +# Load conversations or start a new one +if not st.session_state.conversations: + saved_convos = load_conversations() + if saved_convos: + st.session_state.conversations = saved_convos + if st.session_state.active_conversation == -1: + st.session_state.active_conversation = 0 + else: + create_new_conversation() + st.session_state.active_conversation = 0 + st.rerun() + +# --- 7. MAIN VIEW DISPLAY --- +if st.session_state.get("show_emergency_page"): + with main_area: + render_emergency_page() +else: + with main_area: + render_header() + st.subheader(f"πŸ—£οΈ Current Chatbot Tone: **{st.session_state['selected_tone']}**") + st.markdown(f"**🧠 Mood Selected:** {get_selected_mood()}") + render_chat_interface() + handle_chat_input(model, system_prompt=get_tone_prompt()) + +# --- 8. AUTO SCROLL SCRIPT --- +st.markdown(""" + +""", unsafe_allow_html=True) diff --git a/api.py b/api.py new file mode 100644 index 0000000..85eb2cd --- /dev/null +++ b/api.py @@ -0,0 +1,5 @@ +import google.generativeai as genai +genai.configure(api_key="AIzaSyAgtTtPjJzTaNSrXaWFkMEJKIpMiFI3QNw") +model = genai.GenerativeModel("gemini-1.5-flash") +response = model.generate_content("Hello!") +print(response.text) diff --git a/components/ resources.py b/components/ resources.py new file mode 100644 index 0000000..190f0c7 --- /dev/null +++ b/components/ resources.py @@ -0,0 +1,63 @@ +# resource.py + +# --- Global Crisis Resources --- +GLOBAL_RESOURCES = [ + {"name": "Befrienders Worldwide", "desc": "Emotional support to prevent suicide worldwide.", + "url": "https://www.befrienders.org/"}, + {"name": "International Association for Suicide Prevention (IASP)", "desc": "Find a crisis center anywhere in the world.", + "url": "https://www.iasp.info/resources/Crisis_Centres/"}, + {"name": "Crisis Text Line", "desc": "Text-based support available in the US, UK, Canada, and Ireland.", + "url": "https://www.crisistextline.org/"}, + {"name": "The Trevor Project", "desc": "Crisis intervention and suicide prevention for LGBTQ young people.", + "url": "https://www.thetrevorproject.org/"}, + {"name": "Child Helpline International", "desc": "A global network of child helplines for young people in need of help.", + "url": "https://www.childhelplineinternational.org/"} +] + +# --- Mental Health Resources for Topics --- +mental_health_resources_full = { + "Depression & Mood Disorders": { + "description": "Information on understanding and coping with depression, persistent depressive disorder, and other mood-related challenges.", + "links": [ + {"label": "NIMH - Depression", "url": "https://www.nimh.nih.gov/health/topics/depression"}, + {"label": "Mayo Clinic - Depression", "url": "https://www.mayoclinic.org/diseases-conditions/depression/symptoms-causes/syc-20356007"} + ] + }, + "Anxiety & Panic Disorders": { + "description": "Guidance on managing generalized anxiety, social anxiety, panic attacks, and phobias.", + "links": [ + {"label": "ADAA - Anxiety & Depression", "url": "https://adaa.org/"}, + {"label": "NIMH - Anxiety Disorders", "url": "https://www.nimh.nih.gov/health/topics/anxiety-disorders"} + ] + }, + "Bipolar Disorder": { + "description": "Understanding the complexities of bipolar disorder, including mood swings and treatment options.", + "links": [ + {"label": "NIMH - Bipolar Disorder", "url": "https://www.nimh.nih.gov/health/topics/bipolar-disorder"} + ] + }, + "PTSD & Trauma": { + "description": "Resources for individuals experiencing post-traumatic stress disorder and other trauma-related conditions.", + "links": [ + {"label": "PTSD: National Center", "url": "https://www.ptsd.va.gov/"} + ] + }, + "OCD & Related Disorders": { + "description": "Support and information for obsessive-compulsive disorder, body dysmorphic disorder, and hoarding disorder.", + "links": [ + {"label": "IOCDF - OCD", "url": "https://iocdf.org/"} + ] + }, + "Coping Skills & Self-Care": { + "description": "Practical strategies and techniques for stress management, emotional regulation, and daily well-being.", + "links": [ + {"label": "HelpGuide - Stress Management", "url": "https://www.helpguide.org/articles/stress/stress-management.htm"} + ] + }, + "Therapy & Treatment Options": { + "description": "Overview of various therapeutic approaches, including CBT, DBT, and finding a therapist.", + "links": [ + {"label": "APA - Finding a Therapist", "url": "https://www.apa.org/helpcenter/choose-therapist"} + ] + } +} diff --git a/components/chat_interface.py b/components/chat_interface.py index 874a329..92aa2a1 100644 --- a/components/chat_interface.py +++ b/components/chat_interface.py @@ -1,10 +1,10 @@ import streamlit as st +import streamlit as st import streamlit.components.v1 as components from datetime import datetime from core.utils import get_current_time, get_ai_response, save_conversations -import requests -# Inject JS to get user's local time zone +# --- Inject JS to get user's local time zone --- def set_user_time_in_session(): if "user_time_offset" not in st.session_state: components.html(""" @@ -33,37 +33,45 @@ def set_user_time_in_session(): set_user_time_in_session() -# Display chat messages -def render_chat_interface(): - if st.session_state.active_conversation >= 0: - active_convo = st.session_state.conversations[st.session_state.active_conversation] - - if not active_convo["messages"]: - st.markdown(f""" -
- Hello! I'm TalkHeal, your mental health companion πŸ€—
- How are you feeling today? You can write below or start a new topic. -
{get_current_time()}
-
- """, unsafe_allow_html=True) - - for msg in active_convo["messages"]: - css_class = "user-message" if msg["sender"] == "user" else "bot-message" - st.markdown(f""" -
- {msg["message"]} -
{msg["time"]}
-
- """, unsafe_allow_html=True) - -# Handle chat input and generate AI response +# --- Render chat messages --- +def render_chat_interface(): + st.markdown("### πŸ—¨οΈ TalkHeal Conversation") + + active_index = st.session_state.get("active_conversation", -1) + if active_index == -1 or active_index >= len(st.session_state.conversations): + st.info("Start a conversation to see messages here.") + return + + conversation = st.session_state.conversations[active_index] + + if not conversation["messages"]: + st.markdown(f""" +
+ Hello! I'm TalkHeal, your mental health companion πŸ€—
+ How are you feeling today? You can write below or start a new topic. +
{get_current_time()}
+
+ """, unsafe_allow_html=True) + + for msg in conversation["messages"]: + sender = msg["sender"] + message = msg["message"] + time = msg["time"] + + if sender == "user": + with st.chat_message("user", avatar="πŸ§β€β™€οΈ"): + st.markdown(f"**You:** {message}\n\n{time}", unsafe_allow_html=True) + else: + with st.chat_message("assistant", avatar="πŸ’¬"): + st.markdown(f"{message}\n\n{time}", unsafe_allow_html=True) + def handle_chat_input(model, system_prompt): - if "pre_filled_chat_input" not in st.session_state: - st.session_state.pre_filled_chat_input = "" - initial_value = st.session_state.pre_filled_chat_input + pre_filled = st.session_state.get("pre_filled_chat_input", "") st.session_state.pre_filled_chat_input = "" - with st.form(key="chat_form", clear_on_submit=True): + form_key = f"chat_form_{st.session_state.get('active_conversation', 0)}" + + with st.form(key=form_key, clear_on_submit=True): col1, col2 = st.columns([5, 1]) with col1: user_input = st.text_input( @@ -71,13 +79,15 @@ def handle_chat_input(model, system_prompt): key="message_input", label_visibility="collapsed", placeholder="Type your message here...", - value=initial_value + value=pre_filled ) with col2: send_pressed = st.form_submit_button("Send", use_container_width=True) - if (send_pressed or st.session_state.get("send_chat_message", False)) and user_input.strip(): - if 'send_chat_message' in st.session_state: + auto_send = st.session_state.get("send_chat_message", False) + + if (send_pressed or auto_send) and user_input.strip(): + if auto_send: st.session_state.send_chat_message = False if st.session_state.active_conversation >= 0: @@ -91,17 +101,15 @@ def handle_chat_input(model, system_prompt): "time": current_time }) - # Set title if it's the first message if len(active_convo["messages"]) == 1: title = user_input[:30] + "..." if len(user_input) > 30 else user_input active_convo["title"] = title save_conversations(st.session_state.conversations) - # Format memory def format_memory(convo_history, max_turns=10): context = "" - for msg in convo_history[-max_turns*2:]: # user + bot per turn + for msg in convo_history[-max_turns*2:]: sender = "User" if msg["sender"] == "user" else "Bot" context += f"{sender}: {msg['message']}\n" return context @@ -109,8 +117,15 @@ def format_memory(convo_history, max_turns=10): try: with st.spinner("TalkHeal is thinking..."): memory = format_memory(active_convo["messages"]) - prompt = f"{system_prompt}\n\n{memory}\nUser: {user_input.strip()}\nBot:" - ai_response = get_ai_response(prompt, model) + mood = st.session_state.get("selected_mood_context") or st.session_state.get("current_mood_val", "okay") + + prompt = ( + f"{system_prompt}\n\n" + f"User is feeling {mood}. Respond empathetically.\n\n" + f"{memory}\nUser: {user_input.strip()}\nBot:" + ) + + ai_response = get_ai_response(prompt, "gemini-1.5-flash") active_convo["messages"].append({ "sender": "bot", @@ -142,3 +157,5 @@ def format_memory(convo_history, max_turns=10): save_conversations(st.session_state.conversations) st.rerun() + +__all__ = ["render_chat_interface", "handle_chat_input"] diff --git a/components/sidebar.py b/components/sidebar.py index 38c21a2..b24ffba 100644 --- a/components/sidebar.py +++ b/components/sidebar.py @@ -8,6 +8,7 @@ from streamlit_js_eval import streamlit_js_eval import requests + # --- Structured Emergency Resources --- GLOBAL_RESOURCES = [ {"name": "Befrienders Worldwide", "desc": "Emotional support to prevent suicide worldwide.", @@ -139,6 +140,10 @@ def get_user_country(): } +import streamlit as st +from core.utils import save_conversations +from core.config import create_new_conversation + def render_sidebar(): """Renders the left and right sidebars.""" @@ -217,51 +222,38 @@ def render_sidebar(): else: - st.warning( - "⚠️ Are you sure you want to delete this conversation?") + st.warning("⚠️ Are you sure you want to delete this conversation?") col_confirm, col_cancel = st.columns(2) if col_confirm.button("Yes, delete", key="confirm_delete"): del st.session_state.conversations[st.session_state.delete_candidate] - - from core.utils import save_conversations save_conversations(st.session_state.conversations) - del st.session_state.delete_candidate st.session_state.active_conversation = -1 st.rerun() - if "cancel_clicked" not in st.session_state: - st.session_state.cancel_clicked = False - if col_cancel.button("Cancel", key="cancel_delete"): - if not st.session_state.cancel_clicked: - st.session_state.cancel_clicked = True - del st.session_state.delete_candidate - st.rerun() - else: - st.session_state.cancel_clicked = False - + del st.session_state.delete_candidate + st.rerun() else: st.info("No conversations yet. Start a new chat!") st.markdown("---") - # --- DEDICATED EMERGENCY PAGE BUTTON --- if st.button("🚨 Emergency Help", use_container_width=True, type="secondary"): st.session_state.show_emergency_page = True st.rerun() +# --- FOCUS SESSION BUTTON --- +if st.button("🧘 Focus Session", use_container_width=True, type="secondary", key="focus_session_button"): + st.session_state.show_focus_session = True + st.rerun() - # --- FOCUS SESSION BUTTON --- - if st.button("🧘 Focus Session", use_container_width=True, type="secondary", key="focus_session_button"): - st.session_state.show_focus_session = True - st.rerun() +# --- MOOD DASHBOARD BUTTON --- +render_mood_dashboard_button() - # --- MOOD DASHBOARD BUTTON --- - render_mood_dashboard_button() +# --- Mood Tracker --- +with st.expander("🧠 Mental Health Check", expanded=True): - # --- 3. Dynamic Mood Tracker & Micro-Journal (Fixed Tip & New Button) --- - with st.expander("🧠 Mental Health Check"): st.markdown("**How are you feeling today?**") mood_options_map = { @@ -274,122 +266,133 @@ def render_sidebar(): mood_labels = list(mood_options_map.keys()) selected_mood_label = st.radio( - "Mood Scale", + label="Mood Scale", options=mood_labels, - index=mood_labels.index( - "😊 Okay") if "😊 Okay" in mood_labels else 2, + index=2, key="mood_selector_radio", horizontal=True, label_visibility="collapsed" ) - st.session_state.current_mood_val = mood_options_map[selected_mood_label] - if st.session_state.current_mood_val: - st.markdown("") - journal_prompt_text = { - "very_low": "What's weighing on your mind today?", - "low": "What are your thoughts right now?", - "okay": "Anything specific on your mind today?", - "good": "What made you feel good today?", - "great": "What's making you shine today?" - }.get(st.session_state.current_mood_val, "Reflect on your mood:") - - # Initialize journal entry for the current session - if "mood_journal_entry" not in st.session_state: + current_mood_val = mood_options_map[selected_mood_label] + st.session_state["current_mood_val"] = current_mood_val + + journal_prompts = { + "very_low": "What's weighing on your mind today?", + "low": "What are your thoughts right now?", + "okay": "Anything specific on your mind today?", + "good": "What made you feel good today?", + "great": "What's making you shine today?" + } + + st.markdown(f"**πŸ“ {journal_prompts[current_mood_val]}**") + journal_input = st.text_area("Your thoughts:", key="mood_journal_area", height=100) + + # Initialize states + if "mood_journal_entry" not in st.session_state: + st.session_state.mood_journal_entry = "" + if "mood_tip_display" not in st.session_state: + st.session_state.mood_tip_display = "" + if "mood_entry_status" not in st.session_state: + st.session_state.mood_entry_status = "" + + tips_for_mood = { + "very_low": "Remember, it's okay not to be okay. Consider connecting with a professional.", + "low": "Even small steps help. Try a brief mindful moment or gentle activity.", + "okay": "Keep nurturing your well-being. What's one thing you can do to maintain this?", + "good": "That's wonderful! Savor this feeling and perhaps share your positivity.", + "great": "Fantastic! How can you carry this energy forward into your day?" + }.get(current_mood_val, "A general tip for your mood.") + + st.markdown("") + col1, col2 = st.columns(2) + + with col1: + if st.button("Get Tip & Save Entry", key="save_mood_entry", use_container_width=True): + st.session_state.mood_tip_display = tips_for_mood + st.session_state.mood_entry_status = f"Your mood entry for '{selected_mood_label}' has been noted." st.session_state.mood_journal_entry = "" - # Initialize state for displaying tips and status - if "mood_tip_display" not in st.session_state: - st.session_state.mood_tip_display = "" - if "mood_entry_status" not in st.session_state: - st.session_state.mood_entry_status = "" - - st.text_area( - f"✏️ {journal_prompt_text}", - key="mood_journal_area", - value=st.session_state.mood_journal_entry, - height=70 - ) +# Context reason dropdown +st.markdown("**Why are you feeling this way?**") +context_reasons = ["No specific reason", "Work", "Family", "Health", "Relationships", "Financial", "Social", "Personal goals", "Weather", "Other"] +selected_reason = st.selectbox( + "Select a reason (optional):", + options=context_reasons, + key="mood_context_reason", + label_visibility="collapsed" +) + +# Activity checkboxes +st.markdown("**What did you do today?** (optional)") +activities = [] +col1, col2 = st.columns(2) +with col1: + if st.checkbox("βœ… Exercise", key="activity_exercise"): + activities.append("Exercise") + if st.checkbox("βœ… Socialized", key="activity_socialized"): + activities.append("Socialized") +with col2: + if st.checkbox("βœ… Ate healthy", key="activity_healthy_eating"): + activities.append("Ate healthy") + if st.checkbox("βœ… Slept well", key="activity_slept_well"): + activities.append("Slept well") + +tips_for_mood = { + "very_low": "Remember, it's okay not to be okay. Consider connecting with a professional.", + "low": "Even small steps help. Try a brief mindful moment or gentle activity.", + "okay": "Keep nurturing your well-being. What's one thing you can do to maintain this?", + "good": "That's wonderful! Savor this feeling and perhaps share your positivity.", + "great": "Fantastic! How can you carry this energy forward into your day?" +}.get(st.session_state.current_mood_val, "A general tip for your mood.") + +st.markdown("") +col_tip_save, col_ask_TalkHeal = st.columns(2) + +with col_tip_save: + if st.button("Get Tip & Save Entry", key="save_mood_entry", use_container_width=True): + # Save to mood dashboard + if "mood_tracker" not in st.session_state: + st.session_state.mood_tracker = MoodTracker() + + mood_level = st.session_state.current_mood_val + notes = st.session_state.get("mood_journal_area", "") + context_reason = st.session_state.get("mood_context_reason", "No specific reason") + activities = [] + if st.session_state.get("activity_exercise", False): + activities.append("Exercise") + if st.session_state.get("activity_socialized", False): + activities.append("Socialized") + if st.session_state.get("activity_healthy_eating", False): + activities.append("Ate healthy") + if st.session_state.get("activity_slept_well", False): + activities.append("Slept well") + + st.session_state.mood_tracker.add_mood_entry(mood_level, notes, context_reason, activities) + + st.session_state.mood_tip_display = tips_for_mood + st.session_state.mood_entry_status = f"Your mood entry for '{selected_mood_label}' has been saved to your dashboard!" - # Context reason dropdown - st.markdown("**Why are you feeling this way?**") - context_reasons = ["No specific reason", "Work", "Family", "Health", "Relationships", "Financial", "Social", "Personal goals", "Weather", "Other"] - selected_reason = st.selectbox( - "Select a reason (optional):", - options=context_reasons, - key="mood_context_reason", - label_visibility="collapsed" - ) +with col_ask_TalkHeal: + if st.button("Ask TalkHeal", key="ask_peace_pulse_from_mood", use_container_width=True): + if st.session_state.mood_journal_area.strip(): + st.session_state.pre_filled_chat_input = st.session_state.mood_journal_area + st.session_state.send_chat_message = True - # Activity checkboxes - st.markdown("**What did you do today?** (optional)") - activities = [] - col1, col2 = st.columns(2) - with col1: - if st.checkbox("βœ… Exercise", key="activity_exercise"): - activities.append("Exercise") - if st.checkbox("βœ… Socialized", key="activity_socialized"): - activities.append("Socialized") - with col2: - if st.checkbox("βœ… Ate healthy", key="activity_healthy_eating"): - activities.append("Ate healthy") - if st.checkbox("βœ… Slept well", key="activity_slept_well"): - activities.append("Slept well") - - tips_for_mood = { - "very_low": "Remember, it's okay not to be okay. Consider connecting with a professional.", - "low": "Even small steps help. Try a brief mindful moment or gentle activity.", - "okay": "Keep nurturing your well-being. What's one thing you can do to maintain this?", - "good": "That's wonderful! Savor this feeling and perhaps share your positivity.", - "great": "Fantastic! How can you carry this energy forward into your day?" - }.get(st.session_state.current_mood_val, "A general tip for your mood.") - - st.markdown("") - col_tip_save, col_ask_TalkHeal = st.columns(2) - - with col_tip_save: - if st.button("Get Tip & Save Entry", key="save_mood_entry", use_container_width=True): - # Save to mood dashboard - if "mood_tracker" not in st.session_state: - st.session_state.mood_tracker = MoodTracker() - - mood_level = st.session_state.current_mood_val - notes = st.session_state.get("mood_journal_area", "") - context_reason = st.session_state.get("mood_context_reason", "No specific reason") - activities = [] - if st.session_state.get("activity_exercise", False): - activities.append("Exercise") - if st.session_state.get("activity_socialized", False): - activities.append("Socialized") - if st.session_state.get("activity_healthy_eating", False): - activities.append("Ate healthy") - if st.session_state.get("activity_slept_well", False): - activities.append("Slept well") - - st.session_state.mood_tracker.add_mood_entry(mood_level, notes, context_reason, activities) - - st.session_state.mood_tip_display = tips_for_mood - st.session_state.mood_entry_status = f"Your mood entry for '{selected_mood_label}' has been saved to your dashboard!" st.session_state.mood_journal_entry = "" + st.session_state.mood_tip_display = "" + st.session_state.mood_entry_status = "" + st.rerun() + else: + st.warning("Please enter your thoughts before asking TalkHeal.") + + if st.session_state.mood_tip_display: + st.success(st.session_state.mood_tip_display) + st.session_state.mood_tip_display = "" + + if st.session_state.mood_entry_status: + st.info(st.session_state.mood_entry_status) + st.session_state.mood_entry_status = "" - with col_ask_TalkHeal: - if st.button("Ask TalkHeal", key="ask_peace_pulse_from_mood", use_container_width=True): - if st.session_state.mood_journal_area.strip(): - st.session_state.pre_filled_chat_input = st.session_state.mood_journal_area - st.session_state.send_chat_message = True - st.session_state.mood_journal_entry = "" - st.session_state.mood_tip_display = "" - st.session_state.mood_entry_status = "" - st.rerun() - else: - st.warning( - "Please enter your thoughts before asking TalkHeal.") - - if st.session_state.mood_tip_display: - st.success(st.session_state.mood_tip_display) - st.session_state.mood_tip_display = "" - if st.session_state.mood_entry_status: - st.info(st.session_state.mood_entry_status) - st.session_state.mood_entry_status = "" # --- 4. Resource Hub with Categories & Search --- with st.expander("πŸ“š Resources & Knowledge Base"): diff --git a/components/sidebar.py~ b/components/sidebar.py~ new file mode 100644 index 0000000..fd274f2 --- /dev/null +++ b/components/sidebar.py~ @@ -0,0 +1,420 @@ +from css.styles import apply_custom_css +apply_custom_css() + +import streamlit as st +import webbrowser +from datetime import datetime +from core.utils import create_new_conversation, get_current_time +from core.theme import get_current_theme, toggle_theme, set_palette, PALETTES +#from core.resource import GLOBAL_RESOURCES, mental_health_resources_full + + +# --- Structured Emergency Resources --- +GLOBAL_RESOURCES = [ + {"name": "Befrienders Worldwide", "desc": "Emotional support to prevent suicide worldwide.", + "url": "https://www.befrienders.org/"}, + {"name": "International Association for Suicide Prevention (IASP)", "desc": "Find a crisis center anywhere in the world.", + "url": "https://www.iasp.info/resources/Crisis_Centres/"}, + {"name": "Crisis Text Line", "desc": "Text-based support available in the US, UK, Canada, and Ireland.", + "url": "https://www.crisistextline.org/"}, + {"name": "The Trevor Project", "desc": "Crisis intervention and suicide prevention for LGBTQ young people.", + "url": "https://www.thetrevorproject.org/"}, + {"name": "Child Helpline International", "desc": "A global network of child helplines for young people in need of help.", + "url": "https://www.childhelplineinternational.org/"} +] + +mental_health_resources_full = { + "Depression & Mood Disorders": { + "description": "Information on understanding and coping with depression, persistent depressive disorder, and other mood-related challenges.", + "links": [ + {"label": "NIMH - Depression", + "url": "https://www.nimh.nih.gov/health/topics/depression"}, + {"label": "Mayo Clinic - Depression", + "url": "https://www.mayoclinic.org/diseases-conditions/depression/symptoms-causes/syc-20356007"} + ] + }, + "Anxiety & Panic Disorders": { + "description": "Guidance on managing generalized anxiety, social anxiety, panic attacks, and phobias.", + "links": [ + {"label": "ADAA - Anxiety & Depression", "url": "https://adaa.org/"}, + {"label": "NIMH - Anxiety Disorders", + "url": "https://www.nimh.nih.gov/health/topics/anxiety-disorders"} + ] + }, + "Bipolar Disorder": { + "description": "Understanding the complexities of bipolar disorder, including mood swings and treatment options.", + "links": [ + {"label": "NIMH - Bipolar Disorder", + "url": "https://www.nimh.nih.gov/health/topics/bipolar-disorder"} + ] + }, + "PTSD & Trauma": { + "description": "Resources for individuals experiencing post-traumatic stress disorder and other trauma-related conditions.", + "links": [ + {"label": "PTSD: National Center", "url": "https://www.ptsd.va.gov/"} + ] + }, + "OCD & Related Disorders": { + "description": "Support and information for obsessive-compulsive disorder, body dysmorphic disorder, and hoarding disorder.", + "links": [ + {"label": "IOCDF - OCD", "url": "https://iocdf.org/"} + ] + }, + "Coping Skills & Self-Care": { + "description": "Practical strategies and techniques for stress management, emotional regulation, and daily well-being.", + "links": [ + {"label": "HelpGuide - Stress Management", + "url": "https://www.helpguide.org/articles/stress/stress-management.htm"} + ] + }, + "Therapy & Treatment Options": { + "description": "Overview of various therapeutic approaches, including CBT, DBT, and finding a therapist.", + "links": [ + {"label": "APA - Finding a Therapist", + "url": "https://www.apa.org/helpcenter/choose-therapist"} + ] + } +} + +import streamlit as st +from core.utils import save_conversations +from core.config import create_new_conversation +import uuid # Add this at the top of the file if not already imported + +def render_sidebar(): + """Renders the left and right sidebars.""" + + with st.sidebar: + st.markdown("### πŸ’¬ Conversations") + + # Initialize session state + if "show_quick_start_prompts" not in st.session_state: + st.session_state.show_quick_start_prompts = False + if "pre_filled_chat_input" not in st.session_state: + st.session_state.pre_filled_chat_input = "" + if "send_chat_message" not in st.session_state: + st.session_state.send_chat_message = False + + # βœ… Fixed unique key β€” use a constant key only once + # βœ… Unique key fix using session_state + +# Inside render_sidebar() + unique_chat_key = f"sidebar_new_chat_button_{uuid.uuid4()}" + + if st.button("βž• New Chat", key=unique_chat_key, use_container_width=True, type="primary"): + create_new_conversation() + st.session_state.show_quick_start_prompts = True + st.rerun() + + + + + if st.session_state.show_quick_start_prompts: + st.markdown("---") + st.markdown("**Start with a common topic:**") + quick_prompts = [ + "Feeling overwhelmed", + "Need to vent about my day", + "How to manage stress?", + "Tell me about anxiety" + ] + qp_cols = st.columns(2) + for i, prompt in enumerate(quick_prompts): + with qp_cols[i % 2]: + if st.button(f"✨ {prompt}", key=f"qp_{i}", use_container_width=True): + st.session_state.pre_filled_chat_input = prompt + st.session_state.send_chat_message = True + st.session_state.show_quick_start_prompts = False + st.rerun() + + st.markdown("---") + + if st.session_state.conversations: + if "delete_candidate" not in st.session_state: + for i, convo in enumerate(st.session_state.conversations): + is_active = i == st.session_state.active_conversation + button_style_icon = "🟒" if is_active else "πŸ“" + + col1, col2 = st.columns([5, 1]) + with col1: + if st.button( + f"{button_style_icon} {convo['title'][:22]}...", + key=f"convo_{i}", + help=f"Started: {convo['date']}", + use_container_width=True + ): + st.session_state.active_conversation = i + st.rerun() + with col2: + if st.button("πŸ—‘οΈ", key=f"delete_{i}", type="primary"): + st.session_state.delete_candidate = i + st.rerun() + + else: + st.warning("⚠️ Are you sure you want to delete this conversation?") + col_confirm, col_cancel = st.columns(2) + + if col_confirm.button("Yes, delete", key="confirm_delete"): + del st.session_state.conversations[st.session_state.delete_candidate] + save_conversations(st.session_state.conversations) + del st.session_state.delete_candidate + st.session_state.active_conversation = -1 + st.rerun() + + if col_cancel.button("Cancel", key="cancel_delete"): + del st.session_state.delete_candidate + st.rerun() + else: + st.info("No conversations yet. Start a new chat!") + + st.markdown("---") + + if st.button("🚨 Emergency Help", use_container_width=True, type="secondary"): + st.session_state.show_emergency_page = True + st.rerun() + + # --- Mood Tracker --- + with st.expander("🧠 Mental Health Check", expanded=True): + st.markdown("**How are you feeling today?**") + + mood_options_map = { + "πŸ˜” Very Low": "very_low", + "😐 Low": "low", + "😊 Okay": "okay", + "πŸ˜„ Good": "good", + "🌟 Great": "great" + } + mood_labels = list(mood_options_map.keys()) + + selected_mood_label = st.radio( + label="Mood Scale", + options=mood_labels, + index=2, + key="mood_selector_radio", + horizontal=True, + label_visibility="collapsed" + ) + + # Get mood key from label and save in session + current_mood_val = mood_options_map[selected_mood_label] + st.session_state["current_mood_val"] = current_mood_val + + # Prompt based on mood + journal_prompts = { + "very_low": "What's weighing on your mind today?", + "low": "What are your thoughts right now?", + "okay": "Anything specific on your mind today?", + "good": "What made you feel good today?", + "great": "What's making you shine today?" + } + + st.markdown(f"**πŸ“ {journal_prompts[current_mood_val]}**") + journal_input = st.text_area("Your thoughts:", key="mood_journal_area", height=100) + + # Tips based on mood (using mood *value*, not label) + # Mood-based tips dictionary + tips_for_mood = { + "very_low": "Remember, it's okay not to be okay. Consider connecting with a professional.", + "low": "Even small steps help. Try a brief mindful moment or gentle activity.", + "okay": "Keep nurturing your well-being. What's one thing you can do to maintain this?", + "good": "That's wonderful! Savor this feeling and perhaps share your positivity.", + "great": "Fantastic! How can you carry this energy forward into your day?" + } + + # Get the tip for the selected mood + tip = tips_for_mood.get(current_mood_val, "A general tip for your mood.") + + # Two buttons: Get Tip & Save Entry and Ask TalkHeal + col1, col2 = st.columns(2) + + with col1: + if st.button("Get Tip & Save Entry", key="save_mood_entry", use_container_width=True): + st.session_state.mood_tip_display = tip # βœ… show only selected mood tip + st.session_state.mood_entry_status = f"Your mood entry for '{selected_mood_label}' has been noted." + st.session_state.mood_journal_entry = journal_input # βœ… store the journal input + + with col2: + if st.button("Ask TalkHeal", key="ask_peace_pulse_from_mood", use_container_width=True): + if journal_input.strip(): + st.session_state.pre_filled_chat_input = journal_input + st.session_state.send_chat_message = True + st.session_state.mood_journal_entry = "" + st.session_state.mood_tip_display = "" + st.session_state.mood_entry_status = "" + st.rerun() + else: + st.warning("Please enter your thoughts before asking TalkHeal.") + + if st.session_state.get("mood_tip_display"): + st.success(st.session_state.mood_tip_display) + st.session_state.mood_tip_display = "" + + if st.session_state.get("mood_entry_status"): + st.info(st.session_state.mood_entry_status) + st.session_state.mood_entry_status = "" + + + # --- 4. Resource Hub with Categories & Search --- + with st.expander("πŸ“š Resources & Knowledge Base"): + st.markdown("**Explore topics or search for help:**") + + resource_search_query = st.text_input( + "Search resources...", key="resource_search", placeholder="e.g., 'anxiety tips', 'therapy'", label_visibility="collapsed") + + if resource_search_query: + filtered_topics = [ + topic for topic in mental_health_resources_full + if resource_search_query.lower() in topic.lower() or + any(resource_search_query.lower() in link['label'].lower() for link in mental_health_resources_full[topic]['links']) or + resource_search_query.lower( + ) in mental_health_resources_full[topic]['description'].lower() + ] + + if not filtered_topics: + st.info("No resources found matching your search.") + else: + st.markdown("---") + st.markdown("**Matching Resources:**") + for topic in filtered_topics: + st.markdown(f"**{topic}**") + st.info( + mental_health_resources_full[topic]['description']) + for link in mental_health_resources_full[topic]['links']: + st.markdown(f"β€’ [{link['label']}]({link['url']})") + st.markdown("---") + else: + resource_tabs = st.tabs( + list(mental_health_resources_full.keys())) + + for i, tab_title in enumerate(mental_health_resources_full.keys()): + with resource_tabs[i]: + topic_data = mental_health_resources_full[tab_title] + st.markdown(f"**{tab_title}**") + st.info(topic_data['description']) + for link in topic_data['links']: + st.markdown(f"β€’ [{link['label']}]({link['url']})") + st.markdown("---") + + with st.expander("☎️ Crisis Support"): + st.markdown("**24/7 Crisis Hotlines:**") + for resource in GLOBAL_RESOURCES: + st.markdown( + f"**{resource['name']}**: {resource['desc']} [Visit Website]({resource['url']})") + + # Theme toggle in sidebar + with st.expander("🎨 Theme Settings"): + current_theme = get_current_theme() + is_dark = current_theme["name"] == "Dark" + + # Palette selector (only for light mode) + if not is_dark: + palette_names = [p["name"] for p in PALETTES] + selected_palette = st.selectbox( + "Choose a soothing color palette:", + palette_names, + index=palette_names.index( + st.session_state.get("palette_name", "Light")), + key="palette_selector", + ) + if selected_palette != st.session_state.get("palette_name", "Light"): + set_palette(selected_palette) + + # Current theme display with better styling + st.markdown(""" +
+ Current Theme:
+ {} Mode +
+ """.format(current_theme['name']), unsafe_allow_html=True) + + # Theme toggle button with better styling + button_text = "πŸŒ™ Dark Mode" if not is_dark else "β˜€οΈ Light Mode" + button_color = "primary" if not is_dark else "secondary" + + if st.button( + button_text, + key="sidebar_theme_toggle", + use_container_width=True, + type=button_color + ): + toggle_theme() + + # Quizzes expander (no longer contains nested expander) + with st.expander("πŸ§ͺ Take PsyToolkit Verified Quizzes"): + st.markdown(""" + Explore scientifically backed quizzes to better understand your mental well-being. These tools are for **self-awareness** and not clinical diagnosis. + """) + + quizzes = [ + { + "name": "GAD-7 (Anxiety Assessment)", + "desc": "Measures severity of generalized anxiety symptoms.", + "url": "https://www.psytoolkit.org/cgi-bin/3.6.0/survey?s=u8bAf", + "score_info": """ + Score Interpretation: + GAD-7 score runs from 0 to 21 + - 0–4: Minimal anxiety + - 5–9: Mild anxiety + - 10–14: Moderate anxiety + - 15–21: Severe anxiety + """ + }, + { + "name": "PHQ-9 (Depression Assessment)", + "desc": "Screens for presence and severity of depression.", + "url": "https://www.psytoolkit.org/cgi-bin/3.6.0/survey?s=Hj32b", + "score_info": """ + Score Interpretation: + - 0–4: Mild depression + - 5–9: Moderate depression + - 10–14: Moderately severe depression + - 15–19: Severe depression + """ + }, + { + "name": "The WHO-5 Well-Being Index", + "desc": "Five simple non-intrusive questions to assess well-being. Score ranges from 0 (poor) to 100 (excellent).", + "url": "https://www.psytoolkit.org/cgi-bin/3.6.0/survey?s=POqLJ", + "score_info": """ + Score Interpretation: + -if your score is 50 or lower you should consider + -further checks on whether you suffer + -from clinical depression + """ + }, + { + "name": "Depression Anxiety Stress Scales (DASS)", + "desc": "Measures depression, anxiety, and stress using one combined questionnaire.", + "url": "https://www.psytoolkit.org/cgi-bin/3.6.0/survey?s=HvfDY", + "score_info": "**Score Interpretation (per subscale):**\n\n- **Normal, Mild, Moderate, Severe, Extremely Severe**\n\n| | Depression | Anxiety | Stress |\n|----------|------------|---------|---------|\n| Normal | 0-9 | 0-7 | 0-14 |\n| Mild | 10-13 | 8-9 | 15-18 |\n| Moderate | 14-20 | 10-14 | 19-25 |\n| Severe | 21-27 | 15-19 | 26-33 |\n| Extremely Severe | 28+ | 20+ | 34+ |" +} + ] + + for quiz in quizzes: + st.markdown(f""" + **{quiz['name']}** + *{quiz['desc']}* + [πŸ”— Take Quiz]({quiz['url']}) + {quiz['score_info']} + """) + + # About section moved outside of any expander + st.markdown("---") + st.markdown(""" + **ℹ️ About TalkHeal** + Your compassionate mental health companion, designed to provide: + + β€’ 24/7 emotional support + β€’ Resource guidance + β€’ Crisis intervention + β€’ Professional referrals + + **Remember:** This is not a substitute for professional mental health care. + + --- + + **Created with ❀️ by [Eccentric Explorer](https://eccentriccoder01.github.io/Me)** + *"It's absolutely okay not to be okay :)"* + + πŸ“… Enhanced Version - May 2025 + """) \ No newline at end of file diff --git a/core/config.py b/core/config.py index e385eb8..d83e1fa 100644 --- a/core/config.py +++ b/core/config.py @@ -14,6 +14,8 @@ "menu_items": None } +emoji-mood-selector +# ⚠️ DO NOT CALL st.set_page_config HERE β€” it's already set in talkheal.py #st.set_page_config(**PAGE_CONFIG) # ---------- Custom Dropdown Style ---------- @@ -26,6 +28,7 @@ """, unsafe_allow_html=True) + # ---------- Tone Options ---------- TONE_OPTIONS = { "Compassionate Listener": "You are a compassionate listener β€” soft, empathetic, patient β€” like a therapist who listens without judgment.", @@ -35,22 +38,17 @@ "Mindfulness Guide": "You are a mindfulness guide β€” calm, slow, and grounding β€” focused on breathing, presence, and awareness." } -# ---------- Sidebar Tone Selector ---------- -with st.sidebar: - st.header("🧠 Choose Your AI Tone") - default_tone = list(TONE_OPTIONS.keys())[0] - selected_tone = st.selectbox( - "Select a personality tone:", - options=list(TONE_OPTIONS.keys()), - index=0, - key="tone_selector" - ) - st.session_state["selected_tone"] = selected_tone or default_tone - -# ---------- Display Current Tone in Chat Section ---------- -st.subheader(f"πŸ—£οΈ Current Chatbot Tone: **{st.session_state['selected_tone']}**") - -# ---------- Gemini Configuration ---------- +# ---------- Emoji-Based Mood Options ---------- +MOOD_OPTIONS = { + "😊": "Happy", + "😒": "Sad", + "😑": "Angry", + "😰": "Anxious", + "😌": "Relaxed", + "πŸ˜”": "Lonely" +} + +# ---------- Gemini API Configuration ---------- def configure_gemini(): try: api_key = st.secrets["GEMINI_API_KEY"] @@ -64,10 +62,19 @@ def configure_gemini(): st.error(f"❌ Failed to configure Gemini API: {e}") return None -# ---------- Get System Prompt ---------- -def get_tone_system_prompt(): +# ---------- Get Tone Prompt ---------- +def get_tone_prompt(): tone = st.session_state.get("selected_tone", "Compassionate Listener") return TONE_OPTIONS.get(tone, TONE_OPTIONS["Compassionate Listener"]) +# ---------- Get Mood Label (for emoji picker) ---------- +def get_selected_mood(): + emoji = st.session_state.get("selected_mood", "😊") + return MOOD_OPTIONS.get(emoji, "Happy") # default fallback + +# ---------- Get Mood Prompt (for emoji-based OR radio mood selector) ---------- +def get_mood_context(): + mood = st.session_state.get("current_mood_val") or get_selected_mood() + return f"The user is currently feeling '{mood}'. Please respond empathetically and supportively based on their emotional state." # ---------- Generate AI Response ---------- def generate_response(user_input, model): @@ -94,12 +101,26 @@ def generate_response(user_input, model): st.error(f"❌ Unexpected error occurred: {e}") return None -# ---------- MAIN CHAT INTERFACE ---------- -model = configure_gemini() +# ---------- Conversation State Utility ---------- +def create_new_conversation(): + from datetime import datetime + + new_convo = { + "title": "New Chat", + "messages": [], + "date": datetime.now().strftime("%Y-%m-%d %H:%M:%S") + } + + if "conversations" not in st.session_state: + st.session_state.conversations = [] + + + st.session_state.conversations.insert(0, new_convo) + st.session_state.active_conversation = 0 +# ---------- Required Constants for Imports ---------- +MODEL = "models/gemini-1.5-flash" # or use gemini-2.0 if preferred +SYSTEM_PROMPT = """ +You are TalkHeal, a compassionate and supportive AI assistant focused on mental well-being. +Always reply empathetically, provide helpful suggestions, and foster a safe space for open communication. +""" -if model: - user_input = st.text_input("πŸ’¬ You:", placeholder="Share what's on your mind...") - if user_input: - response = generate_response(user_input, model) - if response: - st.markdown(f"**πŸ€– TalkHeal:** {response}") diff --git a/core/gemini.py b/core/gemini.py new file mode 100644 index 0000000..e8a513b --- /dev/null +++ b/core/gemini.py @@ -0,0 +1,33 @@ +import requests +import os +import streamlit as st + +def get_ai_response(prompt, model="gemini-1.5-flash"): + api_key = st.secrets.get("GEMINI_API_KEY", os.getenv("GEMINI_API_KEY")) + if not api_key: + raise ValueError("Gemini API key not found in secrets or environment variables.") + + url = f"https://generativelanguage.googleapis.com/v1beta/models/{model}:generateContent" + headers = { + "Content-Type": "application/json", + "X-goog-api-key": api_key + } + data = { + "contents": [ + { + "parts": [{"text": prompt}] + } + ] + } + + response = requests.post(url, headers=headers, json=data) + + # βœ… ADD THIS BLOCK HERE (before you parse JSON) + if response.status_code != 200: + st.error(f"Gemini API Error {response.status_code}: {response.text}") + return "⚠️ Gemini API failed to respond. Please try again." + + try: + return response.json()["candidates"][0]["content"]["parts"][0]["text"] + except Exception as e: + return f"⚠️ Failed to parse Gemini response: {e}" diff --git a/core/utils.py b/core/utils.py index 97f3a0a..71d2fc9 100644 --- a/core/utils.py +++ b/core/utils.py @@ -19,8 +19,6 @@ def get_current_time(): return now.strftime("%I:%M %p").lstrip("0") - - def create_new_conversation(initial_message=None): """ Creates a new conversation in the session state. @@ -33,14 +31,14 @@ def create_new_conversation(initial_message=None): "date": datetime.now().strftime("%B %d, %Y"), "messages": [] } - + if initial_message: new_convo["messages"].append({ - "sender": "user", - "message": initial_message, + "sender": "user", + "message": initial_message, "time": get_current_time() }) - + st.session_state.conversations.insert(0, new_convo) st.session_state.active_conversation = 0 return 0 @@ -54,7 +52,6 @@ def clean_ai_response(response_text): response_text = response_text.replace('<', '<') response_text = response_text.replace('>', '>') response_text = response_text.replace('&', '&') - return response_text def get_ai_response(user_message, model): @@ -70,17 +67,16 @@ def get_ai_response(user_message, model): 5. Ask follow-up questions to better understand the user's situation 6. Provide coping strategies and resources when appropriate 7. Not assume that the user is always in overwhelming states. Sometimes he/she might also be in joyful or curious moods and ask questions not related to mental health - + IMPORTANT: Respond with PLAIN TEXT ONLY. Do not include any HTML tags, markdown formatting, or special characters. Just provide a natural, conversational response. - + User message: {user_message} - + Respond in a caring, supportive manner (keep response under 150 words): """ try: response = model.generate_content(mental_health_prompt) - # Clean the response to remove any HTML or unwanted formatting cleaned_response = clean_ai_response(response.text) return cleaned_response except ValueError as e: @@ -101,6 +97,7 @@ def get_ai_response(user_message, model): # logging.error(f"Unexpected error in get_ai_response: {e}") return "I'm here to listen and support you. Sometimes I have trouble connecting, but I want you to know that your feelings are valid and you're not alone. Would you like to share more about what you're experiencing?" +# Implementing IP Based Isolation def cached_user_ip(): # Check if IP is already cached in session state if hasattr(st.session_state, 'cached_ip') and hasattr(st.session_state, 'ip_cache_time'): @@ -129,14 +126,12 @@ def cached_user_ip(): return st.session_state.cached_ip -#Implementing IP Based Isolation def get_user_ip(): try: return requests.get("https://api.ipify.org").text except: return "unknown_ip" -#Saving and loading to/from JSON File def get_memory_file(): ip = cached_user_ip() os.makedirs("data", exist_ok=True) @@ -153,3 +148,17 @@ def load_conversations(): return [] with open(memory_file, 'r', encoding="utf-8") as f: return json.load(f) + +# Mood Tip Generator +def get_mood_tip(mood): + """ + Returns a tip or message based on the selected mood. + """ + tips = { + "Very Low": "It's okay to feel low sometimes. Consider talking to a friend or therapist.", + "Low": "Take a short walk, breathe deeply, and treat yourself with kindness.", + "Okay": "You're doing okay. Reflect on something you're grateful for today.", + "Good": "That's great! Maybe help someone else feel good too.", + "Great": "Awesome! Keep that positive energy going and spread it around." + } + return tips.get(mood, "Remember to take care of yourself.") \ No newline at end of file diff --git a/css/styles.py b/css/styles.py index 18ec9cd..d895ad6 100644 --- a/css/styles.py +++ b/css/styles.py @@ -6,7 +6,25 @@ def get_base64_of_bin_file(bin_file): data = f.read() return base64.b64encode(data).decode() + def apply_custom_css(): + st.markdown( + """ + + """, + unsafe_allow_html=True + ) + from core.theme import get_current_theme theme_config = get_current_theme() theme_overrides = { diff --git a/streamlit.toml b/streamlit.toml index 5cdfe5c..6d0879a 100644 --- a/streamlit.toml +++ b/streamlit.toml @@ -1,2 +1,3 @@ -GEMINI_API_KEY = "GEMINI_API_KEY" +import streamlit as st +GEMINI_API_KEY = st.secrets["GEMINI_API_KEY"] diff --git a/streamlit.toml~ b/streamlit.toml~ new file mode 100644 index 0000000..5716e27 --- /dev/null +++ b/streamlit.toml~ @@ -0,0 +1 @@ +GEMINI_API_KEY = "AIzaSyAgtTtPjJzTaNSrXaWFkMEJKIpMiFI3QNw"