dabur-pricing-app / Genesis_AI_Flowchart.html
Bera
initial deploy
14356bb
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>Genesis AI β€” System Flowchart</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: #f0f4f0; color: #1a1a2e; padding: 36px; }
h1 { font-size: 24px; font-weight: 700; color: #1a6b2f; padding-bottom: 10px;
border-bottom: 3px solid #1a6b2f; margin-bottom: 4px; }
.sub { font-size: 12px; color: #777; margin-bottom: 36px; }
/* ── section card ── */
.card { background: #fff; border-radius: 14px; box-shadow: 0 2px 16px rgba(0,0,0,.08);
padding: 28px 32px; margin-bottom: 30px; }
.card-title { font-size: 13px; font-weight: 700; letter-spacing: .6px; text-transform: uppercase;
color: #1a6b2f; margin-bottom: 18px; }
/* ── mermaid override ── */
.mermaid { font-size: 13px; }
.mermaid svg { width: 100%; height: auto; }
/* ── legend ── */
.legend { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 16px; }
.leg { display: flex; align-items: center; gap: 6px; font-size: 11px; color: #555; }
.leg-dot { width: 14px; height: 14px; border-radius: 3px; flex-shrink: 0; }
/* ── table ── */
table { width: 100%; border-collapse: collapse; font-size: 12px; }
thead tr { background: #1a6b2f; color: #fff; }
thead th { padding: 10px 14px; text-align: left; font-weight: 600; }
tbody tr:nth-child(even) { background: #f5faf5; }
tbody td { padding: 9px 14px; border-bottom: 1px solid #e5ede5; vertical-align: top; }
td:first-child { font-weight: 700; color: #1a6b2f; white-space: nowrap; }
td code { font-family: Consolas, monospace; font-size: 11px; background: #eef4ee;
padding: 2px 6px; border-radius: 3px; }
.badge { display: inline-block; font-size: 10px; font-weight: 700; padding: 2px 7px;
border-radius: 10px; margin-right: 4px; }
.fe { background: #e3f2fd; color: #1565c0; }
.be { background: #fff3e0; color: #c84b00; }
.py { background: #e8f5e9; color: #1b5e20; }
.out { background: #f3e5f5; color: #6a1b9a; }
</style>
</head>
<body>
<h1>Genesis AI β€” Complete System Flowchart</h1>
<p class="sub">End-to-end flow: Excel upload &rarr; Python pipeline &rarr; JSON outputs &rarr; React dashboard</p>
<!-- ══════════════════════════════════════════════════════════════ -->
<!-- MASTER FLOW -->
<!-- ══════════════════════════════════════════════════════════════ -->
<div class="card">
<div class="card-title">Master Flow β€” Upload to Dashboard</div>
<div class="mermaid">
flowchart TD
A([" πŸ‘€ User\nOpens Dashboard "]) --> B
subgraph FE [" REACT FRONTEND (localhost:5173) "]
B["Header.jsx\nShows file badge\n+ Upload button"]
B --> C["UploadModal.jsx\nUser picks .xlsx file"]
C --> D["POST /api/upload\nfetch() with FormData"]
D2["DataContext.jsx\nfetchKey() per tab"]
D3["Dashboard tabs render\nResults / PPA / Market / Recs …"]
D2 --> D3
end
subgraph BE [" FASTAPI BACKEND (localhost:8000) "]
E["upload_server.py\n@app.post('/api/upload')\nSaves .xlsx to _uploads/"]
F["background thread\n_run_pipeline()"]
E --> F
G["GET /api/data/{key}\n@app.get('/api/data/{key}')\nReads output/{key}.json"]
end
subgraph PY [" PYTHON PIPELINE (pipeline/) "]
P1["loader.py\nload_data()\nRead 1_Source_Data sheet\ncompute Price = Val/Vol"]
P2["run.py\nread_brand_config()\nFocal brand + competitors\nfrom 2_Brand_Config sheet"]
P3["modelling.py\nbuild_wide_pivot()\nOne table per CHΓ—RG grain"]
P4["diagnostics.py\nrun_diagnostics()\nCorrelation, CV, RPI checks"]
P5["modelling.py\nrun_elasticity_models()\nOLS regression per grain\nBest Adj-RΒ² spec selected"]
P6["proxies.py\nassign_proxies()\nWrong-sign grains get\nborrowed elasticity"]
P7["exporters/stats.py\nexporters/market.py\nexporters/ppa.py\nexporters/analytics.py\nexporters/recommendations.py"]
P1 --> P2 --> P3 --> P4 --> P5 --> P6 --> P7
end
subgraph OUT [" OUTPUT FILES (output/) "]
J1["models.json\nstats.json\nfreq_anchors.json"]
J2["trend.json Β· ms.json\nvol_salience.json\nval_share.json\ncomp_ms.json Β· vtm.json"]
J3["ppa_mt.json\nppa_tt.json"]
J4["interaction.json\ngrowth_decomp.json\npgi.json"]
J5["recs_full.json"]
end
D --> E
F --> P1
P7 --> J1
P7 --> J2
P7 --> J3
P7 --> J4
P7 --> J5
J1 & J2 & J3 & J4 & J5 --> G
G --> D2
style FE fill:#e3f2fd,stroke:#1565c0,color:#0d1b4b
style BE fill:#fff3e0,stroke:#c84b00,color:#3e2000
style PY fill:#e8f5e9,stroke:#2e7d32,color:#1b2e1b
style OUT fill:#f3e5f5,stroke:#7b1fa2,color:#2e0040
</div>
<div class="legend">
<div class="leg"><div class="leg-dot" style="background:#bbdefb;border:1.5px solid #1565c0"></div> React Frontend</div>
<div class="leg"><div class="leg-dot" style="background:#ffe0b2;border:1.5px solid #c84b00"></div> FastAPI Backend</div>
<div class="leg"><div class="leg-dot" style="background:#c8e6c9;border:1.5px solid #2e7d32"></div> Python Pipeline</div>
<div class="leg"><div class="leg-dot" style="background:#e1bee7;border:1.5px solid #7b1fa2"></div> JSON Outputs</div>
</div>
</div>
<!-- ══════════════════════════════════════════════════════════════ -->
<!-- API FLOW -->
<!-- ══════════════════════════════════════════════════════════════ -->
<div class="card">
<div class="card-title">API Sequence β€” Upload &rarr; Poll &rarr; Fetch Data</div>
<div class="mermaid">
sequenceDiagram
participant UI as React (browser)
participant API as FastAPI :8000
participant PL as Pipeline (subprocess)
participant FS as output/*.json
UI->>API: POST /api/upload (FormData: file.xlsx)
API-->>UI: 200 { ok:true, filename }
Note over API: background thread starts
loop every 2 s while status == "running"
UI->>API: GET /api/upload/status
API-->>UI: { status, message, elapsed_s }
end
Note over PL: loader β†’ config β†’ pivot β†’ diag β†’ OLS β†’ proxies β†’ export
API->>PL: subprocess python -m pipeline.run --input file.xlsx
PL-->>FS: writes 16 Γ— *.json to output/
API-->>UI: status = "done"
loop for each of 16 data keys
UI->>API: GET /api/data/{key}
API->>FS: reads output/{key}.json
FS-->>API: JSON bytes
API-->>UI: JSON response
end
Note over UI: Dashboard tabs render with fresh data
</div>
</div>
<!-- ══════════════════════════════════════════════════════════════ -->
<!-- PIPELINE STEPS DETAIL -->
<!-- ══════════════════════════════════════════════════════════════ -->
<div class="card">
<div class="card-title">Pipeline Steps &mdash; Detailed Breakdown</div>
<div class="mermaid">
flowchart LR
classDef step fill:#e8f5e9,stroke:#2e7d32,color:#1b2e1b,rx:8
classDef json fill:#f3e5f5,stroke:#7b1fa2,color:#2e0040,rx:8
classDef file fill:#fff3e0,stroke:#c84b00,color:#3e2000,rx:4
S1["STEP 1\nloader.py\nload_data()"]:::step
S2["STEP 2\nrun.py\nread_brand_config()"]:::step
S3["STEP 3\nmodelling.py\nbuild_wide_pivot()"]:::step
S4["STEP 4\ndiagnostics.py\nrun_diagnostics()"]:::step
S5["STEP 5\nmodelling.py\nrun_elasticity_models()"]:::step
S6["STEP 6\nproxies.py\nassign_proxies()"]:::step
E1["stats.py\nexport_stats()"]:::step
E2["market.py\nexport_market()"]:::step
E3["ppa.py\nexport_ppa()"]:::step
E4["analytics.py\nexport_analytics()"]:::step
E5["recommendations.py\nexport_recs()"]:::step
J1["models.json\nstats.json\nfreq_anchors.json"]:::json
J2["trend.json\nms.json\nvol_salience.json\nval_share.json\ncomp_ms.json\nvtm.json"]:::json
J3["ppa_mt.json\nppa_tt.json"]:::json
J4["interaction.json\ngrowth_decomp.json\npgi.json"]:::json
J5["recs_full.json"]:::json
S1 --> S2 --> S3 --> S4 --> S5 --> S6
S6 --> E1 & E2 & E3 & E4 & E5
E1 --> J1
E2 --> J2
E3 --> J3
E4 --> J4
E5 --> J5
</div>
</div>
<!-- ══════════════════════════════════════════════════════════════ -->
<!-- STEP TABLE -->
<!-- ══════════════════════════════════════════════════════════════ -->
<div class="card">
<div class="card-title">Step-by-Step Reference Table</div>
<table>
<thead>
<tr>
<th>Step</th>
<th>Layer</th>
<th>File</th>
<th>Function / Endpoint</th>
<th>What it does</th>
<th>Output</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td><span class="badge fe">FE</span></td>
<td><code>Header.jsx</code></td>
<td>Upload button click</td>
<td>Opens UploadModal; shows active filename badge from localStorage</td>
<td>β€”</td>
</tr>
<tr>
<td>2</td>
<td><span class="badge fe">FE</span></td>
<td><code>UploadModal.jsx</code></td>
<td><code>handleUpload()</code></td>
<td>Sends <code>POST /api/upload</code> with FormData; polls <code>/api/upload/status</code> every 2 s</td>
<td>Filename stored in localStorage</td>
</tr>
<tr>
<td>3</td>
<td><span class="badge be">BE</span></td>
<td><code>upload_server.py</code></td>
<td><code>POST /api/upload</code></td>
<td>Validates extension, saves .xlsx to <code>_uploads/</code>, spawns background thread</td>
<td><code>{ ok: true, filename }</code></td>
</tr>
<tr>
<td>4</td>
<td><span class="badge be">BE</span></td>
<td><code>upload_server.py</code></td>
<td><code>_run_pipeline()</code></td>
<td>Calls <code>python -m pipeline.run --input file.xlsx --output output/</code> via subprocess.Popen (streams live)</td>
<td>Terminal log</td>
</tr>
<tr>
<td>5</td>
<td><span class="badge py">PY</span></td>
<td><code>pipeline/loader.py</code></td>
<td><code>load_data()</code></td>
<td>Reads sheet <em>1_Source_Data</em>; computes Price = Value / Volume; drops nulls</td>
<td>DataFrame</td>
</tr>
<tr>
<td>6</td>
<td><span class="badge py">PY</span></td>
<td><code>pipeline/run.py</code></td>
<td><code>read_brand_config()</code></td>
<td>Reads sheet <em>2_Brand_Config</em>; extracts focal brand + competitors</td>
<td>brand config dict</td>
</tr>
<tr>
<td>7</td>
<td><span class="badge py">PY</span></td>
<td><code>pipeline/modelling.py</code></td>
<td><code>build_wide_pivot()</code></td>
<td>One wide table per Channel Γ— Region grain with focal + competitor columns</td>
<td>wide DataFrame</td>
</tr>
<tr>
<td>8</td>
<td><span class="badge py">PY</span></td>
<td><code>pipeline/diagnostics.py</code></td>
<td><code>run_diagnostics()</code></td>
<td>Pearson correlation, CV, RPI checks per grain; writes Excel diagnostics file</td>
<td><code>*_Diagnostics.xlsx</code></td>
</tr>
<tr>
<td>9</td>
<td><span class="badge py">PY</span></td>
<td><code>pipeline/modelling.py</code></td>
<td><code>run_elasticity_models()</code></td>
<td>OLS regression on all spec combos; selects best Adj-RΒ² with correct sign; clamps to [βˆ’6, 0]</td>
<td>results DataFrame</td>
</tr>
<tr>
<td>10</td>
<td><span class="badge py">PY</span></td>
<td><code>pipeline/proxies.py</code></td>
<td><code>assign_proxies()</code></td>
<td>Wrong-sign grains borrow elasticity from adjacent/nearby grains</td>
<td>final elasticities</td>
</tr>
<tr>
<td>11</td>
<td><span class="badge py">PY</span></td>
<td><code>pipeline/exporters/stats.py</code></td>
<td><code>export_stats()</code></td>
<td>Writes elasticity results + brand KPIs</td>
<td><code>models.json, stats.json, freq_anchors.json</code></td>
</tr>
<tr>
<td>12</td>
<td><span class="badge py">PY</span></td>
<td><code>pipeline/exporters/market.py</code></td>
<td><code>export_market()</code></td>
<td>Writes time-series, market share, volume/value share</td>
<td><code>trend.json, ms.json, vol_salience.json, val_share.json, comp_ms.json, vtm.json</code></td>
</tr>
<tr>
<td>13</td>
<td><span class="badge py">PY</span></td>
<td><code>pipeline/exporters/ppa.py</code></td>
<td><code>export_ppa()</code></td>
<td>Reads sheets <em>3_PPA_MT</em> and <em>4_PPA_TT</em> from original xlsx</td>
<td><code>ppa_mt.json, ppa_tt.json</code></td>
</tr>
<tr>
<td>14</td>
<td><span class="badge py">PY</span></td>
<td><code>pipeline/exporters/analytics.py</code></td>
<td><code>export_analytics()</code></td>
<td>Cross-brand correlations, growth decomposition, price gradient index</td>
<td><code>interaction.json, growth_decomp.json, pgi.json</code></td>
</tr>
<tr>
<td>15</td>
<td><span class="badge py">PY</span></td>
<td><code>pipeline/exporters/recommendations.py</code></td>
<td><code>export_recs()</code></td>
<td>Builds pricing recommendation cards per pack using elasticities</td>
<td><code>recs_full.json</code></td>
</tr>
<tr>
<td>16</td>
<td><span class="badge be">BE</span></td>
<td><code>upload_server.py</code></td>
<td><code>GET /api/data/{key}</code></td>
<td>Reads <code>output/{key}.json</code> and returns as JSON response to React</td>
<td>JSON to browser</td>
</tr>
<tr>
<td>17</td>
<td><span class="badge fe">FE</span></td>
<td><code>DataContext.jsx</code></td>
<td><code>fetchKey()</code></td>
<td>Tries <code>/api/data/{key}</code> first; falls back to <code>/data/{key}.json</code> (static)</td>
<td>React state updated</td>
</tr>
<tr>
<td>18</td>
<td><span class="badge fe">FE</span></td>
<td><code>src/components/tabs/</code></td>
<td>All tab components</td>
<td>Read from DataContext and render charts, tables, recommendation cards</td>
<td>Dashboard UI</td>
</tr>
</tbody>
</table>
</div>
<!-- ══════════════════════════════════════════════════════════════ -->
<!-- DATA SERVING β€” TWO-TIER -->
<!-- ══════════════════════════════════════════════════════════════ -->
<div class="card">
<div class="card-title">Data Serving β€” Two-Tier Fallback</div>
<div class="mermaid">
flowchart TD
A["React: fetchKey(key)"] --> B{"FastAPI server\nreachable?"}
B -- Yes --> C["GET /api/data/{key}\nlocalhost:8000"]
B -- No --> D["GET /data/{key}.json\nVite static (public/data/)"]
C -- "200 OK" --> E["Use API response\n(always fresh)"]
C -- "404 / error" --> D
D -- "200 OK" --> F["Use static file\n(last pipeline run)"]
D -- "404 / error" --> G["null β€” tab shows empty state"]
style E fill:#e8f5e9,stroke:#2e7d32
style F fill:#fff3e0,stroke:#c84b00
style G fill:#fce4ec,stroke:#b71c1c
</div>
</div>
<!-- ══════════════════════════════════════════════════════════════ -->
<!-- FILE MAP -->
<!-- ══════════════════════════════════════════════════════════════ -->
<div class="card">
<div class="card-title">Output File Map β€” JSON Key &rarr; Dashboard Tab</div>
<table>
<thead>
<tr>
<th>JSON file</th>
<th>API key</th>
<th>Pipeline exporter</th>
<th>Dashboard tab / component</th>
</tr>
</thead>
<tbody>
<tr><td><code>models.json</code></td><td><code>models</code></td><td>stats.py</td><td>Results β€” elasticity table</td></tr>
<tr><td><code>stats.json</code></td><td><code>stats</code></td><td>stats.py</td><td>Header KPIs, brand summary</td></tr>
<tr><td><code>freq_anchors.json</code></td><td><code>freq_anchors</code></td><td>stats.py</td><td>Results β€” frequency anchors</td></tr>
<tr><td><code>trend.json</code></td><td><code>trend</code></td><td>market.py</td><td>Trends tab β€” time-series chart</td></tr>
<tr><td><code>ms.json</code></td><td><code>ms</code></td><td>market.py</td><td>Market Share tab</td></tr>
<tr><td><code>vol_salience.json</code></td><td><code>vol_salience</code></td><td>market.py</td><td>Growth tab β€” pack salience</td></tr>
<tr><td><code>val_share.json</code></td><td><code>val_share</code></td><td>market.py</td><td>Growth tab β€” value share</td></tr>
<tr><td><code>comp_ms.json</code></td><td><code>comp_ms</code></td><td>market.py</td><td>Market Share β€” all brands</td></tr>
<tr><td><code>vtm.json</code></td><td><code>vtm</code></td><td>market.py</td><td>Results β€” volume-to-market</td></tr>
<tr><td><code>ppa_mt.json</code></td><td><code>ppa_mt</code></td><td>ppa.py</td><td>PPA tab β€” Modern Trade</td></tr>
<tr><td><code>ppa_tt.json</code></td><td><code>ppa_tt</code></td><td>ppa.py</td><td>PPA tab β€” Traditional Trade</td></tr>
<tr><td><code>interaction.json</code></td><td><code>interaction</code></td><td>analytics.py</td><td>Interaction tab β€” correlation matrix</td></tr>
<tr><td><code>growth_decomp.json</code></td><td><code>growth_decomp</code></td><td>analytics.py</td><td>Growth tab β€” decomposition chart</td></tr>
<tr><td><code>pgi.json</code></td><td><code>pgi</code></td><td>analytics.py</td><td>Methodology tab β€” price gradient</td></tr>
<tr><td><code>recs_full.json</code></td><td><code>recs / recs_full</code></td><td>recommendations.py</td><td>Recommendations tab β€” cards</td></tr>
</tbody>
</table>
</div>
<script>
mermaid.initialize({
startOnLoad: true,
theme: 'default',
themeVariables: {
primaryColor: '#e8f5e9',
primaryTextColor: '#1b2e1b',
primaryBorderColor: '#2e7d32',
lineColor: '#2e7d32',
secondaryColor: '#fff3e0',
tertiaryColor: '#f3e5f5',
fontSize: '13px',
},
flowchart: { curve: 'basis', padding: 20 },
sequence: { actorMargin: 80, messageMargin: 40, mirrorActors: false },
})
</script>
</body>
</html>