diff --git a/TalkHeal.py b/TalkHeal.py index f99cfb6..2876716 100644 --- a/TalkHeal.py +++ b/TalkHeal.py @@ -17,6 +17,7 @@ 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 +from components.profile import apply_global_font_size # --- 1. INITIALIZE SESSION STATE --- @@ -41,6 +42,7 @@ st.session_state.selected_tone = "Compassionate Listener" # --- 2. SET PAGE CONFIG --- +apply_global_font_size() # --- 3. APPLY STYLES & CONFIGURATIONS --- diff --git a/components/profile.py b/components/profile.py new file mode 100644 index 0000000..90d8943 --- /dev/null +++ b/components/profile.py @@ -0,0 +1,353 @@ +""" +TalkHeal Profile Management Module + +This module handles user profile functionality including: +- Profile creation and editing +- Profile picture upload and management +- User preferences (name, font size) +- Profile display in sidebar + +Author: TalkHeal Team +Version: 1.0 +""" + +import streamlit as st +import base64 +from datetime import datetime +from io import BytesIO +from PIL import Image + + +def initialize_profile_state(): + """Initialize profile data in session state if not exists""" + if "user_profile" not in st.session_state: + st.session_state.user_profile = { + "name": "", + "profile_picture": None, + "join_date": datetime.now().strftime("%B %Y"), + "font_size": "Medium" + } + + +def get_greeting(): + """Get appropriate greeting based on current time""" + current_hour = datetime.now().hour + if current_hour < 12: + return "Good morning" + elif current_hour < 17: + return "Good afternoon" + else: + return "Good evening" + + +def get_user_initials(name): + """Generate user initials from name""" + if name: + return ''.join([word[0].upper() for word in name.split()[:2]]) + return "TH" + + +def create_default_avatar(initials, size=80): + """Create a default avatar with user initials""" + return st.markdown(f""" +
+ {initials} +
+ """, unsafe_allow_html=True) + + +def handle_profile_picture_upload(uploaded_file): + """Handle profile picture upload and processing""" + if uploaded_file is not None: + try: + # Process and resize image to medium size + image = Image.open(uploaded_file) + # Resize to medium size (200x200) while maintaining aspect ratio + image.thumbnail((200, 200), Image.Resampling.LANCZOS) + + # Convert to base64 for storage + buffered = BytesIO() + image.save(buffered, format="PNG") + img_str = base64.b64encode(buffered.getvalue()).decode() + + # Save to session state + st.session_state.user_profile["profile_picture"] = f"data:image/png;base64,{img_str}" + + st.success("✅ Profile picture uploaded successfully!") + return True + + except Exception as e: + st.error("❌ Error uploading image. Please try a different file.") + return False + + return False + + +def render_profile_header(): + """Render the profile header with picture and greeting""" + profile_data = st.session_state.user_profile + greeting = get_greeting() + + # Profile header section + st.markdown("### 👤 Profile") + + # Profile picture and greeting + col1, col2 = st.columns([1, 2]) + + with col1: + if profile_data["profile_picture"]: + # Display uploaded profile picture with circular shape and medium size + st.markdown(f""" +
+ Profile Picture +
+ """, unsafe_allow_html=True) + else: + # Default avatar with initials + initials = get_user_initials(profile_data["name"]) + create_default_avatar(initials, 80) + + with col2: + if profile_data["name"]: + display_name = profile_data["name"].split()[0] + st.markdown(f"**{greeting}, {display_name}!** 👋") + else: + st.markdown(f"**Welcome to TalkHeal!** 🌟") + st.caption(f"Member since {profile_data['join_date']}") + + +def render_profile_settings(): + """Render the profile settings form""" + profile_data = st.session_state.user_profile + + # Add CSS to fix the text input color issue + st.markdown(""" + + """, unsafe_allow_html=True) + + with st.expander("⚙️ Profile Settings"): + + # Name input + st.markdown("**Your Name**") + new_name = st.text_input( + "Enter your name", + value=profile_data["name"], + key="profile_name_input", + placeholder="Enter your name", + help="Enter your preferred name for personalized interactions" + ) + + # Profile picture upload + st.markdown("**Profile Picture**") + uploaded_file = st.file_uploader( + "Upload a profile picture (Optional)", + type=['png', 'jpg', 'jpeg'], + key="profile_pic_upload", + help="Drag and drop or click to upload. Supported formats: PNG, JPG, JPEG" + ) + + # Handle file upload + handle_profile_picture_upload(uploaded_file) + + # Font size preference + st.markdown("**Font Size**") + font_size = st.selectbox( + "Choose your preferred text size", + ["Small", "Medium", "Large"], + index=["Small", "Medium", "Large"].index(profile_data["font_size"]), + key="font_size_selector", + help="This will change the font size throughout the entire application" + ) + + # Action buttons row + col_save, col_reset = st.columns(2) + + with col_save: + # Save profile button + if st.button("💾 Save Profile", key="save_profile", use_container_width=True, type="primary"): + # Update profile data + profile_data["name"] = new_name.strip() + profile_data["font_size"] = font_size + + # Save to session state + st.session_state.user_profile = profile_data + + # Apply font size globally (you can implement this in your main app) + st.session_state.global_font_size = font_size + + # Success message + st.success("🎉 Profile saved successfully!") + st.balloons() + + # Rerun to update the display + st.rerun() + + with col_reset: + # Reset profile button + if st.button("🔄 Reset All", key="reset_profile", use_container_width=True, type="secondary"): + # Show confirmation dialog + st.session_state.show_reset_confirmation = True + st.rerun() + + # Reset confirmation dialog + if st.session_state.get("show_reset_confirmation", False): + st.warning("⚠️ Are you sure you want to reset all profile settings?") + col_confirm, col_cancel = st.columns(2) + + with col_confirm: + if st.button("✅ Yes, Reset", key="confirm_reset", use_container_width=True, type="primary"): + # Reset to default values + st.session_state.user_profile = { + "name": "", + "profile_picture": None, + "join_date": datetime.now().strftime("%B %Y"), + "font_size": "Medium" + } + # Reset global font size + st.session_state.global_font_size = "Medium" + st.session_state.show_reset_confirmation = False + st.success("🔄 Profile reset successfully!") + st.rerun() + + with col_cancel: + if st.button("❌ Cancel", key="cancel_reset", use_container_width=True): + st.session_state.show_reset_confirmation = False + st.rerun() + + +def render_profile_stats(): + """Render simplified profile statistics""" + profile_data = st.session_state.user_profile + + if profile_data["name"]: + with st.expander("📊 Your TalkHeal Journey"): + col1, col2 = st.columns(2) + + with col1: + st.metric("Conversations", "0", help="Total chat sessions") + + with col2: + st.metric("Days Active", "1", help="Days you've used TalkHeal") + + +def render_profile_section(): + """ + Main function to render the complete profile section + This is the function that should be imported and called in sidebar + """ + # Initialize profile state + initialize_profile_state() + + # Render profile components + render_profile_header() + render_profile_settings() + render_profile_stats() + + # Add separator + st.markdown("---") + + +# Optional: Helper functions for other parts of the app +def get_user_name(): + """Get the current user's name""" + if "user_profile" in st.session_state: + return st.session_state.user_profile.get("name", "") + return "" + + +def get_user_font_size(): + """Get the current user's preferred font size""" + if "global_font_size" in st.session_state: + return st.session_state.global_font_size + elif "user_profile" in st.session_state: + return st.session_state.user_profile.get("font_size", "Medium") + return "Medium" + + +def apply_global_font_size(): + """ + Apply the user's font size preference globally across the application. + Call this function in your main app to apply font size changes. + """ + font_size = get_user_font_size() + + # Font size mappings + font_sizes = { + "Small": "14px", + "Medium": "16px", + "Large": "18px" + } + + selected_size = font_sizes.get(font_size, "16px") + + # Apply CSS to change font size globally + st.markdown(f""" + + """, unsafe_allow_html=True) + + +def get_user_profile_picture(): + """Get the current user's profile picture""" + if "user_profile" in st.session_state: + return st.session_state.user_profile.get("profile_picture", None) + return None \ No newline at end of file diff --git a/components/sidebar.py b/components/sidebar.py index 208d066..bf79dd8 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 components.profile import initialize_profile_state, render_profile_section + # --- Structured Emergency Resources --- GLOBAL_RESOURCES = [ @@ -74,7 +76,10 @@ def render_sidebar(): """Renders the left and right sidebars.""" - + + with st.sidebar: + # === PROFILE SECTION (Now imported from profile.py) === + render_profile_section() with st.sidebar: st.markdown("### 💬 Conversations") if "show_quick_start_prompts" not in st.session_state: