"""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)