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:
195
studies/202602_AmazonConnect/notebooks/04_export.ipynb
Normal file
195
studies/202602_AmazonConnect/notebooks/04_export.ipynb
Normal file
@@ -0,0 +1,195 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "15a4163e",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# 04 — 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": "18f02ef8",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import sys\n",
|
||||
"from pathlib import Path\n",
|
||||
"\n",
|
||||
"ROOT = Path.cwd().resolve()\n",
|
||||
"while ROOT != ROOT.parent and not (ROOT / 'core').is_dir():\n",
|
||||
" ROOT = ROOT.parent\n",
|
||||
"if str(ROOT) not in sys.path:\n",
|
||||
" sys.path.insert(0, str(ROOT))\n",
|
||||
"STUDY = ROOT / 'studies' / '202602_AmazonConnect'\n",
|
||||
"if str(STUDY) not in sys.path:\n",
|
||||
" sys.path.insert(0, str(STUDY))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "7d91c01d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import json\n",
|
||||
"from datetime import datetime, timezone\n",
|
||||
"\n",
|
||||
"import config\n",
|
||||
"import seed_data\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": "cff0b35b",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Build the envelope\n",
|
||||
"\n",
|
||||
"Two paths:\n",
|
||||
"\n",
|
||||
"* **Live** — `core.export.build_report_data(client, public_id)` pulls\n",
|
||||
" authoritative values + summary from Athena and stamps it.\n",
|
||||
"* **Local** — 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": "19416ff3",
|
||||
"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_data.BENEFITS, seed_data.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_data.BENEFITS, name, table='benefits')\n",
|
||||
" sc = apply_scenario(seed_data.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': 'Amazon Connect TEI (local seed)',\n",
|
||||
" 'report_name': 'Total Economic Impact™ Of Amazon Connect',\n",
|
||||
" 'report_vendor': 'AWS',\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™ Of Amazon Connect',\n",
|
||||
" 'vendor': 'AWS',\n",
|
||||
" 'version': '1.0',\n",
|
||||
" 'discount_rate': config.DISCOUNT_RATE,\n",
|
||||
" 'analysis_period_years': config.ANALYSIS_YEARS,\n",
|
||||
" },\n",
|
||||
" 'values': {'benefits': seed_data.BENEFITS, 'costs': seed_data.COSTS},\n",
|
||||
" 'summary': summary,\n",
|
||||
" 'scenarios': scenarios,\n",
|
||||
" 'assumptions': seed_data.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": "98e94d07",
|
||||
"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": "d09cad64",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Envelope shape\n",
|
||||
"\n",
|
||||
"Top-level keys consumed by the report pipeline:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "841f12a1",
|
||||
"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": "17d6d0ce",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Done. Hand off `exports/export.json` to **Peitho** / **html2docx** to produce the final Word report."
|
||||
]
|
||||
}
|
||||
],
|
||||
"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.13.7"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
Reference in New Issue
Block a user