""" CXInsights Dashboard - Export Functions Export insights to Excel, PDF, and other formats. """ import io import json from datetime import datetime from pathlib import Path import pandas as pd import streamlit as st from config import COLORS def create_excel_export(summary: dict, analyses: list[dict], batch_id: str) -> io.BytesIO: """ Create comprehensive Excel export with multiple sheets. Sheets: - Executive Summary - Call Details - Poor CX Drivers - FCR Analysis - Churn Risk - Agent Performance """ output = io.BytesIO() with pd.ExcelWriter(output, engine='openpyxl') as writer: # Sheet 1: Executive Summary summary_data = { "Metric": [ "Batch ID", "Generated At", "Total Calls Analyzed", "Successful Analyses", "Failed Analyses", "Poor CX Drivers Found", "Lost Sales Drivers Found", ], "Value": [ batch_id, summary.get("generated_at", "N/A"), summary.get("summary", {}).get("total_calls", 0), summary.get("summary", {}).get("successful_analyses", 0), summary.get("summary", {}).get("failed_analyses", 0), summary.get("poor_cx", {}).get("total_drivers_found", 0), summary.get("lost_sales", {}).get("total_drivers_found", 0), ] } df_summary = pd.DataFrame(summary_data) df_summary.to_excel(writer, sheet_name="Executive Summary", index=False) # Sheet 2: Outcomes Distribution outcomes = summary.get("outcomes", {}) if outcomes: df_outcomes = pd.DataFrame([ {"Outcome": k, "Count": v, "Percentage": f"{v/sum(outcomes.values())*100:.1f}%"} for k, v in sorted(outcomes.items(), key=lambda x: -x[1]) ]) df_outcomes.to_excel(writer, sheet_name="Outcomes", index=False) # Sheet 3: Call Details call_data = [] for a in analyses: call_data.append({ "Call ID": a.get("call_id", ""), "Outcome": a.get("outcome", ""), "FCR Status": a.get("fcr_status", ""), "Churn Risk": a.get("churn_risk", ""), "Agent Classification": a.get("agent_classification", ""), "Poor CX Drivers": len(a.get("poor_cx_drivers", [])), "FCR Failure Drivers": len(a.get("fcr_failure_drivers", [])), "Churn Risk Drivers": len(a.get("churn_risk_drivers", [])), "Duration (sec)": a.get("observed", {}).get("audio_duration_sec", ""), "Total Turns": a.get("observed", {}).get("turn_metrics", {}).get("total_turns", ""), }) df_calls = pd.DataFrame(call_data) df_calls.to_excel(writer, sheet_name="Call Details", index=False) # Sheet 4: Poor CX Drivers Detail poor_cx_data = [] for a in analyses: for d in a.get("poor_cx_drivers", []): poor_cx_data.append({ "Call ID": a.get("call_id", ""), "Driver Code": d.get("driver_code", ""), "Confidence": f"{d.get('confidence', 0):.0%}", "Origin": d.get("origin", ""), "Reasoning": d.get("reasoning", ""), "Corrective Action": d.get("corrective_action", ""), "Evidence": "; ".join([e.get("text", "") for e in d.get("evidence_spans", [])]), }) if poor_cx_data: df_poor_cx = pd.DataFrame(poor_cx_data) df_poor_cx.to_excel(writer, sheet_name="Poor CX Drivers", index=False) # Sheet 5: FCR Failure Drivers fcr_data = [] for a in analyses: for d in a.get("fcr_failure_drivers", []): fcr_data.append({ "Call ID": a.get("call_id", ""), "Driver Code": d.get("driver_code", ""), "Confidence": f"{d.get('confidence', 0):.0%}", "Origin": d.get("origin", ""), "Reasoning": d.get("reasoning", ""), "Corrective Action": d.get("corrective_action", ""), }) if fcr_data: df_fcr = pd.DataFrame(fcr_data) df_fcr.to_excel(writer, sheet_name="FCR Failures", index=False) # Sheet 6: Churn Risk Drivers churn_data = [] for a in analyses: for d in a.get("churn_risk_drivers", []): churn_data.append({ "Call ID": a.get("call_id", ""), "Risk Level": a.get("churn_risk", ""), "Driver Code": d.get("driver_code", ""), "Confidence": f"{d.get('confidence', 0):.0%}", "Reasoning": d.get("reasoning", ""), "Corrective Action": d.get("corrective_action", ""), }) if churn_data: df_churn = pd.DataFrame(churn_data) df_churn.to_excel(writer, sheet_name="Churn Risk", index=False) # Sheet 7: Agent Performance agent_data = [] for a in analyses: positive = [s.get("skill_code", "") for s in a.get("agent_positive_skills", [])] improvement = [s.get("skill_code", "") for s in a.get("agent_improvement_areas", [])] agent_data.append({ "Call ID": a.get("call_id", ""), "Classification": a.get("agent_classification", ""), "Positive Skills": ", ".join(positive), "Improvement Areas": ", ".join(improvement), }) df_agent = pd.DataFrame(agent_data) df_agent.to_excel(writer, sheet_name="Agent Performance", index=False) # Sheet 8: Top Drivers Summary top_drivers = [] for d in summary.get("poor_cx", {}).get("top_drivers", []): top_drivers.append({ "Type": "Poor CX", "Driver Code": d.get("driver_code", ""), "Occurrences": d.get("occurrences", 0), "Call Rate": f"{d.get('call_rate', 0)*100:.1f}%", "Avg Confidence": f"{d.get('avg_confidence', 0):.0%}", }) for d in summary.get("lost_sales", {}).get("top_drivers", []): top_drivers.append({ "Type": "Lost Sales", "Driver Code": d.get("driver_code", ""), "Occurrences": d.get("occurrences", 0), "Call Rate": f"{d.get('call_rate', 0)*100:.1f}%", "Avg Confidence": f"{d.get('avg_confidence', 0):.0%}", }) if top_drivers: df_top = pd.DataFrame(top_drivers) df_top.to_excel(writer, sheet_name="Top Drivers Summary", index=False) output.seek(0) return output def create_executive_summary_html(summary: dict, analyses: list[dict], batch_id: str) -> str: """ Create HTML executive summary report for PDF export. """ total_calls = summary.get("summary", {}).get("total_calls", 0) # Calculate metrics poor_cx_calls = sum(1 for a in analyses if len(a.get("poor_cx_drivers", [])) > 0) poor_cx_rate = (poor_cx_calls / total_calls * 100) if total_calls > 0 else 0 high_churn = sum(1 for a in analyses if a.get("churn_risk") in ["HIGH", "AT_RISK"]) churn_rate = (high_churn / total_calls * 100) if total_calls > 0 else 0 # FCR rate - Per blueprint: Primera Llamada = FCR success fcr_success = sum(1 for a in analyses if a.get("fcr_status") == "FIRST_CALL") fcr_rate = (fcr_success / total_calls * 100) if total_calls > 0 else 0 # Top drivers top_drivers = summary.get("poor_cx", {}).get("top_drivers", [])[:5] # Outcomes outcomes = summary.get("outcomes", {}) html = f"""
No critical drivers detected.
'}| Outcome | Count | Percentage |
|---|---|---|
| {k} | {v} | {v/sum(outcomes.values())*100:.1f}% |
| No data | ||
| Driver | Occurrences | Call Rate | Confidence |
|---|---|---|---|
| {d.get("driver_code", "")} | {d.get("occurrences", 0)} | {d.get("call_rate", 0)*100:.1f}% | {d.get("avg_confidence", 0):.0%} |
| No drivers detected | |||