"""Module for rendering the PortIQ Portfolio AI chat dialog assistant.""" import streamlit as st import os import json import pandas as pd def on_chat_date_change(): # Update chat_context_date to the selector's value st.session_state["chat_context_date"] = st.session_state["chat_context_date_selector"] # Clear chat history when date context changes st.session_state["chat_history"] = [] def on_chat_close(): st.session_state["show_chat"] = False def _inject_dialog_styles(): """Injects CSS scoped exclusively to the PortIQ chat dialog via a unique marker class.""" st.markdown( """ """, unsafe_allow_html=True ) @st.dialog("💬 PortIQ Portfolio AI", width="large", on_dismiss=on_chat_close) def render_chat_assistant(api_key): """Renders the interactive chat assistant modal.""" from modules.api_caller import run_chat_assistant # Inject dialog-scoped styles _inject_dialog_styles() # Unique wrapper div — all scoped CSS is anchored to .tcr-chat-dlg st.markdown('
', unsafe_allow_html=True) # Auto-scroll helper: fires on mount via a hidden st.markdown( """ """, unsafe_allow_html=True ) # ── 1. Context Date Selection ────────────────────────────────────────────── using_db = False history_dates = [] try: from modules.db import get_available_briefing_dates, get_briefing_from_db history_dates = get_available_briefing_dates() using_db = True except Exception as e: print(f"[chat] DB dates fetch failed, falling back to files: {e}") if not using_db: hist_dir = "history" if os.path.exists(hist_dir): history_files = sorted( [f for f in os.listdir(hist_dir) if f.endswith(".json") and f != "performance_cache.json"], reverse=True ) history_dates = [f.replace(".json", "") for f in history_files] available_dates = [] if "report_data" in st.session_state: available_dates.append("Today") available_dates.extend(history_dates) if not available_dates: st.info("No briefing data available. Please upload portfolio data first.") st.markdown('
', unsafe_allow_html=True) return current_selected = st.session_state.get("chat_context_date", "Today") if current_selected not in available_dates: current_selected = available_dates[0] st.session_state["chat_context_date"] = current_selected st.selectbox( "Briefing Date Context", available_dates, index=available_dates.index(current_selected), key="chat_context_date_selector", on_change=on_chat_date_change, label_visibility="visible" ) selected_date = st.session_state.get("chat_context_date", "Today") # ── Load data for selected date ──────────────────────────────────────────── active_report_data = None active_portfolio_df = None if selected_date == "Today": active_report_data = st.session_state.get("report_data") active_portfolio_df = st.session_state.get("df_original") else: if using_db: try: active_report_data = get_briefing_from_db(selected_date) if active_report_data: active_portfolio_df = pd.DataFrame(active_report_data.get("_portfolio_snapshot", [])) except Exception as e: st.error(f"Error loading {selected_date} from DB: {e}") else: try: with open(os.path.join("history", f"{selected_date}.json"), "r", encoding="utf-8") as fp: active_report_data = json.load(fp) active_portfolio_df = pd.DataFrame(active_report_data.get("_portfolio_snapshot", [])) except Exception as e: st.error(f"Error loading {selected_date} from file: {e}") # ── 2. Actions row ───────────────────────────────────────────────────────── col_clear, col_status = st.columns([4, 6]) with col_clear: if st.button("🗑️ Clear Chat", key="btn_clear_chat_history", use_container_width=True): st.session_state["chat_history"] = [] st.rerun() with col_status: if active_report_data: st.markdown( f"

" f"🟢 Context Loaded ({selected_date})

", unsafe_allow_html=True ) else: st.markdown( "

" "🔴 No Data Loaded

", unsafe_allow_html=True ) st.divider() # ── 3. Scrollable Chat History ───────────────────────────────────────────── if "chat_history" not in st.session_state: st.session_state["chat_history"] = [] chat_container = st.container(height=420) with chat_container: if not st.session_state["chat_history"]: st.chat_message("assistant").write( f"Hi Ram! 👋 I'm PortIQ. Ask me anything about your briefing and stock decisions for **{selected_date}**." ) for msg in st.session_state["chat_history"]: st.chat_message(msg["role"]).write(msg["content"]) # ── 4. Chat Input ────────────────────────────────────────────────────────── user_query = st.chat_input("Ask PortIQ AI...", key="chat_input_query") if user_query: st.session_state["chat_history"].append({"role": "user", "content": user_query}) with chat_container: st.chat_message("user").write(user_query) with chat_container: with st.spinner("PortIQ is analyzing..."): response = run_chat_assistant( query=user_query, chat_history=st.session_state["chat_history"][:-1], active_date=selected_date, active_report_data=active_report_data, active_portfolio_df=active_portfolio_df, api_key=api_key ) st.chat_message("assistant").write(response) st.session_state["chat_history"].append({"role": "assistant", "content": response}) st.rerun() st.markdown('', unsafe_allow_html=True)