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 @@
-
+