{ "cells": [ { "cell_type": "markdown", "id": "3da9de99", "metadata": {}, "source": [ "# 01 · Business Case — Genesys CX Cloud TEI\n", "\n", "Working view of the live Athena tool, plus the **Genesys AI Experience token**\n", "cost line the published study omits. Run `00_provision.ipynb` first.\n", "\n", "The published study models \\$0 AI consumption while three of its four benefits\n", "(self-service uplift, agent efficiency, agent-assist sales) depend on AI\n", "capabilities that Genesys bills via AI Experience tokens. Token pricing is\n", "tiered and deal-specific, so the model keeps it simple — **one annual cost\n", "value, entered from the Genesys quote**, exactly as Athena stores it. Quote\n", "details (volume, unit price, tier) go in the field notes for the audit trail." ] }, { "cell_type": "code", "execution_count": null, "id": "89deae70", "metadata": {}, "outputs": [], "source": [ "import sys, pathlib # path shim: works on a fresh kernel\n", "for _p in [pathlib.Path.cwd(), *pathlib.Path.cwd().parents]:\n", " if (_p / \"pyproject.toml\").exists():\n", " sys.path.insert(0, str(_p)); break\n", "\n", "import pandas as pd\n", "from core.bootstrap import init\n", "from core.notebook_helpers import charts\n", "\n", "pal = init(study=\"202512_GenesysCX\")\n", "client, seed, config = pal.client, pal.seed_data, pal.config\n", "\n", "TOOL_ID = config.TOOL_PUBLIC_ID\n", "assert TOOL_ID, \"No PALLADIUM_GENESYSCX_TOOL_PUBLIC_ID in .env — run 00_provision.ipynb first.\"\n", "tool = client.get_tool(TOOL_ID)\n", "print(f\"Tool: {tool.get('name')} ({TOOL_ID}) status={tool.get('status')}\")" ] }, { "cell_type": "markdown", "id": "09afaf70", "metadata": {}, "source": [ "## Current financial summary" ] }, { "cell_type": "code", "execution_count": null, "id": "3d80c19a", "metadata": {}, "outputs": [], "source": [ "summary = client.calculate(TOOL_ID)\n", "client.print_summary(TOOL_ID)" ] }, { "cell_type": "code", "execution_count": null, "id": "392df0ba", "metadata": {}, "outputs": [], "source": [ "values = client.get_values(TOOL_ID)\n", "benefit_rows = [v for v in values if v.get(\"table\") == \"benefits\"]\n", "cost_rows = [v for v in values if v.get(\"table\") == \"costs\"]\n", "\n", "def value_table(rows, *, initial=False):\n", " out = []\n", " for v in rows:\n", " yv = v.get(\"year_values\") or {}\n", " rec = {\"field\": v.get(\"label\") or v[\"field_key\"]}\n", " if initial:\n", " rec[\"Initial\"] = v.get(\"initial\", 0.0)\n", " rec.update({f\"Year {y}\": yv.get(str(y), 0.0) for y in (1, 2, 3)})\n", " rec[\"risk_adj\"] = v.get(\"risk_adjustment\")\n", " out.append(rec)\n", " return pd.DataFrame(out)\n", "\n", "print(\"Benefits (nominal; Athena risk-adjusts at calculate time):\")\n", "display(value_table(benefit_rows))\n", "print(\"Costs (stored pre-multiplied by 1 + risk_adj):\")\n", "display(value_table(cost_rows, initial=True))" ] }, { "cell_type": "markdown", "id": "2383f761", "metadata": {}, "source": [ "## Financial visualizations\n", "\n", "All figures are risk-adjusted and built from the live Athena values, using\n", "the shared `core.notebook_helpers.charts` helpers (same ones the Streamlit\n", "app uses)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# ── Visual theme — plain values, edit freely (not confidential) ──\n", "THEME = {\n", " \"heading_font\": \"Helvetica Neue, Arial, sans-serif\", # chart titles\n", " \"body_font\": \"Helvetica, Arial, sans-serif\", # axes, legends, labels\n", " \"font_color\": \"#1F2937\", # hex\n", "\n", " # Circle-chart slice colours, applied in order a..j\n", " \"pie_colors\": {\n", " \"a\": \"#1565C0\",\n", " \"b\": \"#2E7D32\",\n", " \"c\": \"#C62828\",\n", " \"d\": \"#F9A825\",\n", " \"e\": \"#6A1B9A\",\n", " \"f\": \"#00838F\",\n", " \"g\": \"#EF6C00\",\n", " \"h\": \"#5D4037\",\n", " \"i\": \"#37474F\",\n", " \"j\": \"#AD1457\",\n", " },\n", "\n", " \"bar_green\": \"#2E7D32\", # benefits bars\n", " \"bar_red\": \"#C62828\", # costs bars\n", "}\n", "\n", "charts.apply_theme(**THEME)\n", "print(\"Theme applied — re-run the chart cells below to restyle.\")" ] }, { "cell_type": "code", "execution_count": null, "id": "14d5942a", "metadata": {}, "outputs": [], "source": [ "# Cost breakdown — share of total three-year cost per line item\n", "charts.cost_breakdown_pie(\n", " cost_rows, title=\"Cost Breakdown — share of 3-year total (risk-adjusted)\"\n", ").show()" ] }, { "cell_type": "code", "execution_count": null, "id": "d13f342e", "metadata": {}, "outputs": [], "source": [ "# Benefits — three-year risk-adjusted total per category\n", "charts.benefits_bar(\n", " benefit_rows, title=\"Benefits (Three-Year, Risk-Adjusted)\"\n", ").show()" ] }, { "cell_type": "code", "execution_count": null, "id": "9ef6caee", "metadata": {}, "outputs": [], "source": [ "# Benefits vs costs, year by year (Initial = one-time Year-0 costs)\n", "charts.benefits_vs_costs_by_year(benefit_rows, cost_rows).show()" ] }, { "cell_type": "code", "execution_count": null, "id": "6f069df6", "metadata": {}, "outputs": [], "source": [ "# Cash flow with cumulative net benefits — the Forrester-style exhibit\n", "def _yearly_breakdown(benefit_items, cost_items):\n", " \"\"\"Risk-adjusted yearly rows + initial, computed from the live values.\"\"\"\n", " initial = sum(float(c.get(\"initial\") or 0) for c in cost_items)\n", " rows, cumulative = [], -initial\n", " for y in (1, 2, 3):\n", " b = sum(float((v.get(\"year_values\") or {}).get(str(y), 0) or 0)\n", " * (1 - float(v.get(\"risk_adjustment\") or 0))\n", " for v in benefit_items)\n", " c = sum(float((v.get(\"year_values\") or {}).get(str(y), 0) or 0)\n", " for v in cost_items)\n", " cumulative += b - c\n", " rows.append({\"year\": y, \"benefits\": b, \"costs\": c,\n", " \"net\": b - c, \"cumulative_net\": cumulative})\n", " return rows, initial\n", "\n", "yb, initial_cost = _yearly_breakdown(benefit_rows, cost_rows)\n", "charts.cashflow_chart(yb, initial_cost=initial_cost).show()\n", "pd.DataFrame(yb)" ] }, { "cell_type": "code", "execution_count": null, "id": "b1ff0315", "metadata": {}, "outputs": [], "source": [ "# Waterfall — Benefits PV down to NPV (from the Athena summary)\n", "charts.waterfall([\n", " (\"Benefits PV\", float(summary[\"total_benefits_pv\"])),\n", " (\"Costs PV\", -float(summary[\"total_costs_pv\"])),\n", " (\"NPV\", float(summary[\"net_present_value\"])),\n", "], title=\"Benefits PV → Costs PV → NPV\").show()" ] }, { "cell_type": "markdown", "id": "c78f77a9", "metadata": {}, "source": [ "## Genesys AI Experience tokens — annual cost\n", "\n", "Enter the negotiated annual token cost from the Genesys quote. For sizing\n", "context, the study's own drivers imply roughly **1,040,000** self-service\n", "interactions/yr and **3,120,000** agent-assisted interactions/yr would draw\n", "tokens — bring the actual figure from the quote, not a derivation." ] }, { "cell_type": "code", "execution_count": null, "id": "99b9c665", "metadata": {}, "outputs": [], "source": [ "# ── Deal inputs ──\n", "AI_TOKEN_ANNUAL_COST = 0.0 # $/yr from the Genesys quote — 0 reproduces the published study\n", "AI_TOKEN_QUOTE_NOTE = \"\" # e.g. \"Quote #1234: 4.2M tokens/yr @ $0.05, tier 2 commit\"\n", "\n", "print(f\"AI token line: ${AI_TOKEN_ANNUAL_COST:,.0f}/yr\")" ] }, { "cell_type": "markdown", "id": "b7c6c4c7", "metadata": {}, "source": [ "### Sensitivity — what the AI line does to NPV and ROI\n", "\n", "Computed locally from the current Athena summary: an annual cost `Δ` raises\n", "costs PV by `Δ × 2.4869` (the 3-year, 10% annuity factor) and lowers NPV by\n", "the same amount." ] }, { "cell_type": "code", "execution_count": null, "id": "09ceeea2", "metadata": {}, "outputs": [], "source": [ "ANNUITY = sum(1 / 1.10**n for n in (1, 2, 3)) # 2.4869\n", "\n", "base_benefits_pv = float(summary[\"total_benefits_pv\"])\n", "base_costs_pv = float(summary[\"total_costs_pv\"])\n", "\n", "# Remove any token cost already stored, to get a clean zero-token base.\n", "current_tokens = next(\n", " (v for v in values if v[\"field_key\"] == \"genesys_ai_tokens\"), {})\n", "current_annual = (current_tokens.get(\"year_values\") or {}).get(\"1\", 0.0)\n", "base_costs_pv -= current_annual * ANNUITY\n", "\n", "sweep = [0, 100_000, 250_000, 500_000, 750_000, 1_000_000]\n", "if AI_TOKEN_ANNUAL_COST and AI_TOKEN_ANNUAL_COST not in sweep:\n", " sweep = sorted(sweep + [AI_TOKEN_ANNUAL_COST])\n", "\n", "rows = []\n", "for ai_annual in sweep:\n", " costs_pv = base_costs_pv + ai_annual * ANNUITY\n", " npv = base_benefits_pv - costs_pv\n", " rows.append({\n", " \"AI cost/yr\": f\"${ai_annual:,.0f}\" + (\" ← your input\" if ai_annual == AI_TOKEN_ANNUAL_COST and ai_annual else \"\"),\n", " \"Costs PV\": f\"${costs_pv:,.0f}\",\n", " \"NPV\": f\"${npv:,.0f}\",\n", " \"ROI\": f\"{npv / costs_pv * 100:,.0f}%\",\n", " })\n", "\n", "display(pd.DataFrame(rows))" ] }, { "cell_type": "markdown", "id": "6516270c", "metadata": {}, "source": [ "## Push the AI token cost to Athena\n", "\n", "Writes the annual cost into `genesys_ai_tokens` (quote details in the notes),\n", "recalculates server-side, and saves a version." ] }, { "cell_type": "code", "execution_count": null, "id": "c6caacea", "metadata": {}, "outputs": [], "source": [ "PUSH = False # ← set True once AI_TOKEN_ANNUAL_COST is final\n", "\n", "if PUSH:\n", " note = (\n", " f\"AI Experience tokens: ${AI_TOKEN_ANNUAL_COST:,.0f}/yr. \"\n", " + (f\"{AI_TOKEN_QUOTE_NOTE} \" if AI_TOKEN_QUOTE_NOTE else \"\")\n", " + \"Line absent from the published Forrester study.\"\n", " )\n", " client.update_values(TOOL_ID, [{\n", " \"field_key\": \"genesys_ai_tokens\",\n", " \"year_values\": {\"1\": round(AI_TOKEN_ANNUAL_COST, 2),\n", " \"2\": round(AI_TOKEN_ANNUAL_COST, 2),\n", " \"3\": round(AI_TOKEN_ANNUAL_COST, 2)},\n", " \"notes\": note,\n", " }])\n", " summary = client.calculate(TOOL_ID)\n", " client.print_summary(TOOL_ID)\n", " client.save_version(TOOL_ID, note=f\"AI token cost set: {note}\")\n", " print(\"✅ Pushed, recalculated, and versioned. Re-run the visualization \"\n", " \"cells above to refresh the charts.\")\n", "else:\n", " print(\"Dry run — set PUSH = True to write to Athena.\")" ] }, { "cell_type": "markdown", "id": "c261ad48", "metadata": {}, "source": [ "## Next steps\n", "\n", "- Adjust other drivers for the client (interaction volume, agent count,\n", " self-service delta) via `client.update_values` or the Streamlit app\n", " (`make app`), saving a version per scenario.\n", "- Export charts for a deck: any figure object supports\n", " `fig.write_image(\"chart.png\")` (needs `pip install kaleido`) or\n", " `fig.write_html(\"chart.html\")`.\n", "- Export for the report pipeline:\n", " `python -m palladium export $PALLADIUM_GENESYSCX_TOOL_PUBLIC_ID -o exports/export.json`" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.7" } }, "nbformat": 4, "nbformat_minor": 5 }