From 486c3d9a1553d9143f84c4ffb18c903f2f7a0e0b Mon Sep 17 00:00:00 2001 From: aila-reddemma-png Date: Sat, 26 Jul 2025 15:28:32 +0530 Subject: [PATCH 1/5] =?UTF-8?q?=E2=9C=A8=20Added=20emoji-based=20mood=20tr?= =?UTF-8?q?acker=20with=20journaling=20and=20Gemini=20integration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TalkHeal.py | 69 ++++++---------- components/ resources.py | 63 +++++++++++++++ components/chat_interface.py | 8 +- components/sidebar.py | 149 ++++++++++++++++------------------- core/config.py | 79 ++++++++----------- core/utils.py | 38 +++++---- 6 files changed, 216 insertions(+), 190 deletions(-) create mode 100644 components/ resources.py diff --git a/TalkHeal.py b/TalkHeal.py index f99cfb6..b8f4dfc 100644 --- a/TalkHeal.py +++ b/TalkHeal.py @@ -1,25 +1,21 @@ +# --- 0. IMPORTS --- import streamlit as st +import google.generativeai as genai -# โœ… MUST be the first Streamlit command -st.set_page_config( - page_title="TalkHeal", - page_icon="๐Ÿ’ฌ", - layout="wide", - initial_sidebar_state=st.session_state.get("sidebar_state", "expanded") -) +# --- 1. FIRST COMMAND: PAGE CONFIG --- +from core.config import PAGE_CONFIG +st.set_page_config(**PAGE_CONFIG) -import google.generativeai as genai -from core.utils import save_conversations, load_conversations -from core.config import configure_gemini, PAGE_CONFIG -from core.utils import get_current_time, create_new_conversation +# --- 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 - -# --- 1. INITIALIZE SESSION STATE --- +# --- 3. SESSION STATE INITIALIZATION --- if "chat_history" not in st.session_state: st.session_state.chat_history = [] if "conversations" not in st.session_state: @@ -39,46 +35,24 @@ ] 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 -# --- 2. SET PAGE CONFIG --- - - -# --- 3. APPLY STYLES & CONFIGURATIONS --- +# --- 4. STYLES & GEMINI SETUP --- apply_custom_css() model = configure_gemini() -# --- 4. TONE SELECTION DROPDOWN IN SIDEBAR --- -TONE_OPTIONS = { - "Compassionate Listener": "You are a compassionate listener โ€” soft, empathetic, patient โ€” like a therapist who listens without judgment.", - "Motivating Coach": "You are a motivating coach โ€” energetic, encouraging, and action-focused โ€” helping the user push through rough days.", - "Wise Friend": "You are a wise friend โ€” thoughtful, poetic, and reflective โ€” giving soulful responses and timeless advice.", - "Neutral Therapist": "You are a neutral therapist โ€” balanced, logical, and non-intrusive โ€” asking guiding questions using CBT techniques.", - "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"]) - -# --- 6. RENDER SIDEBAR --- +# --- 5. SIDEBAR --- render_sidebar() -# --- 7. PAGE ROUTING --- +# --- 6. MAIN PAGE ROUTING LOGIC --- main_area = st.container() +# Load conversations or start a new one if not st.session_state.conversations: - saved_conversations = load_conversations() - if saved_conversations: - st.session_state.conversations = saved_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: @@ -86,7 +60,7 @@ def get_tone_prompt(): st.session_state.active_conversation = 0 st.rerun() -# --- 8. RENDER PAGE --- +# --- 7. MAIN VIEW DISPLAY --- if st.session_state.get("show_emergency_page"): with main_area: render_emergency_page() @@ -94,10 +68,11 @@ def get_tone_prompt(): 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()) -# --- 9. SCROLL SCRIPT --- +# --- 8. AUTO SCROLL SCRIPT --- st.markdown(""" -""", unsafe_allow_html=True) \ No newline at end of file +""", unsafe_allow_html=True) 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 462ad45..3a941ae 100644 --- a/components/chat_interface.py +++ b/components/chat_interface.py @@ -108,7 +108,13 @@ 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:" + mood = st.session_state.get("selected_mood", "๐Ÿ˜Š Happy") + prompt = ( + f"{system_prompt}\n\n" + f"The user is currently feeling: {mood}. Consider this mood while responding empathetically.\n\n" + f"{memory}\nUser: {user_input.strip()}\nBot:" + ) + ai_response = get_ai_response(prompt, model) active_convo["messages"].append({ diff --git a/components/sidebar.py b/components/sidebar.py index 208d066..0a4b45e 100644 --- a/components/sidebar.py +++ b/components/sidebar.py @@ -3,6 +3,8 @@ 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 = [ @@ -72,6 +74,10 @@ } +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.""" @@ -88,6 +94,7 @@ def render_sidebar(): 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:**") @@ -130,43 +137,30 @@ def render_sidebar(): st.rerun() 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() - # --- 3. Dynamic Mood Tracker & Micro-Journal (Fixed Tip & New Button) --- - with st.expander("๐Ÿง  Mental Health Check"): + # --- Mood Tracker --- + with st.expander("๐Ÿง  Mental Health Check", expanded=True): st.markdown("**How are you feeling today?**") mood_options_map = { @@ -179,78 +173,73 @@ 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 - ) - 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): - 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 for this session." + with col2: + 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 = "" - 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/core/config.py b/core/config.py index c14aeb9..1a98507 100644 --- a/core/config.py +++ b/core/config.py @@ -13,17 +13,7 @@ "menu_items": None } -st.set_page_config(**PAGE_CONFIG) - -# ---------- Custom Dropdown Style ---------- -st.markdown(""" - -""", unsafe_allow_html=True) +# โš ๏ธ DO NOT CALL st.set_page_config HERE โ€” it's already set in talkheal.py # ---------- Tone Options ---------- TONE_OPTIONS = { @@ -34,22 +24,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']}**") +# ---------- Emoji-Based Mood Options ---------- +MOOD_OPTIONS = { + "๐Ÿ˜Š": "Happy", + "๐Ÿ˜ข": "Sad", + "๐Ÿ˜ก": "Angry", + "๐Ÿ˜ฐ": "Anxious", + "๐Ÿ˜Œ": "Relaxed", + "๐Ÿ˜”": "Lonely" +} -# ---------- Gemini Configuration ---------- +# ---------- Gemini API Configuration ---------- def configure_gemini(): try: api_key = st.secrets["GEMINI_API_KEY"] @@ -63,30 +48,28 @@ 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"]) -# ---------- Generate AI Response ---------- -def generate_response(user_input, model): - system_prompt = get_tone_system_prompt() - try: - response = model.generate_content([ - {"role": "system", "parts": [system_prompt]}, - {"role": "user", "parts": [user_input]} - ]) - return response.text - except Exception as e: - st.error(f"โŒ Failed to generate response: {e}") - return None +# ---------- Get Mood Label ---------- +def get_selected_mood(): + emoji = st.session_state.get("selected_mood", "๐Ÿ˜Š") + return MOOD_OPTIONS.get(emoji, "Happy") # default fallback +# ---------- 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 = [] -# ---------- MAIN CHAT INTERFACE ---------- -model = configure_gemini() + st.session_state.conversations.insert(0, new_convo) + st.session_state.active_conversation = 0 -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/utils.py b/core/utils.py index 367fd76..953bee1 100644 --- a/core/utils.py +++ b/core/utils.py @@ -18,8 +18,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. @@ -32,14 +30,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 @@ -53,7 +51,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): @@ -69,30 +66,28 @@ 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 Exception as 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 +# IP 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 = get_user_ip() os.makedirs("data", exist_ok=True) @@ -108,4 +103,19 @@ def load_conversations(): if not os.path.exists(memory_file): return [] with open(memory_file, 'r', encoding="utf-8") as f: - return json.load(f) \ No newline at end of file + return json.load(f) + +# โœ… MISSING FUNCTION: 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.") + From 8eb322fd2f6c812e0e34e4f6721b3adb6d85e4f9 Mon Sep 17 00:00:00 2001 From: aila-reddemma-png Date: Sun, 27 Jul 2025 01:39:42 +0530 Subject: [PATCH 2/5] Resolved merge conflicts between emoji-mood-selector and main --- TalkHeal.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/TalkHeal.py b/TalkHeal.py index b8f4dfc..dbb0698 100644 --- a/TalkHeal.py +++ b/TalkHeal.py @@ -6,6 +6,8 @@ from core.config import PAGE_CONFIG st.set_page_config(**PAGE_CONFIG) +GEMINI_API_KEY = st.secrets["GEMINI_API_KEY"] + # --- 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 babcc0582f11f5543914672b45c8ebc84830f7e6 Mon Sep 17 00:00:00 2001 From: aila-reddemma-png Date: Sun, 27 Jul 2025 01:53:04 +0530 Subject: [PATCH 3/5] Resolved merge conflicts between emoji-mood-selector and main --- TalkHeal.py~ | 86 +++++++++++++++++++++++++++++++++++++++++++++++++ streamlit.toml | 5 ++- streamlit.toml~ | 4 +++ 3 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 TalkHeal.py~ create mode 100644 streamlit.toml~ 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/streamlit.toml b/streamlit.toml index 0a23a05..3bdb833 100644 --- a/streamlit.toml +++ b/streamlit.toml @@ -1 +1,4 @@ -GEMINI_API_KEY = "AIzaSyDsLJgA58LvgFtnUdVBLFb08GZQV0wXYjQ" +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..3bdb833 --- /dev/null +++ b/streamlit.toml~ @@ -0,0 +1,4 @@ +import streamlit as st + +GEMINI_API_KEY = st.secrets["GEMINI_API_KEY"] + From 88aa436fd052d8b50bc26c7c8f6d4e8158b6c686 Mon Sep 17 00:00:00 2001 From: aila-reddemma-ydv Date: Sun, 27 Jul 2025 16:58:14 +0530 Subject: [PATCH 4/5] Fix: Integrated mood-aware journaling correctly --- TalkHeal.py | 81 ++++++++++++------------- api.py | 5 ++ components/chat_interface.py | 112 +++++++++++++---------------------- components/sidebar.py | 61 +++++++++++-------- core/config.py | 14 ++++- core/gemini.py | 33 +++++++++++ css/styles.py | 18 ++++++ streamlit.toml | 5 +- streamlit.toml~ | 3 +- 9 files changed, 191 insertions(+), 141 deletions(-) create mode 100644 api.py create mode 100644 core/gemini.py diff --git a/TalkHeal.py b/TalkHeal.py index dbb0698..660446a 100644 --- a/TalkHeal.py +++ b/TalkHeal.py @@ -1,60 +1,62 @@ # --- 0. IMPORTS --- +import uuid # standard library import import streamlit as st -import google.generativeai as genai -# --- 1. FIRST COMMAND: PAGE CONFIG --- +# --- 1. PAGE CONFIG FIRST --- from core.config import PAGE_CONFIG -st.set_page_config(**PAGE_CONFIG) - -GEMINI_API_KEY = st.secrets["GEMINI_API_KEY"] +st.set_page_config(**PAGE_CONFIG) +from css.styles import apply_custom_css -# --- 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 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.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 = [ +# --- 1. PAGE CONFIG & CSS --- +apply_custom_css() + +# --- 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, + "sidebar_state": "expanded", + "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 + ], + "selected_tone": "Compassionate Listener", + "selected_mood": "๐Ÿ™‚" +} -# --- 4. STYLES & GEMINI SETUP --- -apply_custom_css() +for key, val in default_values.items(): + if key not in st.session_state: + st.session_state[key] = val + +# --- 3. GEMINI MODEL SETUP --- model = configure_gemini() -# --- 5. SIDEBAR --- +# --- 4. SIDEBAR --- render_sidebar() -# --- 6. MAIN PAGE ROUTING LOGIC --- +# --- 5. MAIN LOGIC CONTAINER --- main_area = st.container() -# Load conversations or start a new one +# --- 6. Load or Start Conversation --- if not st.session_state.conversations: - saved_convos = load_conversations() - if saved_convos: - st.session_state.conversations = saved_convos + saved = load_conversations() + if saved: + st.session_state.conversations = saved if st.session_state.active_conversation == -1: st.session_state.active_conversation = 0 else: @@ -62,17 +64,16 @@ st.session_state.active_conversation = 0 st.rerun() -# --- 7. MAIN VIEW DISPLAY --- -if st.session_state.get("show_emergency_page"): - with main_area: +# --- 7. ROUTING --- +with main_area: + if st.session_state.get("show_emergency_page"): render_emergency_page() -else: - with main_area: + else: 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()) + handle_chat_input(model=model, system_prompt=get_tone_prompt()) # --- 8. AUTO SCROLL SCRIPT --- st.markdown(""" 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/chat_interface.py b/components/chat_interface.py index 3a941ae..fb960c9 100644 --- a/components/chat_interface.py +++ b/components/chat_interface.py @@ -1,68 +1,37 @@ 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 - -# 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(""" - - """, height=0) - - st.markdown(""" - - """, unsafe_allow_html=True) - -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 +from core.utils import save_conversations, get_current_time +from core.gemini import get_ai_response + +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] + + 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( @@ -70,13 +39,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: @@ -90,17 +61,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 @@ -108,14 +77,15 @@ def format_memory(convo_history, max_turns=10): try: with st.spinner("TalkHeal is thinking..."): memory = format_memory(active_convo["messages"]) - mood = st.session_state.get("selected_mood", "๐Ÿ˜Š Happy") + mood = st.session_state.get("selected_mood_context") or st.session_state.get("current_mood_val", "okay") + prompt = ( f"{system_prompt}\n\n" - f"The user is currently feeling: {mood}. Consider this mood while responding empathetically.\n\n" + f"User is feeling {mood}. Respond empathetically.\n\n" f"{memory}\nUser: {user_input.strip()}\nBot:" ) - ai_response = get_ai_response(prompt, model) + ai_response = get_ai_response(prompt, "gemini-1.5-flash") active_convo["messages"].append({ "sender": "bot", @@ -133,3 +103,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 0a4b45e..fd274f2 100644 --- a/components/sidebar.py +++ b/components/sidebar.py @@ -1,3 +1,6 @@ +from css.styles import apply_custom_css +apply_custom_css() + import streamlit as st import webbrowser from datetime import datetime @@ -73,16 +76,18 @@ } } - 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: @@ -90,11 +95,20 @@ def render_sidebar(): if "send_chat_message" not in st.session_state: st.session_state.send_chat_message = False - if st.button("โž• New Chat", key="new_chat", use_container_width=True, type="primary"): + # โœ… 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:**") @@ -164,12 +178,12 @@ def render_sidebar(): st.markdown("**How are you feeling today?**") mood_options_map = { - "๐Ÿ˜” Very Low": "very_low", - "๐Ÿ˜ Low": "low", - "๐Ÿ˜Š Okay": "okay", - "๐Ÿ˜„ Good": "good", - "๐ŸŒŸ Great": "great" - } + "๐Ÿ˜” Very Low": "very_low", + "๐Ÿ˜ Low": "low", + "๐Ÿ˜Š Okay": "okay", + "๐Ÿ˜„ Good": "good", + "๐ŸŒŸ Great": "great" + } mood_labels = list(mood_options_map.keys()) selected_mood_label = st.radio( @@ -181,9 +195,11 @@ def render_sidebar(): 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?", @@ -195,35 +211,32 @@ def render_sidebar(): 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 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(current_mood_val, "A general tip for your mood.") + } + + # Get the tip for the selected mood + tip = tips_for_mood.get(current_mood_val, "A general tip for your mood.") - st.markdown("") + # 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 = tips_for_mood + 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 = "" + 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 st.session_state.mood_journal_area.strip(): - st.session_state.pre_filled_chat_input = st.session_state.mood_journal_area + 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 = "" @@ -232,11 +245,11 @@ def render_sidebar(): else: st.warning("Please enter your thoughts before asking TalkHeal.") - if st.session_state.mood_tip_display: + 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.mood_entry_status: + if st.session_state.get("mood_entry_status"): st.info(st.session_state.mood_entry_status) st.session_state.mood_entry_status = "" diff --git a/core/config.py b/core/config.py index 1a98507..6adb787 100644 --- a/core/config.py +++ b/core/config.py @@ -53,10 +53,16 @@ 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 ---------- +# ---------- 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." + # ---------- Conversation State Utility ---------- def create_new_conversation(): from datetime import datetime @@ -72,4 +78,10 @@ def create_new_conversation(): 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. +""" 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/css/styles.py b/css/styles.py index b4ee017..3801417 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 3bdb833..5716e27 100644 --- a/streamlit.toml +++ b/streamlit.toml @@ -1,4 +1 @@ -import streamlit as st - -GEMINI_API_KEY = st.secrets["GEMINI_API_KEY"] - +GEMINI_API_KEY = "AIzaSyAgtTtPjJzTaNSrXaWFkMEJKIpMiFI3QNw" diff --git a/streamlit.toml~ b/streamlit.toml~ index 3bdb833..12daa24 100644 --- a/streamlit.toml~ +++ b/streamlit.toml~ @@ -1,4 +1,3 @@ -import streamlit as st +GEMINI_API_KEY = "AIzaSyAgtTtPjJzTaNSrXaWFkMEJKIpMiFI3QNw" -GEMINI_API_KEY = st.secrets["GEMINI_API_KEY"] From 83be1877b7554a6d12e51e2b7791cd68fab8e977 Mon Sep 17 00:00:00 2001 From: aila-reddemma-ydv Date: Fri, 1 Aug 2025 12:42:46 +0530 Subject: [PATCH 5/5] Resolved merge conflicts, verified mood selector & chat interface integration1 --- components/sidebar.py | 63 +++---- components/sidebar.py~ | 420 +++++++++++++++++++++++++++++++++++++++++ streamlit.toml | 5 +- streamlit.toml~ | 2 - 4 files changed, 449 insertions(+), 41 deletions(-) create mode 100644 components/sidebar.py~ diff --git a/components/sidebar.py b/components/sidebar.py index fd274f2..b11929d 100644 --- a/components/sidebar.py +++ b/components/sidebar.py @@ -1,6 +1,3 @@ -from css.styles import apply_custom_css -apply_custom_css() - import streamlit as st import webbrowser from datetime import datetime @@ -76,18 +73,16 @@ } } + 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: @@ -95,20 +90,11 @@ def render_sidebar(): 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"): + if st.button("โž• New Chat", key="new_chat", 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:**") @@ -178,12 +164,12 @@ def render_sidebar(): st.markdown("**How are you feeling today?**") mood_options_map = { - "๐Ÿ˜” Very Low": "very_low", - "๐Ÿ˜ Low": "low", - "๐Ÿ˜Š Okay": "okay", - "๐Ÿ˜„ Good": "good", - "๐ŸŒŸ Great": "great" - } + "๐Ÿ˜” Very Low": "very_low", + "๐Ÿ˜ Low": "low", + "๐Ÿ˜Š Okay": "okay", + "๐Ÿ˜„ Good": "good", + "๐ŸŒŸ Great": "great" + } mood_labels = list(mood_options_map.keys()) selected_mood_label = st.radio( @@ -195,11 +181,9 @@ def render_sidebar(): 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?", @@ -211,32 +195,35 @@ def render_sidebar(): 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 + # 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 the tip for the selected mood - tip = tips_for_mood.get(current_mood_val, "A general tip for your mood.") + }.get(current_mood_val, "A general tip for your mood.") - # Two buttons: Get Tip & Save Entry and Ask TalkHeal + 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 = tip # โœ… show only selected mood tip + 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 = journal_input # โœ… store the journal input + st.session_state.mood_journal_entry = "" 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 + 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 = "" @@ -245,11 +232,11 @@ def render_sidebar(): else: st.warning("Please enter your thoughts before asking TalkHeal.") - if st.session_state.get("mood_tip_display"): + 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.get("mood_entry_status"): + if st.session_state.mood_entry_status: st.info(st.session_state.mood_entry_status) st.session_state.mood_entry_status = "" @@ -417,4 +404,4 @@ def render_sidebar(): *"It's absolutely okay not to be okay :)"* ๐Ÿ“… Enhanced Version - May 2025 - """) \ No newline at end of file + """) 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/streamlit.toml b/streamlit.toml index 5716e27..3bdb833 100644 --- a/streamlit.toml +++ b/streamlit.toml @@ -1 +1,4 @@ -GEMINI_API_KEY = "AIzaSyAgtTtPjJzTaNSrXaWFkMEJKIpMiFI3QNw" +import streamlit as st + +GEMINI_API_KEY = st.secrets["GEMINI_API_KEY"] + diff --git a/streamlit.toml~ b/streamlit.toml~ index 12daa24..5716e27 100644 --- a/streamlit.toml~ +++ b/streamlit.toml~ @@ -1,3 +1 @@ GEMINI_API_KEY = "AIzaSyAgtTtPjJzTaNSrXaWFkMEJKIpMiFI3QNw" - -