diff --git a/training/dashboard/static/dashboard.js b/training/dashboard/static/dashboard.js index b5e8d80..275974b 100644 --- a/training/dashboard/static/dashboard.js +++ b/training/dashboard/static/dashboard.js @@ -238,8 +238,8 @@ } // Occasionally tweak a model metric so the bars aren't static. if (Math.random() < 0.05) { - const m = ['rnn', 'gru', 'lstm', 'bert'][Math.floor(Math.random() * 4)]; - const base = { rnn: 0.872, gru: 0.911, lstm: 0.928, bert: 0.954 }[m]; + const m = ['knn', 'rnn', 'gru', 'lstm', 'bert'][Math.floor(Math.random() * 5)]; + const base = { knn: 0.736, rnn: 0.872, gru: 0.911, lstm: 0.928, bert: 0.954 }[m]; dispatch({ type: 'model_metric', model: m, accuracy: base + (Math.random() - 0.5) * 0.012 }); } } @@ -1345,8 +1345,15 @@ def train_nn(*, model, X_train, y_train, X_val, y_val, function fmtInt(n) { return (typeof n === 'number') ? n.toLocaleString() : '—'; } + // Tracks whether real phase_mix data has arrived. demo_start uses + // this to decide whether to inject a synthetic fallback — if real + // data is already present (from snapshot or the phase_mix feeder), + // the demo toggle does NOT clobber it. + let hasRealMix = false; + function applyMix(mix) { if (!mix) return; + hasRealMix = true; const w = mix.weighted_seconds || {}; const c = mix.counts || {}; // Prefer time-weighted proportions; fall back to label counts. @@ -1378,6 +1385,31 @@ def train_nn(*, model, X_train, y_train, X_val, y_val, on('snapshot', m => { if (m.phase_mix) applyMix(m.phase_mix); }); on('phase_mix', applyMix); + on('demo_start', () => { + // Synthetic fallback: only fires if no real phase_mix has + // arrived yet (e.g. dashboard offline, or feeder hasn't done its + // first compute). The numbers below mirror a real production run + // so the bar reads correctly during a deck-only demo. If real + // data later arrives via snapshot or phase_mix event, applyMix + // overwrites this on the spot. + if (hasRealMix) return; + applyMix({ + weighted_seconds: { + clean: 2659.1, armed: 725.7, infecting: 1607.4, + infected_running: 8308.3, dormant: 3059.3, + }, + counts: { + clean: 451, armed: 198, infecting: 379, + infected_running: 614, dormant: 223, + }, + sampled_episodes: 500, + population_episodes: 78705, + total_labels: 1865, + }); + // applyMix flipped hasRealMix to true — flip back so a future + // real arrival is still recognised as the first real one. + hasRealMix = false; + }); on('demo_stop', () => { // Demo toggle off doesn't wipe the dataset mix — the dataset is // ground truth, the demo only fakes per-event widgets. diff --git a/training/dashboard/static/index.html b/training/dashboard/static/index.html index e11ab00..2705411 100644 --- a/training/dashboard/static/index.html +++ b/training/dashboard/static/index.html @@ -1314,6 +1314,6 @@ - +