Spaces:
Paused
Paused
| """ | |
| components.py - A-GRADE VERSION | |
| COMPLETE AND COHERENT with analytics.py, app.py, llm_agent_A_GRADE.py | |
| NEW FEATURES: | |
| 1. Proactive AI insights display (auto-generated at top) | |
| 2. Scenario comparison mode (side-by-side current vs scenario) | |
| 3. What-if mode (interactive sliders for testing) | |
| 4. Query detection for chart updates | |
| 5. All existing features preserved | |
| PRESERVED FEATURES: | |
| - Dynamic suggestions (never recycle) | |
| - Topic tracking across conversation | |
| - Category-specific visuals | |
| - Profile editing integration | |
| - All existing chart types | |
| """ | |
| from styles import CHART_PALETTES | |
| import streamlit as st | |
| import plotly.graph_objects as go | |
| from analytics import ( | |
| analyze_exam_performance, | |
| get_category_insights, | |
| calculate_budget_metrics, | |
| parse_budget_query, | |
| apply_scenario_changes, | |
| compare_scenarios, | |
| generate_proactive_insights | |
| ) | |
| from styles import get_custom_css, get_metric_card_html, get_insight_html | |
| from profile_editor import render_profile_editor | |
| def set_seed_chat(prompt_text): | |
| st.session_state.seed_chat = prompt_text | |
| def create_animated_donut_chart(values, labels, colors, title=""): | |
| fig = go.Figure(data=[go.Pie( | |
| labels=labels, values=values, hole=0.6, | |
| marker=dict(colors=colors, line=dict(color='white', width=2)), | |
| textinfo='label+percent', textposition='outside' | |
| )]) | |
| fig.update_layout( | |
| title=dict(text=title, font=dict(size=16, color='#1a1a1a', family='Inter')), | |
| showlegend=False, height=300, | |
| margin=dict(t=40, b=20, l=20, r=20), | |
| paper_bgcolor='rgba(0,0,0,0)', plot_bgcolor='rgba(0,0,0,0)' | |
| ) | |
| return fig | |
| def create_gauge_chart(value, max_value, title="Progress"): | |
| fig = go.Figure(go.Indicator( | |
| mode="gauge+number", value=value, | |
| title={'text': title, 'font': {'size': 14}}, | |
| number={'font': {'size': 24}}, | |
| gauge={ | |
| 'axis': {'range': [None, max_value]}, | |
| 'bar': {'color': "#bf6dbf"}, | |
| 'steps': [ | |
| {'range': [0, max_value * 0.5], 'color': '#fee2e2'}, | |
| {'range': [max_value * 0.5, max_value * 0.75], 'color': '#fef3c7'}, | |
| {'range': [max_value * 0.75, max_value], 'color': '#d1fae5'} | |
| ] | |
| } | |
| )) | |
| fig.update_layout( | |
| height=250, | |
| margin=dict(t=60, b=20, l=20, r=20), | |
| paper_bgcolor='rgba(0,0,0,0)' | |
| ) | |
| return fig | |
| # ===== NEW: QUERY DETECTION FOR SCENARIOS ===== | |
| def check_query_for_scenario(query, profile): | |
| """ | |
| Check if user query is asking a what-if question. | |
| Returns scenario_profile if detected, None otherwise. | |
| """ | |
| changes = parse_budget_query(query) | |
| if changes: | |
| scenario_profile = apply_scenario_changes(profile, changes) | |
| return scenario_profile | |
| return None | |
| # ===== NEW: PROACTIVE INSIGHTS RENDERING ===== | |
| def render_proactive_insights(profile, category): | |
| """ | |
| Render auto-generated proactive insights at top of dashboard. | |
| These appear automatically based on user's data. | |
| """ | |
| insights = generate_proactive_insights(profile, category) | |
| if not insights: | |
| return | |
| st.markdown("### 🎯 AI Insights for You") | |
| # Show top 2 most relevant insights | |
| for insight in insights[:2]: | |
| insight_type = insight.get("type", "insight") | |
| icon = insight.get("icon", "💡") | |
| text = insight.get("text", "") | |
| action = insight.get("action", "") | |
| # Color coding based on insight type | |
| if insight_type == "critical": | |
| bg_color = "#fee2e2" | |
| border_color = "#ef4444" | |
| elif insight_type == "warning": | |
| bg_color = "#fef3c7" | |
| border_color = "#f59e0b" | |
| elif insight_type == "success": | |
| bg_color = "#d1fae5" | |
| border_color = "#10b981" | |
| else: # opportunity | |
| bg_color = "#e0e7ff" | |
| border_color = "#6366f1" | |
| st.markdown(f""" | |
| <div style='background: {bg_color}; border-left: 4px solid {border_color}; | |
| padding: 1rem; margin-bottom: 0.75rem; border-radius: 0.5rem;'> | |
| <div style='display: flex; align-items: flex-start; gap: 0.75rem;'> | |
| <span style='font-size: 1.5rem;'>{icon}</span> | |
| <div style='flex: 1;'> | |
| <p style='margin: 0; font-size: 0.95rem; color: #1f2937; font-weight: 500;'>{text}</p> | |
| </div> | |
| </div> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| if action: | |
| if st.button(f"💬 {action}", key=f"insight_action_{hash(action)}", use_container_width=True): | |
| set_seed_chat(action) | |
| st.markdown("---") | |
| # ===== NEW: SCENARIO COMPARISON RENDERING ===== | |
| def render_scenario_comparison(current_profile, scenario_profile, category): | |
| """ | |
| Render side-by-side comparison of current vs scenario. | |
| Shows visual diff in charts. | |
| """ | |
| st.markdown("### 📊 Scenario Comparison") | |
| if category == "Finance": | |
| current_data = calculate_budget_metrics(current_profile) | |
| scenario_data = calculate_budget_metrics(scenario_profile) | |
| comparison = compare_scenarios(current_profile, scenario_profile) | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| st.markdown("#### Current Budget") | |
| st.metric("Spent", f"${current_profile['spend']:,}") | |
| st.metric("Remaining", f"${current_data['remaining']:,}") | |
| # Current chart | |
| fig_current = create_animated_donut_chart( | |
| list(current_data["categories"].values()), | |
| list(current_data["categories"].keys()), | |
| ['#10b981', '#f59e0b', '#ef4444'] | |
| ) | |
| st.plotly_chart(fig_current, use_container_width=True, key="scenario_current_chart") | |
| with col2: | |
| st.markdown("#### Scenario Budget") | |
| st.metric("Spent", f"${scenario_profile['spend']:,}", | |
| delta=f"{comparison['differences']['spend']:+,.0f}") | |
| st.metric("Remaining", f"${scenario_data['remaining']:,}", | |
| delta=f"{comparison['differences']['remaining']:+,.0f}") | |
| # Scenario chart | |
| fig_scenario = create_animated_donut_chart( | |
| list(scenario_data["categories"].values()), | |
| list(scenario_data["categories"].keys()), | |
| ['#10b981', '#f59e0b', '#ef4444'] | |
| ) | |
| st.plotly_chart(fig_scenario, use_container_width=True, key="scenario_new_chart") | |
| # Show insights | |
| st.markdown("#### 💡 What This Means") | |
| for insight in comparison['insights']: | |
| st.info(insight) | |
| elif category == "Education": | |
| current_exam = analyze_exam_performance(current_profile) | |
| scenario_exam = analyze_exam_performance(scenario_profile) | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| st.markdown("#### Current Performance") | |
| st.metric("Score", current_profile['recent_exam']) | |
| st.metric("To Goal", f"{current_exam['points_needed']} pts") | |
| with col2: | |
| st.markdown("#### Scenario Performance") | |
| st.metric("Score", scenario_profile['recent_exam'], | |
| delta=f"{scenario_profile['recent_exam'] - current_profile['recent_exam']:+}") | |
| st.metric("To Goal", f"{scenario_exam['points_needed']} pts", | |
| delta=f"{scenario_exam['points_needed'] - current_exam['points_needed']:+}") | |
| # ===== NEW: WHAT-IF MODE ===== | |
| def render_whatif_mode(profile, category): | |
| """ | |
| Interactive what-if mode with sliders. | |
| User can adjust values and see instant impact. | |
| """ | |
| st.markdown("### 🔮 What-If Mode") | |
| st.markdown("*Adjust values to see instant impact*") | |
| if category == "Finance": | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| new_spend = st.slider( | |
| "Monthly Spending", | |
| 0, 5000, | |
| profile['spend'], | |
| 50, | |
| key="whatif_spend" | |
| ) | |
| with col2: | |
| new_budget = st.slider( | |
| "Monthly Budget", | |
| 1000, 10000, | |
| profile['budget'], | |
| 100, | |
| key="whatif_budget" | |
| ) | |
| # Create scenario | |
| scenario = profile.copy() | |
| scenario['spend'] = new_spend | |
| scenario['budget'] = new_budget | |
| # Show impact | |
| st.markdown("#### Impact Analysis") | |
| col1, col2, col3 = st.columns(3) | |
| current_remaining = profile['budget'] - profile['spend'] | |
| scenario_remaining = new_budget - new_spend | |
| with col1: | |
| st.metric("Current Remaining", f"${current_remaining:,}") | |
| with col2: | |
| st.metric("Scenario Remaining", f"${scenario_remaining:,}", | |
| delta=f"{scenario_remaining - current_remaining:+,}") | |
| with col3: | |
| spend_pct = round((new_spend / new_budget) * 100, 1) | |
| status = "✅ On Track" if spend_pct <= 75 else "⚠️ Over Target" | |
| st.metric("Status", status) | |
| # Visual comparison | |
| render_scenario_comparison(profile, scenario, category) | |
| elif category == "Education": | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| new_score = st.slider( | |
| "New Exam Score", | |
| 400, 1600, | |
| profile['recent_exam'], | |
| 10, | |
| key="whatif_score" | |
| ) | |
| with col2: | |
| study_hours = st.slider( | |
| "Study Hours/Week", | |
| 0, 40, | |
| 10, | |
| 1, | |
| key="whatif_study" | |
| ) | |
| # Create scenario | |
| scenario = profile.copy() | |
| scenario['recent_exam'] = new_score | |
| # Show impact | |
| st.markdown("#### Impact Analysis") | |
| col1, col2, col3 = st.columns(3) | |
| current_to_goal = profile['goal'] - profile['recent_exam'] | |
| scenario_to_goal = profile['goal'] - new_score | |
| with col1: | |
| st.metric("Current Score", profile['recent_exam']) | |
| with col2: | |
| st.metric("Scenario Score", new_score, | |
| delta=f"{new_score - profile['recent_exam']:+}") | |
| with col3: | |
| st.metric("Points to Goal", scenario_to_goal, | |
| delta=f"{scenario_to_goal - current_to_goal:+}") | |
| # ===== EXISTING: DASHBOARD SUMMARY ===== | |
| def render_dashboard_summary(profile, category): | |
| st.markdown("### 📊 Your Dashboard") | |
| render_profile_editor(profile, category) | |
| col1, col2, col3 = st.columns(3) | |
| if category == "Finance": | |
| with col1: | |
| spend_pct = round((profile['spend'] / profile['budget']) * 100, 1) | |
| delta = f"🔴 {spend_pct}% of ${profile['budget']:,}" if spend_pct > 75 else f"🟢 {spend_pct}% of ${profile['budget']:,}" | |
| st.markdown(get_metric_card_html("This Month's Budget Used", f"${profile['spend']:,}", delta, "💰"), unsafe_allow_html=True) | |
| with col2: | |
| remaining = profile['budget'] - profile['spend'] | |
| st.markdown(get_metric_card_html("Remaining Budget", f"${remaining:,}", f"💡 {round((remaining/profile['budget'])*100, 1)}% left", "💳"), unsafe_allow_html=True) | |
| with col3: | |
| st.markdown(get_metric_card_html("Savings Goal", "1,200 dollars", "✨ +300 dollars from last month", "🎯"), unsafe_allow_html=True) | |
| elif category == "Education": | |
| with col1: | |
| exam_data = analyze_exam_performance(profile) | |
| st.markdown(get_metric_card_html("Recent Exam Score", f"{profile['recent_exam']}", f"🎯 Goal: {profile['goal']} ({exam_data['points_needed']} needed)", "📚"), unsafe_allow_html=True) | |
| with col2: | |
| progress_pct = round((profile['recent_exam'] / profile['goal']) * 100, 1) | |
| st.markdown(get_metric_card_html("Goal Progress", f"{progress_pct}%", f"📈 {profile['recent_exam']}/{profile['goal']}", "🎯"), unsafe_allow_html=True) | |
| with col3: | |
| st.markdown(get_metric_card_html("Study Time Today", "-12%", "⚠️ Below average", "⏰"), unsafe_allow_html=True) | |
| # ===== ENHANCED: LEFT PANEL WITH PROACTIVE INSIGHTS ===== | |
| def render_left_panel(state, category): | |
| profile = state.profile | |
| # NEW: Show proactive AI insights at top | |
| render_proactive_insights(profile, category) | |
| render_dashboard_summary(profile, category) | |
| st.markdown("---") | |
| # Existing visuals | |
| if category == "Education": | |
| render_education_visuals(profile) | |
| elif category == "Finance": | |
| render_finance_visuals(profile) | |
| st.markdown("---") | |
| # NEW: What-If Mode button | |
| if category in ["Finance", "Education"]: | |
| with st.expander("🔮 Try What-If Mode", expanded=False): | |
| render_whatif_mode(profile, category) | |
| st.markdown("---") | |
| # Existing smart insights (kept for compatibility) | |
| st.markdown("### 💡 Smart Insights") | |
| insights = get_category_insights(category, profile) | |
| for i, insight in enumerate(insights[:3]): | |
| card_type = "warning" if "⚠️" in insight else "insight" | |
| st.markdown(get_insight_html(insight, card_type), unsafe_allow_html=True) | |
| if st.button(f"Ask about this", key=f"insight_{category}_{i}", use_container_width=True): | |
| set_seed_chat(f"Tell me more about: {insight}") | |
| # ===== EXISTING: EDUCATION VISUALS ===== | |
| def render_education_visuals(profile): | |
| exam_data = analyze_exam_performance(profile) | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| st.markdown("#### 📈 Score Breakdown") | |
| fig = create_animated_donut_chart( | |
| list(exam_data["score_breakdown"].values()), | |
| list(exam_data["score_breakdown"].keys()), | |
| CHART_PALETTES['education'] | |
| ) | |
| st.plotly_chart(fig, use_container_width=True, key="main_score_chart") | |
| with col2: | |
| st.markdown("#### 🎯 Goal Progress") | |
| fig = create_gauge_chart(profile['recent_exam'], profile['goal'], | |
| f"{profile['recent_exam']}/{profile['goal']}") | |
| st.plotly_chart(fig, use_container_width=True, key="main_goal_gauge") | |
| # ===== EXISTING: FINANCE VISUALS ===== | |
| def render_finance_visuals(profile): | |
| budget_data = calculate_budget_metrics(profile) | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| st.markdown("#### 💸 Spending Breakdown") | |
| fig = create_animated_donut_chart( | |
| list(budget_data["categories"].values()), | |
| list(budget_data["categories"].keys()), | |
| CHART_PALETTES['finance'] | |
| ) | |
| st.plotly_chart(fig, use_container_width=True, key="main_spending_chart") | |
| with col2: | |
| st.markdown("#### 🎯 Budget Status") | |
| fig = create_gauge_chart(profile['spend'], profile['budget'], | |
| f"${profile['spend']}/${profile['budget']}") | |
| st.plotly_chart(fig, use_container_width=True, key="main_budget_gauge") | |
| # ===== EXISTING: TOPIC EXTRACTION (unchanged) ===== | |
| def extract_topics_from_history(chat_history): | |
| """Extract ALL topics AND subtopics ever discussed""" | |
| all_user_text = " ".join([m['content'].lower() for m in chat_history if m['role'] == 'user']) | |
| topics_discussed = set() | |
| # Finance topics | |
| if any(w in all_user_text for w in ['save', 'savings', 'emergency', 'automate']): | |
| topics_discussed.add('savings') | |
| if any(w in all_user_text for w in ['invest', 'etf', 'stock', 'crypto', 'bitcoin', 'trading', 'options']): | |
| topics_discussed.add('investing') | |
| if any(w in all_user_text for w in ['budget', 'spend', 'expense', 'cost', 'cut', '50/30/20']): | |
| topics_discussed.add('budgeting') | |
| if any(w in all_user_text for w in ['debt', 'loan', 'credit', 'repay']): | |
| topics_discussed.add('debt') | |
| # Finance subtopics (deeper tracking) | |
| if any(w in all_user_text for w in ['etf', 'exchange traded']): | |
| topics_discussed.add('etf_basics') | |
| if any(w in all_user_text for w in ['index fund', 'index', 'mutual fund']): | |
| topics_discussed.add('index_funds') | |
| if any(w in all_user_text for w in ['bitcoin', 'crypto', 'cryptocurrency']): | |
| topics_discussed.add('crypto') | |
| if any(w in all_user_text for w in ['best etf', 'which etf', 'etf for']): | |
| topics_discussed.add('etf_selection') | |
| if any(w in all_user_text for w in ['long-term', 'long term', 'strategy']): | |
| topics_discussed.add('long_term') | |
| if any(w in all_user_text for w in ['dividend', 'yield', 'income']): | |
| topics_discussed.add('dividends') | |
| if any(w in all_user_text for w in ['rebalance', 'allocation', 'portfolio']): | |
| topics_discussed.add('portfolio') | |
| # Savings subtopics | |
| if any(w in all_user_text for w in ['high-yield', 'high yield', 'best savings']): | |
| topics_discussed.add('high_yield') | |
| if any(w in all_user_text for w in ['automate', 'automatic', 'auto-save']): | |
| topics_discussed.add('automate_savings') | |
| if any(w in all_user_text for w in ['emergency fund', 'emergency']): | |
| topics_discussed.add('emergency_fund') | |
| # Budgeting subtopics | |
| if any(w in all_user_text for w in ['50/30/20', 'budget rule']): | |
| topics_discussed.add('budget_rules') | |
| if any(w in all_user_text for w in ['track spending', 'budget app']): | |
| topics_discussed.add('tracking_tools') | |
| if any(w in all_user_text for w in ['cut expenses', 'reduce spending']): | |
| topics_discussed.add('cutting_expenses') | |
| # Education topics | |
| if any(w in all_user_text for w in ['study', 'exam', 'test', 'score', 'improve', 'focus']): | |
| topics_discussed.add('studying') | |
| if any(w in all_user_text for w in ['practice', 'question', 'weak', 'subject']): | |
| topics_discussed.add('practice') | |
| return topics_discussed | |
| def detect_current_topic(user_message_text): | |
| """Detect which topic the user is asking about RIGHT NOW""" | |
| text = user_message_text.lower() | |
| # Finance | |
| if any(w in text for w in ['save', 'savings', 'automate', 'emergency fund']): | |
| return 'savings' | |
| if any(w in text for w in ['invest', 'etf', 'stock', 'bitcoin', 'crypto', 'options', 'trading']): | |
| return 'investing' | |
| if any(w in text for w in ['budget', 'spend', 'expense', '50/30/20', 'cut', 'stick', 'track']): | |
| return 'budgeting' | |
| if any(w in text for w in ['debt', 'loan', 'credit', 'repay']): | |
| return 'debt' | |
| # Education | |
| if any(w in text for w in ['study', 'focus', 'rush', 'manage time']): | |
| return 'studying' | |
| if any(w in text for w in ['exam', 'test', 'score', 'weak', 'improve']): | |
| return 'exams' | |
| if any(w in text for w in ['practice', 'question', 'quiz']): | |
| return 'practice' | |
| return None | |
| # ===== EXISTING: FINANCE SUGGESTIONS (unchanged) ===== | |
| def get_suggestions_for_finance(chat_history, current_topic, topics_discussed): | |
| """FINANCE SUGGESTIONS - Progressive deepening""" | |
| if current_topic == 'savings': | |
| if 'savings' not in topics_discussed: | |
| return [ | |
| ("📈 High-yield accounts?", "What are the best high-yield savings accounts for Gen Z?"), | |
| ("🎯 Automate savings", "How can I automate my savings?"), | |
| ("💡 Cut biggest expenses", "What are my biggest expenses to cut?") | |
| ] | |
| else: | |
| return [ | |
| ("💳 Which account best for me?", "Which high-yield savings account would be best for my situation?"), | |
| ("🔄 Emergency fund sizing", "How much should I keep in an emergency fund?"), | |
| ("📊 Track savings progress", "How do I track and measure my automated savings?") | |
| ] | |
| elif current_topic == 'investing': | |
| # Level 1: Complete beginner | |
| if 'investing' not in topics_discussed: | |
| return [ | |
| ("📊 Start investing small", "How do I start investing with little money?"), | |
| ("🔍 ETFs vs stocks", "Should I invest in ETFs or individual stocks?"), | |
| ("📈 Best beginner ETFs", "What are beginner-friendly investment tips for Gen Z?") | |
| ] | |
| # Level 2: Asked about ETFs/basics, now go deeper | |
| elif 'etf_selection' not in topics_discussed and 'index_funds' not in topics_discussed: | |
| return [ | |
| ("💎 Best ETFs for my age", "What are the best ETFs for my age and budget?"), | |
| ("📈 Index funds?", "What's the difference between ETFs and index funds?"), | |
| ("🔐 Safe investments", "What are the safest investment options for beginners?") | |
| ] | |
| # Level 3: Asked about specific ETFs/index funds, now strategy | |
| elif 'long_term' not in topics_discussed and 'portfolio' not in topics_discussed: | |
| return [ | |
| ("⏰ Long-term strategy", "What's a good long-term investment strategy?"), | |
| ("📊 Portfolio allocation", "How should I allocate my investment portfolio?"), | |
| ("💰 Dividend investing", "Should I focus on dividend-paying investments?") | |
| ] | |
| # Level 4: Advanced investor questions | |
| else: | |
| return [ | |
| ("🔄 Rebalancing", "When and how should I rebalance my portfolio?"), | |
| ("🌍 International ETFs", "Should I invest in international ETFs?"), | |
| ("📈 Growth vs value", "What's the difference between growth and value investing?") | |
| ] | |
| elif current_topic == 'budgeting': | |
| if 'budgeting' not in topics_discussed: | |
| return [ | |
| ("✂️ Cut expenses smartly", "Where can I cut expenses without sacrificing quality?"), | |
| ("📊 Track spending", "Best way to track my spending automatically?"), | |
| ("🎯 Create monthly budget", "Help me create a realistic monthly budget") | |
| ] | |
| else: | |
| return [ | |
| ("50/30/20 rule?", "Should I use the 50/30/20 budgeting rule?"), | |
| ("💳 Best budget app", "What budget tracking app should I use?"), | |
| ("🎯 Stick to budget", "How do I actually stick to my budget?") | |
| ] | |
| elif current_topic == 'debt': | |
| if 'debt' not in topics_discussed: | |
| return [ | |
| ("💳 Pay off faster", "Best strategy to pay off debt faster?"), | |
| ("🔍 Debt vs savings", "Should I focus on debt or savings first?"), | |
| ("📉 Lower interest", "How to reduce credit card interest rates?") | |
| ] | |
| else: | |
| return [ | |
| ("📊 Snowball vs avalanche", "Is snowball or avalanche better for me?"), | |
| ("⏰ Payoff timeline", "How long would it take to pay off my debt?"), | |
| ("🆘 Negotiate rates", "Can I negotiate lower interest rates?") | |
| ] | |
| else: | |
| return [ | |
| ("💰 Save more?", "How can I save more money this month?"), | |
| ("📊 Break down spending", "Break down my spending and show where to cut costs"), | |
| ("📈 Investment tips", "What are beginner-friendly investment tips for Gen Z?") | |
| ] | |
| # ===== EXISTING: EDUCATION SUGGESTIONS (unchanged) ===== | |
| def get_suggestions_for_education(chat_history, current_topic, topics_discussed): | |
| """EDUCATION SUGGESTIONS - Progressive deepening""" | |
| if current_topic == 'studying': | |
| if 'studying' not in topics_discussed: | |
| return [ | |
| ("⏰ Study schedule", "Help me create an effective study schedule"), | |
| ("🎯 Stay focused", "Best techniques to stay focused while studying?"), | |
| ("📝 Take notes better", "What's the most effective way to take notes?") | |
| ] | |
| else: | |
| return [ | |
| ("🚀 Pomodoro technique", "How does the Pomodoro technique work for studying?"), | |
| ("📍 Study environment", "How do I create a good study environment?"), | |
| ("⚡ Study groups", "How can I make study groups effective?") | |
| ] | |
| elif current_topic == 'exams': | |
| if 'exams' not in topics_discussed: | |
| return [ | |
| ("📊 Boost scores fast", "What's the fastest way to improve exam scores?"), | |
| ("✏️ Test strategies", "Give me strategies for better test performance"), | |
| ("🎯 Fix weak subjects", "How do I tackle my weakest subjects?") | |
| ] | |
| else: | |
| return [ | |
| ("🧠 Active recall", "How does active recall help with exam prep?"), | |
| ("📅 Study calendar", "How should I plan my study calendar for exams?"), | |
| ("😰 Test anxiety", "How do I handle test anxiety?") | |
| ] | |
| elif current_topic == 'practice': | |
| if 'practice' not in topics_discussed: | |
| return [ | |
| ("✏️ Practice questions", "Give me practice questions for my weakest subject"), | |
| ("🎯 Target weak areas", "How do I focus practice on weak areas?"), | |
| ("📊 Quiz myself", "What's the best way to quiz myself?") | |
| ] | |
| else: | |
| return [ | |
| ("🔄 Spaced repetition", "How does spaced repetition work?"), | |
| ("📈 Track progress", "How do I measure improvement from practice?"), | |
| ("💡 Learn from mistakes", "How should I analyze my practice mistakes?") | |
| ] | |
| else: | |
| return [ | |
| ("📚 Analyze exam", "Analyze my last exam and tell me where to improve"), | |
| ("✏️ Practice questions", "Give me practice questions for my weakest subject"), | |
| ("🎯 Improve scores", "What's the fastest way to improve my exam scores?") | |
| ] | |
| # ===== EXISTING: DYNAMIC SUGGESTIONS (unchanged) ===== | |
| def get_dynamic_suggestions_v4(chat_history, category): | |
| """PRODUCTION VERSION - Never recycles suggestions""" | |
| if len(chat_history) <= 1: | |
| if category == "Finance": | |
| return [ | |
| ("💰 Save more?", "How can I save more money this month?"), | |
| ("📊 Break down spending", "Break down my spending and show where to cut costs"), | |
| ("📈 Investment tips", "What are beginner-friendly investment tips for Gen Z?") | |
| ] | |
| elif category == "Education": | |
| return [ | |
| ("📚 Analyze exam", "Analyze my last exam and tell me where to improve"), | |
| ("✏️ Practice questions", "Give me practice questions for my weakest subject"), | |
| ("🎯 Improve scores", "What's the fastest way to improve my exam scores?") | |
| ] | |
| topics_discussed = extract_topics_from_history(chat_history) | |
| latest_user_msg = "" | |
| for msg in reversed(chat_history): | |
| if msg['role'] == 'user': | |
| latest_user_msg = msg['content'] | |
| break | |
| current_topic = detect_current_topic(latest_user_msg) | |
| if category == "Finance": | |
| return get_suggestions_for_finance(chat_history, current_topic, topics_discussed) | |
| elif category == "Education": | |
| return get_suggestions_for_education(chat_history, current_topic, topics_discussed) | |
| return [("💭 Ask something", "What's on your mind?")] | |
| # ===== EXISTING: CHAT PANEL (unchanged) ===== | |
| def render_chat_panel(chat_history_key, category): | |
| """Chat panel with PRODUCTION-READY suggestion engine""" | |
| icon_map = {"Finance": "💰", "Education": "📚", "Family": "👨👩👧", "Friends": "👥", "Weekend/Vacation": "🏖"} | |
| category_icon = icon_map.get(category, "🎯") | |
| col1, col2 = st.columns([4, 1]) | |
| with col1: | |
| st.markdown(f"### 💬 Chat with Aqua about {category_icon} {category}") | |
| with col2: | |
| if st.button("🔄 Reset", key=f"reset_chat_{category}", use_container_width=True, type="secondary"): | |
| st.session_state[chat_history_key] = [] | |
| st.rerun() | |
| if not st.session_state[chat_history_key]: | |
| welcome_msg = f"Hey! 👋 I'm Aqua, your {category.lower()} mentor. What's on your mind?" | |
| st.session_state[chat_history_key].append({"role": "assistant", "content": welcome_msg}) | |
| # Display all messages | |
| for msg in st.session_state[chat_history_key]: | |
| with st.chat_message(msg["role"], avatar="🌊" if msg["role"] == "assistant" else "👤"): | |
| st.markdown(msg["content"]) | |
| st.markdown("---") | |
| st.markdown("### ⚡ Quick Actions") | |
| suggestions = get_dynamic_suggestions_v4(st.session_state[chat_history_key], category) | |
| if suggestions: | |
| cols = st.columns(min(len(suggestions), 3)) | |
| for i, (display_text, full_prompt) in enumerate(suggestions): | |
| col_idx = i % len(cols) | |
| button_key = f"quick_{category}_{i}_{len(st.session_state[chat_history_key])}_prod" | |
| if cols[col_idx].button(display_text, key=button_key, use_container_width=True): | |
| set_seed_chat(full_prompt) |