teragron commited on
Commit
00d04b6
·
verified ·
1 Parent(s): daf9d04

deploy: 683d1c8

Browse files
Files changed (2) hide show
  1. README.md +9 -4
  2. index.html +177 -17
README.md CHANGED
@@ -1,10 +1,15 @@
1
  ---
2
  title: Evo Viewer
3
- emoji: 💻
4
- colorFrom: yellow
5
- colorTo: green
6
  sdk: static
7
  pinned: false
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
1
  ---
2
  title: Evo Viewer
3
+ emoji: 📈
4
+ colorFrom: indigo
5
+ colorTo: blue
6
  sdk: static
7
  pinned: false
8
  ---
9
 
10
+ # Evo Viewer
11
+
12
+ Live status for the [evolution-trainer](https://github.com/Teragron/evolution-trainer)
13
+ run. Pure static page -- fetches `run/history.csv` and `run/config.json`
14
+ straight from the browser off the public `teragron/evo-run` dataset repo
15
+ every 45s. No backend, no token, nothing to keep running.
index.html CHANGED
@@ -1,19 +1,179 @@
1
  <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  </html>
 
1
  <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>evolution training - live status</title>
7
+ <script src="https://cdn.jsdelivr.net/npm/chart.js@4"></script>
8
+ <style>
9
+ :root { color-scheme: dark; }
10
+ * { box-sizing: border-box; }
11
+ body {
12
+ margin: 0; padding: 2rem;
13
+ background: #12141a; color: #dde;
14
+ font: 14px/1.5 ui-monospace, "Consolas", "SF Mono", monospace;
15
+ }
16
+ h1 { font-size: 1.1rem; color: #ffc454; margin: 0 0 .25rem; }
17
+ .sub { color: #8890a0; margin-bottom: 1.5rem; }
18
+ .sub a { color: #6cb2ff; }
19
+ .stats {
20
+ display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
21
+ gap: 12px; margin-bottom: 1.5rem;
22
+ }
23
+ .card {
24
+ background: #171a22; border: 1px solid #262b38; border-radius: 8px;
25
+ padding: 12px 14px;
26
+ }
27
+ .card .label { color: #8890a0; font-size: .75rem; text-transform: uppercase; letter-spacing: .04em; }
28
+ .card .value { font-size: 1.3rem; color: #eef; margin-top: 4px; }
29
+ .card .value.stale { color: #ffa35c; }
30
+ .chart-wrap {
31
+ background: #171a22; border: 1px solid #262b38; border-radius: 8px;
32
+ padding: 16px; height: 360px;
33
+ }
34
+ .empty { color: #8890a0; padding: 2rem 0; text-align: center; }
35
+ </style>
36
+ </head>
37
+ <body>
38
+ <h1>evolution training - live status</h1>
39
+ <div class="sub">
40
+ watching <code>teragron/evo-run</code> &middot;
41
+ <a href="https://github.com/Teragron/evolution-trainer">source</a>
42
+ </div>
43
+
44
+ <div class="stats">
45
+ <div class="card"><div class="label">generation</div><div class="value" id="v-gen">-</div></div>
46
+ <div class="card"><div class="label">best fitness ever</div><div class="value" id="v-best">-</div></div>
47
+ <div class="card"><div class="label">speed</div><div class="value" id="v-speed">-</div></div>
48
+ <div class="card"><div class="label">last updated</div><div class="value" id="v-age">-</div></div>
49
+ </div>
50
+
51
+ <div class="chart-wrap">
52
+ <canvas id="chart"></canvas>
53
+ <div class="empty" id="empty" style="display:none">no data yet -- waiting for the first checkpoint push</div>
54
+ </div>
55
+
56
+ <script>
57
+ const REPO_ID = "teragron/evo-run";
58
+ const RAW_BASE = `https://huggingface.co/datasets/${REPO_ID}/resolve/main/run/`;
59
+ const API_URL = `https://huggingface.co/api/datasets/${REPO_ID}`;
60
+ const REFRESH_MS = 45000;
61
+ const GENS_WINDOW = 20;
62
+
63
+ let lastGood = null; // { rows, population, lastModified }
64
+ let chart = null;
65
+
66
+ function parseCsv(text) {
67
+ const lines = text.trim().split("\n");
68
+ const header = lines[0].split(",");
69
+ return lines.slice(1).map(line => {
70
+ const cells = line.split(",");
71
+ const row = {};
72
+ header.forEach((h, i) => { row[h] = Number(cells[i]); });
73
+ return row;
74
+ });
75
+ }
76
+
77
+ function fmtAge(iso) {
78
+ if (!iso) return "unknown";
79
+ const seconds = (Date.now() - new Date(iso).getTime()) / 1000;
80
+ if (seconds < 90) return `${seconds.toFixed(0)}s ago`;
81
+ if (seconds < 5400) return `${(seconds / 60).toFixed(0)}m ago`;
82
+ return `${(seconds / 3600).toFixed(1)}h ago`;
83
+ }
84
+
85
+ function setText(id, text, stale) {
86
+ const el = document.getElementById(id);
87
+ el.textContent = text;
88
+ el.classList.toggle("stale", !!stale);
89
+ }
90
+
91
+ function renderChart(rows) {
92
+ const gens = rows.map(r => r.generation);
93
+ const best = rows.map(r => r.best);
94
+ const mean = rows.map(r => r.mean);
95
+ const ctx = document.getElementById("chart").getContext("2d");
96
+ const data = {
97
+ labels: gens,
98
+ datasets: [
99
+ { label: "mean", data: mean, borderColor: "#6a7590", borderWidth: 1.5,
100
+ pointRadius: 0, tension: 0.15 },
101
+ { label: "best", data: best, borderColor: "#ffc454", borderWidth: 2.5,
102
+ pointRadius: 0, tension: 0.15 },
103
+ ],
104
+ };
105
+ const opts = {
106
+ responsive: true, maintainAspectRatio: false,
107
+ animation: false,
108
+ interaction: { mode: "index", intersect: false },
109
+ scales: {
110
+ x: { title: { display: true, text: "generation", color: "#8890a0" },
111
+ ticks: { color: "#8890a0" }, grid: { color: "#232733" } },
112
+ y: { title: { display: true, text: "fitness (m)", color: "#8890a0" },
113
+ ticks: { color: "#8890a0" }, grid: { color: "#232733" } },
114
+ },
115
+ plugins: { legend: { labels: { color: "#dde" } } },
116
+ };
117
+ if (chart) {
118
+ chart.data = data;
119
+ chart.options = opts;
120
+ chart.update();
121
+ } else {
122
+ chart = new Chart(ctx, { type: "line", data, options: opts });
123
+ }
124
+ }
125
+
126
+ async function fetchState() {
127
+ const [csvText, config, apiInfo] = await Promise.all([
128
+ fetch(RAW_BASE + "history.csv").then(r => { if (!r.ok) throw new Error("history.csv " + r.status); return r.text(); }),
129
+ fetch(RAW_BASE + "config.json").then(r => { if (!r.ok) throw new Error("config.json " + r.status); return r.json(); }),
130
+ fetch(API_URL).then(r => r.ok ? r.json() : null).catch(() => null),
131
+ ]);
132
+ return {
133
+ rows: parseCsv(csvText),
134
+ population: config?.ga?.population ?? "?",
135
+ lastModified: apiInfo?.lastModified ?? null,
136
+ };
137
+ }
138
+
139
+ async function refresh() {
140
+ let state, stale = false;
141
+ try {
142
+ state = await fetchState();
143
+ lastGood = state;
144
+ } catch (e) {
145
+ if (!lastGood) {
146
+ document.getElementById("empty").style.display = "block";
147
+ setText("v-gen", "no data yet");
148
+ setText("v-best", "no data yet");
149
+ setText("v-speed", "no data yet");
150
+ setText("v-age", "no data yet");
151
+ return;
152
+ }
153
+ state = lastGood;
154
+ stale = true;
155
+ }
156
+
157
+ const { rows, population, lastModified } = state;
158
+ if (!rows.length) return;
159
+ document.getElementById("empty").style.display = "none";
160
+
161
+ const last = rows[rows.length - 1];
162
+ const bestEver = Math.max(...rows.map(r => r.best));
163
+ const window = rows.slice(-GENS_WINDOW);
164
+ const meanSecs = window.reduce((a, r) => a + r.seconds, 0) / window.length;
165
+ const gensPerHour = meanSecs > 0 ? 3600 / meanSecs : NaN;
166
+
167
+ setText("v-gen", `${last.generation}${stale ? " (stale)" : ""}`, stale);
168
+ setText("v-best", `${bestEver.toFixed(2)} m (pop ${population})`, stale);
169
+ setText("v-speed", `${last.evals_per_sec.toFixed(0)} evals/s, ~${gensPerHour.toFixed(0)} gen/hr`, stale);
170
+ setText("v-age", `${fmtAge(lastModified)}${stale ? " (fetch failing)" : ""}`, stale);
171
+
172
+ renderChart(rows);
173
+ }
174
+
175
+ refresh();
176
+ setInterval(refresh, REFRESH_MS);
177
+ </script>
178
+ </body>
179
  </html>