Token Calculator

This commit is contained in:
2026-06-10 14:28:16 -04:00
parent 64fb83257d
commit 71b98ee4e4
20 changed files with 9719 additions and 916 deletions

View File

@@ -32,7 +32,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
"✅ Athena connected — https://athena.ouranos.helu.ca (1 report templates visible)\n",
"✅ Athena connected — https://athena.ouranos.helu.ca (2 report templates visible)\n",
"📁 Study: 202512_GenesysCX\n"
]
}
@@ -69,7 +69,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
"Created report template UCb2hSJprSBx\n"
"Found existing report template UCb2hSJprSBx (status: active)\n"
]
}
],
@@ -114,7 +114,7 @@
"`(1 + risk_adj)`; Year-0 amounts use companion `*_initial` fields.\n",
"The `genesys_ai_tokens` line is seeded \\$0 (reproduces the published study) —\n",
"the annual cost gets entered per deal, from the Genesys quote, in\n",
"`01_business_case.ipynb`."
"`03_business_case.ipynb`."
]
},
{
@@ -127,8 +127,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
"12 fields created, 0 already existed.\n",
"Report template activated.\n"
"0 fields created, 12 already existed.\n"
]
}
],
@@ -305,7 +304,7 @@
},
{
"cell_type": "code",
"execution_count": 6,
"execution_count": 5,
"id": "1e375b54",
"metadata": {},
"outputs": [
@@ -445,7 +444,7 @@
},
{
"cell_type": "code",
"execution_count": 7,
"execution_count": 6,
"id": "584e01dd",
"metadata": {},
"outputs": [
@@ -531,7 +530,7 @@
},
{
"cell_type": "code",
"execution_count": 8,
"execution_count": 7,
"id": "e04b1676",
"metadata": {},
"outputs": [
@@ -539,7 +538,6 @@
"name": "stdout",
"output_type": "stream",
"text": [
"Auto-selected proposal 1: Secure Cloud Infrastructure Modernization\n",
"Attaching via: {'proposal': 1}\n"
]
}
@@ -589,7 +587,7 @@
},
{
"cell_type": "code",
"execution_count": 9,
"execution_count": 8,
"id": "0655d1fc",
"metadata": {},
"outputs": [
@@ -597,7 +595,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
"Created tool 3rzDgVdsjhVv attached to {'proposal': 1}\n"
"Found existing tool 3rzDgVdsjhVv (status: draft)\n"
]
}
],
@@ -643,7 +641,7 @@
},
{
"cell_type": "code",
"execution_count": 10,
"execution_count": 9,
"id": "86443d76",
"metadata": {},
"outputs": [
@@ -696,7 +694,7 @@
},
{
"cell_type": "code",
"execution_count": 11,
"execution_count": 10,
"id": "0728b42e",
"metadata": {},
"outputs": [
@@ -724,7 +722,7 @@
},
{
"cell_type": "code",
"execution_count": 12,
"execution_count": 11,
"id": "aba8fc21",
"metadata": {},
"outputs": [
@@ -853,7 +851,7 @@
},
{
"cell_type": "code",
"execution_count": 13,
"execution_count": 12,
"id": "d8102590",
"metadata": {},
"outputs": [
@@ -861,13 +859,12 @@
"name": "stdout",
"output_type": "stream",
"text": [
"Saved version 1 (baseline).\n",
"Saved to /Users/robert/git/palladium/.env:\n",
" PALLADIUM_GENESYSCX_REPORT_PUBLIC_ID=UCb2hSJprSBx\n",
" PALLADIUM_GENESYSCX_TOOL_PUBLIC_ID=3rzDgVdsjhVv\n",
" PALLADIUM_GENESYSCX_PROPOSAL_ID=1\n",
"\n",
"Next → 01_business_case.ipynb (AI token cost entry + sensitivity).\n"
"Next → 01_benefits.ipynb (walk through the four Forrester benefits).\n"
]
}
],
@@ -876,7 +873,7 @@
" client.save_version(TOOL_ID, note=(\n",
" \"Baseline — published Forrester CX Cloud TEI figures (Dec 2025). \"\n",
" \"genesys_ai_tokens at $0 per the published study; set the annual \"\n",
" \"cost from the Genesys quote in 01_business_case before client use.\"\n",
" \"cost from the Genesys quote in 03_business_case before client use.\"\n",
" ))\n",
" print(\"Saved version 1 (baseline).\")\n",
"\n",
@@ -893,7 +890,7 @@
"print(f\"Saved to {env_path}:\")\n",
"for k, v in ids.items():\n",
" print(f\" {k}={v}\")\n",
"print(\"\\nNext → 01_business_case.ipynb (AI token cost entry + sensitivity).\")"
"print(\"\\nNext → 01_benefits.ipynb (walk through the four Forrester benefits).\")"
]
},
{
@@ -903,6 +900,14 @@
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "13acdc34-71f6-4220-8675-4e1527cb8e39",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {

File diff suppressed because one or more lines are too long

View File

@@ -1,376 +0,0 @@
{
"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
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,382 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "g3-md-intro",
"metadata": {},
"source": [
"# 03 \u2014 Business Case\n",
"\n",
"Combine the benefits and costs into the consolidated TEI summary,\n",
"render the cash-flow exhibit, run scenario analysis, **and price the\n",
"Genesys AI Experience tokens line that the published study omits**.\n",
"This notebook should reproduce the headline numbers from the PDF\n",
"Financial Summary:\n",
"\n",
"* **NPV \\$10.78M \u2022 ROI 266% \u2022 Payback \u2248 4 months**\n",
"\n",
"It then exposes a sensitivity sweep for the AI-tokens annual cost so\n",
"you can see exactly what an honest deal looks like before sending it\n",
"to a client."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "03-bootstrap",
"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",
"from core.bootstrap import init\n",
"\n",
"pal = init(study=\"202512_GenesysCX\")\n",
"client, seed, config = pal.client, pal.seed_data, pal.config\n",
"\n",
"STUDY = pal.root / 'studies' / '202512_GenesysCX'\n",
"ROOT = pal.root\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "g3-code-imports",
"metadata": {},
"outputs": [],
"source": [
"from core.export.report_data import _compute_summary\n",
"from core.notebook_helpers import charts, display, tables"
]
},
{
"cell_type": "markdown",
"id": "g3-md-summary",
"metadata": {},
"source": [
"## Local summary (no Athena round-trip)\n",
"\n",
"Compute the moderate-case TEI summary directly from `seed_data` so the\n",
"notebook produces results even before the Athena tool is provisioned.\n",
"Headline numbers should match the published study."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "g3-code-summary",
"metadata": {},
"outputs": [],
"source": [
"summary = _compute_summary(\n",
" seed.BENEFITS,\n",
" seed.COSTS,\n",
" config.DISCOUNT_RATE,\n",
" config.ANALYSIS_YEARS,\n",
")\n",
"# `_compute_summary` returns roi_pct; expose it as `roi` for kpi_cards.\n",
"summary['roi'] = summary.get('roi_pct')\n",
"display.kpi_cards(summary, title='Forrester composite \u2014 moderate case')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "g3-code-cashflow-table",
"metadata": {},
"outputs": [],
"source": [
"df_cash = tables.cashflow_table(summary)\n",
"df_cash.style.format({c: '${:,.0f}' for c in df_cash.columns if c != 'Year'})"
]
},
{
"cell_type": "markdown",
"id": "g3-md-cashflow",
"metadata": {},
"source": [
"## Cash flow chart\n",
"\n",
"Mirrors the Forrester *Cash Flow Chart* exhibit: stacked benefits/costs\n",
"by year + cumulative-net line. Payback hits inside Year 1."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "g3-code-cashflow-chart",
"metadata": {},
"outputs": [],
"source": [
"charts.cashflow_chart(\n",
" summary['yearly_breakdown'],\n",
" initial_cost=summary.get('initial_costs', 0),\n",
").show()"
]
},
{
"cell_type": "markdown",
"id": "g3-md-waterfall",
"metadata": {},
"source": [
"## Waterfall: Benefits PV \u2192 Costs PV \u2192 NPV"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "g3-code-waterfall",
"metadata": {},
"outputs": [],
"source": [
"charts.waterfall([\n",
" ('Benefits PV', summary['total_benefits_pv']),\n",
" ('Costs PV', -summary['total_costs_pv']),\n",
" ('NPV', summary['npv']),\n",
"]).show()"
]
},
{
"cell_type": "markdown",
"id": "g3-md-scenarios",
"metadata": {},
"source": [
"## Scenario analysis\n",
"\n",
"Apply the default Palladium multipliers (see `core.calculations.SCENARIOS`):\n",
"\n",
"* **Conservative** \u2014 lower adoption, higher risk on benefits / lower on costs\n",
"* **Moderate** \u2014 base case (= the published Forrester study)\n",
"* **Aggressive** \u2014 full adoption, lower risk on benefits / higher on costs"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "g3-code-scenarios",
"metadata": {},
"outputs": [],
"source": [
"from core.calculations import apply_scenario\n",
"import pandas as pd\n",
"\n",
"scenario_summaries = {}\n",
"for name in ('conservative', 'moderate', 'aggressive'):\n",
" sb = apply_scenario(seed.BENEFITS, name, table='benefits')\n",
" sc = apply_scenario(seed.COSTS, name, table='costs')\n",
" scenario_summaries[name] = _compute_summary(sb, sc, config.DISCOUNT_RATE, config.ANALYSIS_YEARS)\n",
"\n",
"scen_df = pd.DataFrame([\n",
" {\n",
" 'Scenario': k,\n",
" 'Benefits PV': v['total_benefits_pv'],\n",
" 'Costs PV': v['total_costs_pv'],\n",
" 'NPV': v['npv'],\n",
" 'ROI %': v['roi_pct'],\n",
" 'Payback (mo)': round(v['payback_months'], 1) if v['payback_months'] is not None else None,\n",
" }\n",
" for k, v in scenario_summaries.items()\n",
"])\n",
"scen_df.style.format({\n",
" 'Benefits PV': '${:,.0f}', 'Costs PV': '${:,.0f}', 'NPV': '${:,.0f}', 'ROI %': '{:,.0f}%'\n",
"})"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "g3-code-scenario-chart",
"metadata": {},
"outputs": [],
"source": [
"charts.scenario_comparison(scenario_summaries).show()"
]
},
{
"cell_type": "markdown",
"id": "g3-md-tokens-intro",
"metadata": {},
"source": [
"## Genesys AI Experience tokens \u2014 annual cost\n",
"\n",
"Token pricing is tiered, capability-dependent, and deal-specific \u2014\n",
"Athena stores a single annual cost value per line, and so does the\n",
"seed. Enter the negotiated annual cost from the Genesys quote here.\n",
"Quote details (volume, unit price, tier) go into the field notes for\n",
"the audit trail.\n",
"\n",
"For sizing context, the study's own drivers imply roughly **1,040,000**\n",
"self-service interactions/yr and **3,120,000** agent-assisted\n",
"interactions/yr would draw tokens \u2014 bring the actual figure from the\n",
"quote, not a derivation."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "g3-code-token-input",
"metadata": {},
"outputs": [],
"source": [
"# \u2500\u2500 Deal inputs \u2500\u2500\n",
"AI_TOKEN_ANNUAL_COST = 0.0 # $/yr from the Genesys quote \u2014 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": "g3-md-sensitivity",
"metadata": {},
"source": [
"### Sensitivity \u2014 what the AI line does to NPV and ROI\n",
"\n",
"An annual cost `\u0394` raises Costs PV by `\u0394 \u00d7 2.4869` (the 3-year, 10%\n",
"annuity factor) and lowers NPV by the same amount. The sweep below\n",
"shows where the deal stops being attractive \u2014 and quantifies how much\n",
"of the published 266% ROI was *contingent on Forrester modelling \\$0\n",
"of token spend*."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "g3-code-sensitivity",
"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",
"sweep = [0, 100_000, 250_000, 500_000, 750_000, 1_000_000, 1_500_000, 2_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_v = base_benefits_pv - costs_pv\n",
" roi_pct = (npv_v / costs_pv * 100) if costs_pv else 0\n",
" rows.append({\n",
" 'AI cost/yr': f\"${ai_annual:,.0f}\" + (' \u2190 your input' if ai_annual == AI_TOKEN_ANNUAL_COST and ai_annual else ''),\n",
" 'Costs PV': f'${costs_pv:,.0f}',\n",
" 'NPV': f'${npv_v:,.0f}',\n",
" 'ROI': f'{roi_pct:,.0f}%',\n",
" })\n",
"\n",
"pd.DataFrame(rows)"
]
},
{
"cell_type": "markdown",
"id": "g3-md-tokens-push",
"metadata": {},
"source": [
"### Push the AI-tokens cost to Athena\n",
"\n",
"When `AI_TOKEN_ANNUAL_COST` is set and `TOOL_PUBLIC_ID` exists, write\n",
"the annual cost into the `genesys_ai_tokens` field, with the quote\n",
"details preserved in the field notes."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "g3-code-tokens-push",
"metadata": {},
"outputs": [],
"source": [
"PUSH = False # \u2190 set True once AI_TOKEN_ANNUAL_COST is final\n",
"\n",
"if PUSH and config.TOOL_PUBLIC_ID:\n",
" from core.tei_client import TEIClient\n",
"\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 = TEIClient()\n",
" client.update_values(config.TOOL_PUBLIC_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",
" client.calculate(config.TOOL_PUBLIC_ID)\n",
" client.print_summary(config.TOOL_PUBLIC_ID)\n",
" client.save_version(config.TOOL_PUBLIC_ID, note=f'AI token cost set: {note}')\n",
" display.alert('Pushed, recalculated, and versioned.', 'success')\n",
"else:\n",
" display.alert('Dry run \u2014 set <code>PUSH = True</code> and ensure '\n",
" '<code>TOOL_PUBLIC_ID</code> is configured to write to Athena.', 'info')"
]
},
{
"cell_type": "markdown",
"id": "g3-md-crosscheck",
"metadata": {},
"source": [
"## Cross-check vs Athena (optional)\n",
"\n",
"When `TOOL_PUBLIC_ID` is set, ask Athena to recalculate the summary on\n",
"the server side and confirm it matches our local computation (modulo\n",
"the documented Year-0 discounting delta \u2014 see `02_costs.ipynb`)."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "g3-code-crosscheck",
"metadata": {},
"outputs": [],
"source": [
"if config.TOOL_PUBLIC_ID:\n",
" from core.tei_client import TEIClient\n",
"\n",
" client = TEIClient()\n",
" client.calculate(config.TOOL_PUBLIC_ID)\n",
" server_summary = client.get_summary(config.TOOL_PUBLIC_ID)\n",
" display.kpi_cards(server_summary, title='Athena server-side summary')\n",
"else:\n",
" display.alert('Set TOOL_PUBLIC_ID to compare Athena vs local.', 'info')"
]
},
{
"cell_type": "markdown",
"id": "g3-md-next",
"metadata": {},
"source": [
"Continue with [`04_export.ipynb`](04_export.ipynb) \u2192"
]
}
],
"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
}

View File

@@ -0,0 +1,195 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "g4-md-intro",
"metadata": {},
"source": [
"# 04 \u2014 Export for the report pipeline\n",
"\n",
"Build the structured JSON envelope consumed by the html2docx report\n",
"generation pipeline (Peitho). Output goes to `exports/export.json`."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "04-bootstrap",
"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",
"from core.bootstrap import init\n",
"\n",
"pal = init(study=\"202512_GenesysCX\")\n",
"client, seed, config = pal.client, pal.seed_data, pal.config\n",
"\n",
"STUDY = pal.root / 'studies' / '202512_GenesysCX'\n",
"ROOT = pal.root\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "g4-code-imports",
"metadata": {},
"outputs": [],
"source": [
"import json\n",
"from datetime import datetime, timezone\n",
"from core import __version__\n",
"from core.calculations import apply_scenario\n",
"from core.export.report_data import _compute_summary\n",
"from core.notebook_helpers import display"
]
},
{
"cell_type": "markdown",
"id": "g4-md-build",
"metadata": {},
"source": [
"## Build the envelope\n",
"\n",
"Two paths:\n",
"\n",
"* **Live** \u2014 `core.export.build_report_data(client, public_id)` pulls\n",
" authoritative values + summary from Athena and stamps it.\n",
"* **Local** \u2014 when no `TOOL_PUBLIC_ID` is configured, build the envelope\n",
" directly from `seed_data` so this notebook is always runnable."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "g4-code-build",
"metadata": {},
"outputs": [],
"source": [
"if config.TOOL_PUBLIC_ID:\n",
" from core.export import build_report_data\n",
" from core.tei_client import TEIClient\n",
"\n",
" client = TEIClient()\n",
" envelope = build_report_data(\n",
" client,\n",
" config.TOOL_PUBLIC_ID,\n",
" include_scenarios=True,\n",
" study_slug=config.STUDY_SLUG,\n",
" )\n",
" source = 'live (Athena)'\n",
"else:\n",
" summary = _compute_summary(\n",
" seed.BENEFITS, seed.COSTS, config.DISCOUNT_RATE, config.ANALYSIS_YEARS\n",
" )\n",
" summary['roi'] = summary.get('roi_pct')\n",
" scenarios = {}\n",
" for name in ('conservative', 'moderate', 'aggressive'):\n",
" sb = apply_scenario(seed.BENEFITS, name, table='benefits')\n",
" sc = apply_scenario(seed.COSTS, name, table='costs')\n",
" scenarios[name] = _compute_summary(sb, sc, config.DISCOUNT_RATE, config.ANALYSIS_YEARS)\n",
" envelope = {\n",
" 'metadata': {\n",
" 'study_slug': config.STUDY_SLUG,\n",
" 'tool_public_id': '',\n",
" 'tool_name': 'CX Cloud (Genesys + Salesforce) TEI (local seed)',\n",
" 'report_name': 'Total Economic Impact\u2122 Of CX Cloud \u2014 Genesys + Salesforce',\n",
" 'report_vendor': 'Genesys',\n",
" 'report_version': '1.0',\n",
" 'generated_at': datetime.now(timezone.utc).isoformat(),\n",
" 'generator': f'palladium core {__version__} (offline)',\n",
" },\n",
" 'report': {\n",
" 'name': 'Total Economic Impact\u2122 Of CX Cloud \u2014 Genesys + Salesforce',\n",
" 'vendor': 'Genesys',\n",
" 'version': '1.0',\n",
" 'discount_rate': config.DISCOUNT_RATE,\n",
" 'analysis_period_years': config.ANALYSIS_YEARS,\n",
" },\n",
" 'values': {'benefits': seed.BENEFITS, 'costs': seed.COSTS},\n",
" 'summary': summary,\n",
" 'scenarios': scenarios,\n",
" 'assumptions': seed.ASSUMPTIONS,\n",
" }\n",
" source = 'offline seed data'\n",
"\n",
"display.alert(f'Envelope built from <b>{source}</b>.', 'info')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "g4-code-write",
"metadata": {},
"outputs": [],
"source": [
"out_path = STUDY / 'exports' / 'export.json'\n",
"out_path.parent.mkdir(parents=True, exist_ok=True)\n",
"out_path.write_text(json.dumps(envelope, indent=2, default=str))\n",
"size_kb = out_path.stat().st_size / 1024\n",
"display.alert(f'Wrote <code>{out_path.relative_to(ROOT)}</code> ({size_kb:.1f} KB).', 'success')"
]
},
{
"cell_type": "markdown",
"id": "g4-md-shape",
"metadata": {},
"source": [
"## Envelope shape\n",
"\n",
"Top-level keys consumed by the report pipeline:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "g4-code-shape",
"metadata": {},
"outputs": [],
"source": [
"for key in envelope:\n",
" sub = envelope[key]\n",
" if isinstance(sub, dict):\n",
" print(f' {key}: dict with keys {list(sub.keys())}')\n",
" elif isinstance(sub, list):\n",
" print(f' {key}: list[{len(sub)}]')\n",
" else:\n",
" print(f' {key}: {type(sub).__name__}')"
]
},
{
"cell_type": "markdown",
"id": "g4-md-done",
"metadata": {},
"source": [
"Done. Hand off `exports/export.json` to **Peitho** / **html2docx** to produce the final Word report.\n",
"\n",
"**CLI alternative:** `python -m palladium export $PALLADIUM_GENESYSCX_TOOL_PUBLIC_ID -o studies/202512_GenesysCX/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
}