Spaces:
Sleeping
Sleeping
| <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 → Python pipeline → JSON outputs → 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 → Poll → 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 — 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 → 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> | |