sales_analytics / page_manager.py
cryogenic22's picture
Update page_manager.py
2a4697e verified
"""
Page Manager for Pharmaceutical Analytics Application
This module manages the different pages/views of the application,
enabling a multi-page structure without bloating the main app.py.
"""
import streamlit as st
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from datetime import datetime
import time
import threading
import queue
import sys
import traceback
import json
# Import diagnostics module
from updated_diagnostics import render_diagnostics_tab
def run_workflow_in_thread(workflow, alert):
"""Run the workflow in a separate thread and update session state"""
try:
# Update status
st.session_state.status_queue.put(("info", "Planning analysis approach..."))
st.session_state.current_step = "planning"
# Run the workflow
print(f"Starting workflow with alert: {alert}")
result = workflow.run_workflow(alert)
print("Workflow completed successfully")
# Store the result
st.session_state.workflow_state = result
# Update status
st.session_state.status_queue.put(("success", "Analysis complete!"))
st.session_state.current_step = "complete"
except Exception as e:
error_details = f"Error in workflow: {str(e)}\n{traceback.format_exc()}"
print(error_details)
st.session_state.status_queue.put(("error", f"Error: {str(e)}"))
st.session_state.current_step = "error"
# Store error details
if "error_details" not in st.session_state:
st.session_state.error_details = []
st.session_state.error_details.append(error_details)
def run_workflow_directly(alert_text):
"""Run the workflow directly (not in a thread) for debugging"""
try:
# Create the workflow
SalesAnalysisWorkflow = st.session_state.agents["SalesAnalysisWorkflow"]
workflow = SalesAnalysisWorkflow(db_path="data/pharma_db.sqlite")
# Update status
st.session_state.current_step = "planning"
# Run the workflow with verbose debug output
st.info("Running workflow directly...")
# Add detailed debugging information at each step
st.write("1. Creating workflow instance")
# Store the alert in session state
st.session_state.alert = alert_text
# Run the workflow step by step
st.write("2. Starting workflow execution")
result = workflow.run_workflow(alert_text)
# Print workflow state
st.write("3. Workflow execution completed")
st.write(f"Status: {result.get('status', 'unknown')}")
st.write(f"Plan created: {'Yes' if result.get('plan') else 'No'}")
st.write(f"Data sources: {len(result.get('data_sources', {}))}")
st.write(f"Analysis results: {len(result.get('analysis_results', {}))}")
st.write(f"Validation results: {len(result.get('validation_results', {}))}")
st.write(f"Insight requests: {len(result.get('insight_requests', []))}")
st.write(f"Insight cards: {len(result.get('insight_cards', {}))}")
# Store the result
st.session_state.workflow_state = result
st.session_state.current_step = "complete"
# Add debug output
if "insight_requests" in result and result["insight_requests"]:
st.write("Insight Requests Details:")
for i, req in enumerate(result["insight_requests"]):
st.write(f"Request {i+1}: ID={req.request_id}")
return True
except Exception as e:
st.error(f"Error in direct workflow execution: {str(e)}")
st.code(traceback.format_exc())
return False
def render_main_page():
"""Render the main page with alert input and sample dashboard"""
st.header("📱 Incoming Alert")
col1, col2 = st.columns([3, 1])
with col1:
# Dropdown for alert selection
alert_option = st.selectbox(
"Select Alert Type:",
[
"Sales Decline",
"Market Share Loss",
"Inventory Issue",
"Competitor Launch",
"Custom Alert"
]
)
# Alert templates
alert_templates = {
"Sales Decline": "Sales of DrugX down 15% in Northeast region over past 30 days compared to forecast.",
"Market Share Loss": "Market share of DrugX decreased by 8 percentage points in the Southeast region over the last quarter.",
"Inventory Issue": "Multiple stockouts of DrugX reported in Midwest distribution centers affecting 25% of pharmacies.",
"Competitor Launch": "Competitor MedCorp launched similar product at 20% lower price point in Western territories.",
"Custom Alert": ""
}
# Alert description
alert_text = st.text_area(
"Alert Description:",
value=alert_templates[alert_option],
height=100
)
# Submit button (only enabled if agents are loaded)
submit_button = st.button("Analyze Alert", disabled=not st.session_state.get("agents_loaded", False))
if submit_button and alert_text:
try:
# Initialize queue if not exists
if "status_queue" not in st.session_state:
st.session_state.status_queue = queue.Queue()
# Create and start the workflow
SalesAnalysisWorkflow = st.session_state.agents["SalesAnalysisWorkflow"]
workflow = SalesAnalysisWorkflow(db_path="data/pharma_db.sqlite")
# Show initial status
st.info("Starting analysis workflow...")
st.session_state.logs.append({
"timestamp": datetime.now().isoformat(),
"type": "info",
"message": "Starting analysis workflow..."
})
# Store the alert in session state
st.session_state.alert = alert_text
# Start the workflow in a separate thread
thread = threading.Thread(
target=run_workflow_in_thread,
args=(workflow, alert_text),
daemon=True
)
thread.start()
# Store the thread and mark alert as submitted
st.session_state.workflow_thread = thread
st.session_state.alert_submitted = True
# Change active page to analysis viewer
st.session_state.active_page = "analysis"
# Force page refresh
st.rerun()
except Exception as e:
st.error(f"Error starting workflow: {str(e)}")
st.code(traceback.format_exc())
# Add fallback direct execution button
if alert_text and st.session_state.get("agents_loaded", False):
if st.button("Debug: Run Directly (No Thread)"):
if run_workflow_directly(alert_text):
st.success("Workflow completed! Check the Analysis Viewer page.")
st.session_state.active_page = "analysis"
st.rerun()
with col2:
st.image("https://img.icons8.com/fluency/240/000000/notification-center.png", width=150)
st.markdown("**Source:** Mobile Alert System")
st.markdown("**Priority:** High")
st.markdown("**Time:** " + datetime.now().strftime("%Y-%m-%d %H:%M"))
# Show example dashboard
st.markdown("---")
st.header("📊 Example Dashboard Preview")
# Create sample visualization
fig = px.line(
pd.DataFrame({
'Month': pd.date_range(start='2023-01-01', periods=12, freq='M'),
'Sales': [1200, 1250, 1300, 1400, 1500, 1600, 1550, 1500, 1450, 1300, 1200, 1150],
'Target': [1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550, 1600, 1650, 1700, 1750]
}),
x='Month',
y=['Sales', 'Target'],
title="DrugX Performance (Sample Data)",
labels={"value": "Sales ($K)", "variable": "Metric"}
)
fig.update_layout(height=400)
st.plotly_chart(fig, use_container_width=True)
def render_page():
"""Render the current active page based on session state"""
# Initialize session state if needed
initialize_session()
# Process status updates from thread if workflow is running
if st.session_state.get("workflow_thread") and st.session_state.workflow_thread.is_alive():
while not st.session_state.status_queue.empty():
status_type, status_message = st.session_state.status_queue.get()
if status_type == "info":
st.info(status_message)
elif status_type == "success":
st.success(status_message)
elif status_type == "error":
st.error(status_message)
# Add to logs
st.session_state.logs.append({
"timestamp": datetime.now().isoformat(),
"type": status_type,
"message": status_message
})
# Create navigation in sidebar
with st.sidebar:
st.header("Navigation")
# Only show navigation options if environment is ready
if st.session_state.get("environment_ready", False):
pages = {
"main": "Home",
"analysis": "Analysis Viewer",
"diagnostics": "Diagnostics"
}
# Only show Analysis Viewer option if an analysis exists
if st.session_state.get("workflow_state") is None and "analysis" in pages:
pages = {k: v for k, v in pages.items() if k != "analysis"}
# Radio buttons for navigation
selected_page = st.radio("Go to", list(pages.values()))
# Map selection back to page key
reverse_pages = {v: k for k, v in pages.items()}
st.session_state.active_page = reverse_pages.get(selected_page, "main")
# Render the active page
active_page = st.session_state.get("active_page", "main")
if active_page == "main":
render_main_page()
elif active_page == "analysis":
workflow_state = st.session_state.get("workflow_state")
if workflow_state:
if workflow_state.get("status") == "complete":
render_analysis_results(workflow_state)
else:
render_analysis_progress()
else:
st.info("No analysis is currently running. Start an analysis from the Home page.")
st.session_state.active_page = "main"
st.rerun()
elif active_page == "diagnostics":
render_diagnostics_tab()
else:
st.error(f"Unknown page: {active_page}")
st.session_state.active_page = "main"
def render_analysis_progress():
"""Render the analysis progress view"""
# Show progress
current_step = st.session_state.current_step
# Progress indicators
st.markdown("### 🔄 Analysis in Progress")
# Progress bar
steps = ["planning", "data_collection", "analysis", "validation", "insights", "complete"]
step_idx = steps.index(current_step) if current_step in steps else 0
progress = (step_idx + 1) / len(steps)
progress_bar = st.progress(progress)
# Step indicators
col1, col2, col3, col4, col5 = st.columns(5)
with col1:
check = "✅" if step_idx >= 0 else "🔄"
check = "🔄" if step_idx == 0 else check
st.markdown(f"{check} **Planning**")
with col2:
check = "✅" if step_idx >= 1 else "⏳"
check = "🔄" if step_idx == 1 else check
st.markdown(f"{check} **Data Collection**")
with col3:
check = "✅" if step_idx >= 2 else "⏳"
check = "🔄" if step_idx == 2 else check
st.markdown(f"{check} **Analysis**")
with col4:
check = "✅" if step_idx >= 3 else "⏳"
check = "🔄" if step_idx == 3 else check
st.markdown(f"{check} **Validation**")
with col5:
check = "✅" if step_idx >= 4 else "⏳"
check = "🔄" if step_idx == 4 else check
st.markdown(f"{check} **Insights**")
# Show current activity based on step
st.markdown("---")
# Display the alert being analyzed
alert_container = st.container(border=True)
with alert_container:
st.markdown("**Alert Being Analyzed:**")
st.info(st.session_state.get("alert", "Unknown alert"))
# Show thinking animation or appropriate step visualization
thinking_container = st.container()
with thinking_container:
if current_step == "planning":
render_planning_activity()
elif current_step == "data_collection":
render_data_collection_activity()
elif current_step == "analysis":
render_analysis_activity()
elif current_step == "validation":
render_validation_activity()
elif current_step == "insights":
render_insights_activity()
# Placeholder for log console
with st.expander("View Process Log"):
for log in st.session_state.logs:
timestamp = log.get("timestamp", "")
message = log.get("message", "")
log_type = log.get("type", "info")
if log_type == "error":
st.error(f"{timestamp}: {message}")
else:
st.text(f"{timestamp}: {message}")
# Display any error details if available
if "error_details" in st.session_state and st.session_state.error_details:
with st.expander("Error Details", expanded=True):
for i, error in enumerate(st.session_state.error_details):
st.error(f"Error {i+1}:")
st.code(error)
# Auto refresh only if thread is still running
if st.session_state.get("workflow_thread") and st.session_state.workflow_thread.is_alive():
time.sleep(0.5)
st.rerun()
def render_planning_activity():
"""Render Planning Agent activity visualization"""
st.markdown("### 🧠 Planning Agent at Work")
st.markdown("The Planning Agent is decomposing the problem and creating an analysis plan.")
# Show thinking animation
thinking_messages = [
"Identifying required data sources...",
"Determining appropriate analytical approaches...",
"Creating task dependency graph...",
"Designing validation strategy..."
]
thinking_placeholder = st.empty()
for i in range(len(thinking_messages)):
thinking_placeholder.info(thinking_messages[i % len(thinking_messages)])
time.sleep(0.5)
def render_data_collection_activity():
"""Render Data Agent activity visualization"""
st.markdown("### 🗃️ Data Agent at Work")
st.markdown("The Data Agent is translating requirements into SQL queries and collecting data.")
# Show SQL generation animation
if st.session_state.get("show_sql", False):
sql_placeholder = st.empty()
example_sql = """
-- Retrieving DrugX sales data by region
SELECT
r.region_name,
strftime('%Y-%m', s.sale_date) as month,
SUM(s.units_sold) as total_units,
SUM(s.revenue) as total_revenue,
SUM(s.margin) as total_margin
FROM
sales s
JOIN
regions r ON s.region_id = r.region_id
WHERE
s.product_id = 'DRX'
AND s.sale_date >= date('now', '-90 days')
GROUP BY
r.region_name, strftime('%Y-%m', s.sale_date)
ORDER BY
r.region_name, month;
"""
for i in range(0, min(len(example_sql), 100), 10):
sql_placeholder.code(example_sql[:i] + "▌", language="sql")
time.sleep(0.02)
sql_placeholder.code(example_sql, language="sql")
def render_analysis_activity():
"""Render Analytics Agent activity visualization"""
st.markdown("### 📊 Analytics Agent at Work")
st.markdown("The Analytics Agent is performing statistical analysis and modeling.")
# Show Python code generation animation
if st.session_state.get("show_code", False):
code_placeholder = st.empty()
example_code = """
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from statsmodels.tsa.seasonal import seasonal_decompose
def analyze_sales_decline(sales_df):
# Convert date column to datetime
sales_df['date'] = pd.to_datetime(sales_df['date'])
# Focus on Northeast region
ne_sales = sales_df[sales_df['region'] == 'Northeast']
# Perform time series decomposition
result = seasonal_decompose(ne_sales['sales'],
model='multiplicative',
period=12)
# Calculate percentage decline
latest_month = ne_sales['date'].max()
prev_month = latest_month - pd.DateOffset(months=1)
latest_sales = ne_sales[ne_sales['date'] == latest_month]['sales'].values[0]
prev_sales = ne_sales[ne_sales['date'] == prev_month]['sales'].values[0]
pct_decline = (prev_sales - latest_sales) / prev_sales * 100
"""
for i in range(0, min(len(example_code), 200), 20):
code_placeholder.code(example_code[:i] + "▌", language="python")
time.sleep(0.01)
code_placeholder.code(example_code, language="python")
def render_validation_activity():
"""Render QA Agent activity visualization"""
st.markdown("### 🔍 QA Agent at Work")
st.markdown("The QA Agent is validating the analysis results for accuracy and completeness.")
# Show quality checks
checks = [
{"check": "Data completeness", "status": "Running..."},
{"check": "Statistical significance", "status": "Waiting..."},
{"check": "Alternative hypotheses", "status": "Waiting..."},
{"check": "Insight relevance", "status": "Waiting..."}
]
check_placeholder = st.empty()
for i in range(min(len(checks), 4)):
checks[i]["status"] = "Passed ✅"
check_table = pd.DataFrame(checks)
check_placeholder.table(check_table)
time.sleep(0.5)
def render_insights_activity():
"""Render Insights Agent activity visualization"""
st.markdown("### 💡 Insights Agent at Work")
st.markdown("The Insights Agent is generating visualizations and actionable recommendations.")
# Show visualization generation
viz_placeholder = st.empty()
# Create sample visualization progressively
for i in range(1, 5):
fig = go.Figure()
months = pd.date_range(start='2023-01-01', periods=12, freq='M')
sales = [1200, 1250, 1300, 1400, 1500, 1600, 1550, 1500, 1450, 1300, 1200, 1150]
targets = [1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550, 1600, 1650, 1700, 1750]
if i >= 1:
fig.add_trace(go.Scatter(
x=months[:8+i],
y=targets[:8+i],
mode='lines+markers',
name='Target',
line=dict(color='green', width=2)
))
if i >= 2:
fig.add_trace(go.Scatter(
x=months[:8+i],
y=sales[:8+i],
mode='lines+markers',
name='Actual Sales',
line=dict(color='blue', width=2)
))
if i >= 3:
# Add competitor launch annotation
fig.add_vline(
x=months[9],
line_dash="dash",
line_color="red",
annotation_text="Competitor Launch" if i >= 4 else ""
)
fig.update_layout(
title="DrugX Performance Analysis",
xaxis_title="Month",
yaxis_title="Sales ($K)",
height=400
)
viz_placeholder.plotly_chart(fig, use_container_width=True)
time.sleep(0.5)
def render_analysis_results(workflow_state):
"""Render completed analysis results"""
st.markdown("### ✅ Analysis Complete")
# Display debug info at the top if there were any issues
if "error_details" in st.session_state and st.session_state.error_details:
with st.expander("Debug Information", expanded=False):
for i, error in enumerate(st.session_state.error_details):
st.error(f"Error {i+1}:")
st.code(error)
# Extract plan and insights
plan = workflow_state.get("plan")
insight_cards = workflow_state.get("insight_cards", {})
visualizations = workflow_state.get("visualizations", [])
# Display the alert
st.markdown("#### 📱 Alert Analyzed")
st.info(workflow_state.get("alert", ""))
# Display the problem statement
if plan:
st.markdown("#### 🎯 Problem Analysis")
st.markdown(plan.problem_statement)
# Display insight cards
st.markdown("---")
st.markdown("### 💡 Key Insights")
if insight_cards:
for card_id, card in insight_cards.items():
# Create a card-like container
with st.container():
st.subheader(card.title)
st.markdown(card.description)
# Display visualizations if available
if hasattr(card, 'charts') and card.charts and len(visualizations) > 0:
# Generate sample visualizations
cols = st.columns(min(len(card.charts), 2))
for i, chart_name in enumerate(card.charts[:2]):
with cols[i % 2]:
# Create appropriate chart based on name
if "trend" in chart_name.lower():
# Create sample time series
months = pd.date_range(start='2023-01-01', periods=12, freq='M')
sales = [1200, 1250, 1300, 1400, 1500, 1600, 1550, 1500, 1450, 1300, 1200, 1150]
targets = [1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550, 1600, 1650, 1700, 1750]
fig = go.Figure()
fig.add_trace(go.Scatter(
x=months, y=sales, mode='lines+markers', name='Actual Sales',
line=dict(color='blue', width=2)
))
fig.add_trace(go.Scatter(
x=months, y=targets, mode='lines+markers', name='Target',
line=dict(color='green', width=2, dash='dash')
))
# Add competitor launch annotation
fig.add_vline(
x=months[9], line_dash="dash", line_color="red",
annotation_text="Competitor Launch"
)
fig.update_layout(
title="DrugX Sales Trend",
xaxis_title="Month",
yaxis_title="Sales ($K)",
height=300
)
st.plotly_chart(fig, use_container_width=True)
elif "competitor" in chart_name.lower():
# Create sample competitor comparison
fig = go.Figure()
# Market share data
months = pd.date_range(start='2023-01-01', periods=12, freq='M')
drugx_share = [65, 64, 66, 67, 68, 67, 66, 65, 64, 58, 54, 50]
competitor_share = [0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 10, 15]
other_share = [35, 36, 34, 33, 32, 33, 34, 35, 36, 37, 36, 35]
fig.add_trace(go.Bar(
x=months, y=drugx_share, name='DrugX',
marker_color='blue'
))
fig.add_trace(go.Bar(
x=months, y=competitor_share, name='CompDrug2',
marker_color='red'
))
fig.add_trace(go.Bar(
x=months, y=other_share, name='Others',
marker_color='gray'
))
fig.update_layout(
title="Market Share Comparison",
xaxis_title="Month",
yaxis_title="Market Share (%)",
barmode='stack',
height=300
)
st.plotly_chart(fig, use_container_width=True)
elif "supply" in chart_name.lower():
# Create sample supply chain visualization
fig = go.Figure()
# Inventory data
months = pd.date_range(start='2023-01-01', periods=12, freq='M')
inventory = [40, 38, 42, 45, 43, 41, 39, 37, 35, 25, 20, 18]
stockouts = [0, 0, 0, 0, 0, 0, 0, 0, 5, 15, 22, 25]
fig.add_trace(go.Scatter(
x=months, y=inventory, mode='lines+markers', name='Inventory Days',
line=dict(color='blue', width=2)
))
fig.add_trace(go.Bar(
x=months, y=stockouts, name='Stockout %',
marker_color='red'
))
fig.update_layout(
title="Supply Chain Metrics",
xaxis_title="Month",
yaxis_title="Inventory Days / Stockout %",
height=300
)
st.plotly_chart(fig, use_container_width=True)
else:
# Create a generic chart
st.image("https://img.icons8.com/fluency/240/000000/graph.png", width=100)
st.markdown(f"*{chart_name}*")
# Display key findings
if hasattr(card, 'key_findings') and card.key_findings:
st.markdown("#### Key Findings")
for i, finding in enumerate(card.key_findings):
expander = st.expander(f"{finding.get('finding', 'Finding')}")
with expander:
st.markdown(f"**Details:** {finding.get('details', '')}")
if 'evidence' in finding:
st.markdown(f"**Evidence:** {finding.get('evidence', '')}")
if 'impact' in finding:
st.markdown(f"**Impact:** {finding.get('impact', '')}")
# Display metrics
if hasattr(card, 'metrics') and card.metrics:
st.markdown("#### Key Metrics")
metric_cols = st.columns(min(len(card.metrics), 4))
for i, (metric_name, metric_value) in enumerate(card.metrics.items()):
with metric_cols[i % len(metric_cols)]:
st.metric(
label=metric_name.replace('_', ' ').title(),
value=metric_value
)
# Display action items
if hasattr(card, 'action_items') and card.action_items:
st.markdown("#### Recommended Actions")
for i, action in enumerate(card.action_items):
priority = action.get('priority', 'Medium')
priority_color = {
'High': 'red',
'Medium': 'orange',
'Low': 'blue'
}.get(priority, 'gray')
st.markdown(f"**{i+1}. {action.get('action', 'Action')}** "
f"<span style='color:{priority_color};'>[{priority}]</span>",
unsafe_allow_html=True)
action_cols = st.columns(3)
with action_cols[0]:
st.markdown(f"**Owner:** {action.get('owner', 'TBD')}")
with action_cols[1]:
st.markdown(f"**Timeline:** {action.get('timeline', 'TBD')}")
with action_cols[2]:
st.markdown(f"**Expected Impact:** {action.get('expected_impact', 'TBD')}")
st.markdown("---")
else:
st.warning("No insight cards were generated. There might have been an error in the analysis.")
# Show detailed workflow state information for debugging
with st.expander("Debug: Workflow State", expanded=True):
# Basic workflow information
st.write("### Basic Workflow Information")
st.write(f"Alert: {workflow_state.get('alert', 'Not available')}")
st.write(f"Status: {workflow_state.get('status', 'Unknown')}")
st.write(f"Plan created: {'Yes' if workflow_state.get('plan') else 'No'}")
# Check data sources
data_sources = workflow_state.get('data_sources', {})
st.write(f"Data sources: {len(data_sources)} found")
if data_sources:
st.write("Data source IDs: " + ", ".join(data_sources.keys()))
# Check analysis results
analysis_results = workflow_state.get('analysis_results', {})
st.write(f"Analysis results: {len(analysis_results)} found")
if analysis_results:
for key, result in analysis_results.items():
st.write(f"- Analysis {key}: {result.name if hasattr(result, 'name') else 'Unnamed'}")
if hasattr(result, 'insights') and result.insights:
st.write(f" Insights: {len(result.insights)}")
if hasattr(result, 'attribution') and result.attribution:
st.write(f" Attribution factors: {len(result.attribution)}")
# Check validation results
validation_results = workflow_state.get('validation_results', {})
st.write(f"Validation results: {len(validation_results)} found")
# Check insight requests
insight_requests = workflow_state.get('insight_requests', [])
st.write(f"Insight requests: {len(insight_requests)} found")
if insight_requests:
for i, req in enumerate(insight_requests):
st.write(f"- Request {i+1}: ID={req.request_id if hasattr(req, 'request_id') else 'Unknown'}")
# Check logs
logs = workflow_state.get('logs', [])
if logs:
st.write("### Workflow Logs")
log_df = pd.DataFrame(logs)
st.dataframe(log_df)
# Show data sources (simplified)
with st.expander("View Data Sources"):
for source_id, source in workflow_state.get("data_sources", {}).items():
st.markdown(f"**{source.name}**")
st.dataframe(source.content.head(5))
# Show code details if enabled
if st.session_state.get("show_code", False):
with st.expander("View Generated Code"):
for analysis_id, analysis in workflow_state.get("analysis_results", {}).items():
st.markdown(f"#### Analysis: {analysis.name}")
st.code(analysis.code, language="python")
# Debug information for insight requests
with st.expander("Debug Insight Requests/Results", expanded=True):
insight_requests = workflow_state.get("insight_requests", [])
insight_cards = workflow_state.get("insight_cards", {})
# Show insight requests
st.write(f"### Insight Requests: {len(insight_requests)}")
for i, request in enumerate(insight_requests):
st.write(f"#### Request {i+1}: {request.request_id if hasattr(request, 'request_id') else 'Unknown'}")
try:
# Try to display request details
if hasattr(request, 'original_problem'):
st.write(f"Problem: {request.original_problem}")
# Show truncated analysis results
if hasattr(request, 'analysis_results'):
st.write("Analysis Results Keys:")
st.json({k: type(v).__name__ for k, v in request.analysis_results.items()})
# Show truncated validation results
if hasattr(request, 'validation_results'):
st.write("Validation Results Keys:")
st.json({k: type(v).__name__ for k, v in request.validation_results.items()})
except Exception as e:
st.error(f"Error displaying request details: {str(e)}")
# Show insight cards
st.write(f"### Insight Cards: {len(insight_cards)}")
for card_id, card in insight_cards.items():
st.write(f"Card ID: {card_id}")
try:
st.json({
"title": card.title if hasattr(card, 'title') else "N/A",
"description": card.description[:100] + "..." if hasattr(card, 'description') else "N/A",
"key_findings": f"{len(card.key_findings)} findings" if hasattr(card, 'key_findings') else "N/A",
"charts": card.charts if hasattr(card, 'charts') else "N/A",
})
except Exception as e:
st.error(f"Error displaying card details: {str(e)}")
def initialize_session():
"""Initialize session state variables if they don't exist"""
if "active_page" not in st.session_state:
st.session_state.active_page = "main"
if "workflow_state" not in st.session_state:
st.session_state.workflow_state = None
if "workflow_thread" not in st.session_state:
st.session_state.workflow_thread = None
if "status_queue" not in st.session_state:
st.session_state.status_queue = queue.Queue()
if "logs" not in st.session_state:
st.session_state.logs = []
if "current_step" not in st.session_state:
st.session_state.current_step = None
if "alert_submitted" not in st.session_state:
st.session_state.alert_submitted = False
if "show_sql" not in st.session_state:
st.session_state.show_sql = False
if "show_code" not in st.session_state:
st.session_state.show_code = False
if "alert" not in st.session_state:
st.session_state.alert = ""
if "error_details" not in st.session_state:
st.session_state.error_details = []