dabur-pricing-app / Genesis_AI_Data_Flow.html
Bera
initial deploy
14356bb
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Genesis AI β€” Complete Data Flow</title>
<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: 'Segoe UI', Arial, sans-serif;
background: #f4f6f9;
color: #1a1a2e;
padding: 32px;
}
h1 {
font-size: 22px;
font-weight: 700;
color: #1a6b2f;
border-bottom: 3px solid #1a6b2f;
padding-bottom: 10px;
margin-bottom: 6px;
}
.subtitle {
font-size: 12px;
color: #666;
margin-bottom: 32px;
}
/* ── Section cards ── */
.section {
background: #fff;
border-radius: 12px;
box-shadow: 0 2px 12px rgba(0,0,0,.08);
padding: 24px 28px;
margin-bottom: 28px;
}
.section-title {
font-size: 14px;
font-weight: 700;
letter-spacing: .5px;
text-transform: uppercase;
color: #1a6b2f;
margin-bottom: 18px;
display: flex;
align-items: center;
gap: 8px;
}
.section-title .badge {
background: #1a6b2f;
color: #fff;
font-size: 11px;
border-radius: 20px;
padding: 2px 10px;
}
/* ── Mermaid diagram wrapper ── */
.mermaid {
overflow-x: auto;
padding: 8px 0;
}
/* ── Step table ── */
table {
width: 100%;
border-collapse: collapse;
font-size: 12px;
}
thead tr {
background: #1a6b2f;
color: #fff;
}
thead th {
padding: 9px 14px;
text-align: left;
font-weight: 600;
letter-spacing: .3px;
}
tbody tr:nth-child(odd) { background: #f8faf8; }
tbody tr:nth-child(even) { background: #fff; }
tbody tr:hover { background: #e8f5e9; }
td {
padding: 8px 14px;
vertical-align: top;
border-bottom: 1px solid #e8ede9;
}
td:first-child { font-weight: 600; color: #1a6b2f; white-space: nowrap; }
.tag {
display: inline-block;
font-size: 10px;
font-weight: 600;
padding: 2px 7px;
border-radius: 4px;
white-space: nowrap;
}
.tag-fe { background: #e3f2fd; color: #1565c0; }
.tag-api { background: #fff3e0; color: #e65100; }
.tag-py { background: #e8f5e9; color: #1a6b2f; }
.tag-out { background: #f3e5f5; color: #6a1b9a; }
/* ── File list ── */
.file-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 10px;
margin-top: 4px;
}
.file-card {
background: #f8faf8;
border: 1px solid #c8e6c9;
border-radius: 8px;
padding: 10px 13px;
}
.file-card .fname {
font-family: 'Consolas', monospace;
font-size: 11px;
font-weight: 700;
color: #1a6b2f;
}
.file-card .fsrc {
font-size: 10px;
color: #888;
margin-top: 3px;
}
/* ── API table ── */
code {
font-family: 'Consolas', monospace;
font-size: 11.5px;
background: #f0f4f0;
padding: 2px 6px;
border-radius: 4px;
}
.footer {
text-align: center;
font-size: 11px;
color: #aaa;
margin-top: 32px;
padding-top: 16px;
border-top: 1px solid #e0e0e0;
}
</style>
</head>
<body>
<h1>Genesis AI β€” Price Elasticity Intelligence</h1>
<div class="subtitle">Complete Data Flow &nbsp;|&nbsp; Frontend β†’ API β†’ Python Pipeline β†’ Output β†’ Dashboard</div>
<!-- ── MASTER FLOWCHART ── -->
<div class="section">
<div class="section-title"><span class="badge">1</span> Master Flow Diagram</div>
<div class="mermaid">
flowchart TD
A([User opens Dashboard\nbrowser Β· localhost:5173]) --> B
B{Upload server\nrunning?}
B -- YES --> C1[GET /api/data/key x16\nFastAPI reads output/*.json]
B -- NO --> C2[GET /data/key.json x16\nVite serves public/data/ static files]
C1 --> D([React tabs render\nwith computed data])
C2 --> D
style A fill:#1a6b2f,color:#fff,rx:20
style D fill:#1a6b2f,color:#fff,rx:20
style B fill:#fff3e0,color:#333
</div>
</div>
<!-- ── UPLOAD FLOW ── -->
<div class="section">
<div class="section-title"><span class="badge">2</span> Upload Button β†’ Python Pipeline β†’ Dashboard Refresh</div>
<div class="mermaid">
flowchart TD
U1([User clicks Upload button\nHeader.jsx]) -->|opens| U2[UploadModal.jsx]
U2 -->|POST /api/upload/reset| U3[FastAPI resets job state β†’ idle]
U3 --> U4[User drags or picks .xlsx file]
U4 -->|POST /api/upload\nmultipart form-data| U5
U5[upload_server.py\n@app.post /api/upload] --> U6[Save file to\n_uploads/ folder]
U6 --> U7[Spawn background thread\n_run_pipeline]
U7 -->|returns immediately| U8[HTTP 200 Β· ok: true]
U8 --> U9[UploadModal polls every 1.5s\nGET /api/upload/status\nGET /api/upload/logs]
U7 -->|subprocess.Popen| P1
P1[pipeline/run.py\nEntry Point] --> P2
P2[pipeline/loader.py\nload_source_data\nread_brand_config] --> P3
P3[pipeline/config.py\nDEFAULT_PACK_ORDER\nconstants only] --> P4
P4[pipeline/modelling.py\nbuild_wide_pivot\nrun_elasticity_models\n343 specs tested] --> P5
P5[pipeline/proxies.py\nassign_proxies 7 grains\ncompute_freq_anchors] --> P6
P6[pipeline/diagnostics.py\nrun_diagnostics\nStep1_Diagnostics.xlsx] --> P7
P7[pipeline/exporters/stats.py] --> J1[models.json\nstats.json\nfreq_anchors.json]
P7 --> EX2
EX2[pipeline/exporters/market.py] --> J2[trend.json Β· ms.json\nvol_salience.json Β· val_share.json\ncomp_ms.json Β· vtm.json]
EX2 --> EX3
EX3[pipeline/exporters/ppa.py\nreads sheet 3_PPA_MT\nreads sheet 4_PPA_TT] --> J3[ppa_mt.json\nppa_tt.json]
EX3 --> EX4
EX4[pipeline/exporters/analytics.py] --> J4[interaction.json\ngrowth_decomp.json\npgi.json]
EX4 --> EX5
EX5[pipeline/exporters/recommendations.py] --> J5[recs_full.json]
J1 & J2 & J3 & J4 & J5 --> OUT[16 JSON files\nin output/]
OUT --> CP[Copied to\npublic/data/ as fallback]
OUT --> ST[Job status = done]
ST --> PL[UploadModal sees done\nUser clicks Reload Dashboard]
PL -->|GET /api/data/key x16| SV[upload_server.py\n@app.get /api/data/key\nreads output/key.json]
SV --> RD([React re-renders\nall 9 tabs with fresh data])
style U1 fill:#1a6b2f,color:#fff
style RD fill:#1a6b2f,color:#fff
style P1 fill:#1565c0,color:#fff
style OUT fill:#6a1b9a,color:#fff
</div>
</div>
<!-- ── STEP BY STEP TABLE ── -->
<div class="section">
<div class="section-title"><span class="badge">3</span> Step-by-Step Reference</div>
<table>
<thead>
<tr>
<th>Step</th>
<th>Where</th>
<th>File / Endpoint</th>
<th>What happens</th>
<th>Layer</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Browser</td>
<td><code>Header.jsx</code></td>
<td>User clicks ↑ Upload button β€” UploadModal opens</td>
<td><span class="tag tag-fe">Frontend</span></td>
</tr>
<tr>
<td>2</td>
<td>Browser</td>
<td><code>UploadModal.jsx</code></td>
<td>POST /api/upload/reset β€” clears previous job state on server</td>
<td><span class="tag tag-api">API</span></td>
</tr>
<tr>
<td>3</td>
<td>Browser</td>
<td><code>UploadModal.jsx</code></td>
<td>POST /api/upload β€” sends .xlsx file as multipart form-data</td>
<td><span class="tag tag-api">API</span></td>
</tr>
<tr>
<td>4</td>
<td>Server</td>
<td><code>upload_server.py</code></td>
<td>Saves file to _uploads/, spawns background thread, returns HTTP 200 immediately</td>
<td><span class="tag tag-py">Python</span></td>
</tr>
<tr>
<td>5</td>
<td>Server</td>
<td><code>upload_server.py</code></td>
<td>subprocess.Popen β†’ runs python -m pipeline.run with the uploaded file</td>
<td><span class="tag tag-py">Python</span></td>
</tr>
<tr>
<td>6</td>
<td>Pipeline</td>
<td><code>pipeline/loader.py</code></td>
<td>Reads sheet 1_Source_Data β†’ 3,207 rows DataFrame. Reads sheet 2_Brand_Config β†’ focal brand + competitors</td>
<td><span class="tag tag-py">Python</span></td>
</tr>
<tr>
<td>7</td>
<td>Pipeline</td>
<td><code>pipeline/config.py</code></td>
<td>Loads DEFAULT_PACK_ORDER and all modelling thresholds (no I/O)</td>
<td><span class="tag tag-py">Python</span></td>
</tr>
<tr>
<td>8</td>
<td>Pipeline</td>
<td><code>pipeline/modelling.py</code></td>
<td>build_wide_pivot() builds monthly CHΓ—Region tables. run_elasticity_models() tests 343 OLS specs per grain, selects best Adj-RΒ²</td>
<td><span class="tag tag-py">Python</span></td>
</tr>
<tr>
<td>9</td>
<td>Pipeline</td>
<td><code>pipeline/proxies.py</code></td>
<td>assign_proxies() fills 7 grains that failed sign check. compute_freq_anchors() finds dominant pack per CHΓ—Region</td>
<td><span class="tag tag-py">Python</span></td>
</tr>
<tr>
<td>10</td>
<td>Pipeline</td>
<td><code>pipeline/diagnostics.py</code></td>
<td>Runs collinearity, RPI, distribution, cannibalization checks β†’ writes Step1_Diagnostics.xlsx</td>
<td><span class="tag tag-py">Python</span></td>
</tr>
<tr>
<td>11</td>
<td>Exporters</td>
<td><code>exporters/stats.py</code></td>
<td>Writes models.json, stats.json, freq_anchors.json to output/</td>
<td><span class="tag tag-out">Output</span></td>
</tr>
<tr>
<td>12</td>
<td>Exporters</td>
<td><code>exporters/market.py</code></td>
<td>Writes trend.json, ms.json, vol_salience.json, val_share.json, comp_ms.json, vtm.json</td>
<td><span class="tag tag-out">Output</span></td>
</tr>
<tr>
<td>13</td>
<td>Exporters</td>
<td><code>exporters/ppa.py</code></td>
<td>Reads Excel sheets 3_PPA_MT and 4_PPA_TT β†’ writes ppa_mt.json, ppa_tt.json</td>
<td><span class="tag tag-out">Output</span></td>
</tr>
<tr>
<td>14</td>
<td>Exporters</td>
<td><code>exporters/analytics.py</code></td>
<td>Writes interaction.json, growth_decomp.json, pgi.json</td>
<td><span class="tag tag-out">Output</span></td>
</tr>
<tr>
<td>15</td>
<td>Exporters</td>
<td><code>exporters/recommendations.py</code></td>
<td>Writes recs_full.json</td>
<td><span class="tag tag-out">Output</span></td>
</tr>
<tr>
<td>16</td>
<td>Server</td>
<td><code>upload_server.py</code></td>
<td>Copies all 16 JSON files from output/ to public/data/ as static fallback. Sets job status = done</td>
<td><span class="tag tag-py">Python</span></td>
</tr>
<tr>
<td>17</td>
<td>Browser</td>
<td><code>UploadModal.jsx</code></td>
<td>Polling detects status = done. User clicks Reload Dashboard</td>
<td><span class="tag tag-fe">Frontend</span></td>
</tr>
<tr>
<td>18</td>
<td>Browser</td>
<td><code>DataContext.jsx</code></td>
<td>Fires GET /api/data/{key} Γ— 16 calls to fetch all computed JSON data</td>
<td><span class="tag tag-api">API</span></td>
</tr>
<tr>
<td>19</td>
<td>Server</td>
<td><code>upload_server.py</code></td>
<td>@app.get("/api/data/{key}") reads output/{key}.json β†’ returns JSON to browser</td>
<td><span class="tag tag-py">Python</span></td>
</tr>
<tr>
<td>20</td>
<td>Browser</td>
<td>All 9 tab components</td>
<td>React re-renders every tab with fresh pipeline-computed data</td>
<td><span class="tag tag-fe">Frontend</span></td>
</tr>
</tbody>
</table>
</div>
<!-- ── API ENDPOINTS ── -->
<div class="section">
<div class="section-title"><span class="badge">4</span> All API Endpoints</div>
<table>
<thead>
<tr><th>Method</th><th>Endpoint</th><th>Called by</th><th>Purpose</th></tr>
</thead>
<tbody>
<tr><td>POST</td><td><code>/api/upload</code></td><td>UploadModal.jsx</td><td>Upload .xlsx file β†’ triggers Python pipeline</td></tr>
<tr><td>GET</td> <td><code>/api/upload/status</code></td><td>UploadModal.jsx (poll)</td><td>Returns { status, message, elapsed_s }</td></tr>
<tr><td>GET</td> <td><code>/api/upload/logs</code></td><td>UploadModal.jsx (poll)</td><td>Returns live pipeline stdout as { logs }</td></tr>
<tr><td>POST</td><td><code>/api/upload/reset</code></td><td>UploadModal.jsx (on open)</td><td>Clears job state back to idle</td></tr>
<tr><td>GET</td> <td><code>/api/data/{key}</code></td><td>DataContext.jsx</td><td>Serves output/{key}.json computed by pipeline</td></tr>
<tr><td>GET</td> <td><code>/api/data</code></td><td>(debug)</td><td>Lists all available data keys and file sizes</td></tr>
<tr><td>GET</td> <td><code>/data/{key}.json</code></td><td>DataContext.jsx (fallback)</td><td>Vite static file β€” used only when server is down</td></tr>
</tbody>
</table>
</div>
<!-- ── OUTPUT FILES ── -->
<div class="section">
<div class="section-title"><span class="badge">5</span> Python Output Files β†’ Dashboard Tabs</div>
<div class="file-grid">
<div class="file-card"><div class="fname">models.json</div><div class="fsrc">exporters/stats.py β†’ Elasticity Results tab</div></div>
<div class="file-card"><div class="fname">stats.json</div><div class="fsrc">exporters/stats.py β†’ Header KPIs</div></div>
<div class="file-card"><div class="fname">freq_anchors.json</div><div class="fsrc">exporters/stats.py β†’ Methodology tab</div></div>
<div class="file-card"><div class="fname">trend.json</div><div class="fsrc">exporters/market.py β†’ Trends tab</div></div>
<div class="file-card"><div class="fname">ms.json</div><div class="fsrc">exporters/market.py β†’ shared</div></div>
<div class="file-card"><div class="fname">vol_salience.json</div><div class="fsrc">exporters/market.py β†’ shared</div></div>
<div class="file-card"><div class="fname">val_share.json</div><div class="fsrc">exporters/market.py β†’ shared</div></div>
<div class="file-card"><div class="fname">comp_ms.json</div><div class="fsrc">exporters/market.py β†’ shared</div></div>
<div class="file-card"><div class="fname">vtm.json</div><div class="fsrc">exporters/market.py β†’ Brand Interaction tab</div></div>
<div class="file-card"><div class="fname">ppa_mt.json</div><div class="fsrc">exporters/ppa.py β†’ PPA tab (MT)</div></div>
<div class="file-card"><div class="fname">ppa_tt.json</div><div class="fsrc">exporters/ppa.py β†’ PPA tab (TT)</div></div>
<div class="file-card"><div class="fname">interaction.json</div><div class="fsrc">exporters/analytics.py β†’ Brand Interaction tab</div></div>
<div class="file-card"><div class="fname">growth_decomp.json</div><div class="fsrc">exporters/analytics.py β†’ Growth Decomp tab</div></div>
<div class="file-card"><div class="fname">pgi.json</div><div class="fsrc">exporters/analytics.py β†’ Price Gradient tab</div></div>
<div class="file-card"><div class="fname">recs_full.json</div><div class="fsrc">exporters/recommendations.py β†’ Recommendations tab</div></div>
<div class="file-card"><div class="fname">recs.json</div><div class="fsrc">alias of recs_full.json</div></div>
</div>
</div>
<div class="footer">
Genesis AI Β· Price Elasticity Intelligence Β· Dabur Sarson Amla &nbsp;|&nbsp; Generated by Claude Code
</div>
<script>
mermaid.initialize({
startOnLoad: true,
theme: 'default',
flowchart: { curve: 'basis', padding: 20 },
themeVariables: {
primaryColor: '#e8f5e9',
primaryTextColor: '#1a1a2e',
primaryBorderColor: '#1a6b2f',
lineColor: '#1a6b2f',
secondaryColor: '#fff3e0',
tertiaryColor: '#e3f2fd',
}
})
</script>
</body>
</html>