refactor: restructure repo into core/app modules with per-study folders

Reorganize Palladium codebase into a modular architecture with `core/`
shared logic and `app/` Streamlit UI, separating per-study assets into
`studies/YYYYMM_<Vendor>/` folders containing notebooks, seed data, and
configuration. Update README to reflect new structure, add `.gitignore`
entries for `.env` and study exports, and refresh component documentation.
This commit is contained in:
2026-05-20 22:28:12 -04:00
parent a6f3ee3676
commit a2420ed692
52 changed files with 35300 additions and 105 deletions

View File

@@ -0,0 +1,162 @@
"""
Seed dataset for the Amazon Connect TEI (Forrester, Feb 2026).
Each row matches the wire shape produced by
``core.tei_client.TEIClient._normalize_value`` so it can be passed
straight to ``client.update_values(public_id, BENEFITS + COSTS)``.
Numbers are the *nominal* (pre-risk-adjustment) values from the PDF —
risk adjustment is stored as a factor and applied by Athena's
calculator (or, locally, by ``core.calculations.risk_adjust_*``).
References for the totals (from the PDF):
Benefits (3-yr risk-adjusted PV @ 10%): $101,696,791
Costs (3-yr risk-adjusted PV @ 10%): $ 22,983,076
NPV $ 78,713,715
ROI 342%
Payback <6 months
"""
from __future__ import annotations
#: 3-year nominal benefit cashflows. Risk adjustment factor is stored
#: separately; calculator applies it.
BENEFITS: list[dict] = [
{
"field_key": "ai_contact_resolution",
"table": "benefits",
"label": "AI-driven contact resolution efficiency",
"category": "Productivity",
"year_values": {"1": 13_911_040, "2": 23_932_480, "3": 37_797_760},
"risk_adjustment": 0.15,
"notes": (
"PDF Section At/Atr. Composite: 20M annual contacts, 30% YoY "
"growth, 75% calls, 10-min AHT with legacy. Connect drops AHT "
"12% Y1 and shifts traffic to chat/self-service. 80% "
"productivity recapture. Risk adj 15% (legacy performance, "
"implementation depth, integration scope, growth)."
),
},
{
"field_key": "ai_content_sentiment",
"table": "benefits",
"label": "AI-powered content and sentiment analysis savings",
"category": "Productivity",
"year_values": {"1": 4_586_620, "2": 5_358_412, "3": 6_291_680},
"risk_adjustment": 0.15,
"notes": (
"PDF Section Bt/Btr. Auto post-contact summaries reclaim ~60s "
"per call; QA scaled from 13% to 100%; supervisors freed from "
"manual review. Risk adj 15%."
),
},
{
"field_key": "ai_forecasting_supervision",
"table": "benefits",
"label": "AI-enabled forecasting, agent scheduling, and supervision",
"category": "Productivity",
"year_values": {"1": 6_651_680, "2": 9_133_760, "3": 12_391_712},
"risk_adjustment": 0.15,
"notes": (
"PDF Section Ct/Ctr. ML-WFM yields 5% agent FTE optimization "
"and supervisors managing 20% more agents (10→12). 80% "
"productivity recapture. Risk adj 15%."
),
},
{
"field_key": "data_driven_profit_lift",
"table": "benefits",
"label": "Data-driven profit lift with increased conversion",
"category": "Revenue",
"year_values": {"1": 1_200_000, "2": 1_560_000, "3": 2_028_000},
"risk_adjustment": 0.20,
"notes": (
"PDF Section Dt/Dtr. Composite revenue $10B Y1 (+30% YoY); "
"5% from outbound contact-center marketing; conversion lifts "
"from 10% to 12% (+20% relative); 12% operating margin. "
"Risk adj 20%."
),
},
{
"field_key": "legacy_solution_savings",
"table": "benefits",
"label": "Legacy solution cost savings",
"category": "Cost Savings",
"year_values": {"1": 6_177_600, "2": 8_030_880, "3": 10_440_144},
"risk_adjustment": 0.20,
"notes": (
"PDF Section Et/Etr. Avg legacy license $180/agent-month × "
"(agents+supervisors) × 12, plus 30% overhead for infra & "
"third-party tools. Risk adj 20%."
),
},
]
#: Costs include an "initial" (year-0, undiscounted) component for
#: implementation. Cost risk adjustments are applied *upward*.
COSTS: list[dict] = [
{
"field_key": "amazon_connect_usage",
"table": "costs",
"label": "Amazon Connect usage cost",
"category": "Subscription",
"initial": 0,
"year_values": {"1": 6_456_448, "2": 7_951_164, "3": 9_832_961},
"risk_adjustment": 0.05,
"notes": (
"PDF Section Ft/Ftr. Telephony $0.0106/min + Unlimited AI "
"$0.0380/min on minutes that reach an agent, plus chat at "
"$0.0100/message (10 messages/chat). Risk adj 5%."
),
},
{
"field_key": "implementation_migration",
"table": "costs",
"label": "Implementation and migration cost",
"category": "Implementation",
"initial": 1_087_500,
"year_values": {"1": 188_333, "2": 188_333, "3": 0},
"risk_adjustment": 0.10,
"notes": (
"PDF Section Gt/Gtr. 6-month initial migration: 5 internal "
"FTE @ $115k + $800k pro-services. Y1/Y2 M&A integrations: 2 "
"months × 2 FTE + $150k pro-services. Risk adj 10%."
),
},
{
"field_key": "ongoing_management",
"table": "costs",
"label": "Ongoing management",
"category": "Operations",
"initial": 0,
"year_values": {"1": 256_200, "2": 187_200, "3": 187_200},
"risk_adjustment": 0.15,
"notes": (
"PDF Section Ht/Htr. Y1: 5 IT/PM @ 30% × $115k + 5 business "
"users @ 30% × $55,800. Y2/Y3: 3 IT/PM @ 30% + 5 business "
"users @ 30%. Risk adj 15%."
),
},
]
#: Top-line composite assumptions — for the 03_business_case narrative.
ASSUMPTIONS: dict = {
"agents_fte": 2_000,
"supervisors_fte": 200,
"annual_contacts_y1": 20_000_000,
"growth_rate": 0.30,
"call_share": 0.75,
"aht_legacy_minutes": 10,
"agent_salary": 45_760,
"supervisor_salary": 55_800,
"discount_rate": 0.10,
"analysis_years": 3,
}
def all_values() -> list[dict]:
"""Return BENEFITS + COSTS — handy single-call payload for update_values."""
return BENEFITS + COSTS