Spaces:
Sleeping
Sleeping
3D replay: the models' plans only
Browse files
README.md
CHANGED
|
@@ -24,7 +24,7 @@ tasks on other days.
|
|
| 24 |
|---|---|
|
| 25 |
| `/web` | OpenEnv's web UI. **Explore**: the eval explorer, the 3D replay and the train graph. **Playground**: reset, step and the MCP tools by hand |
|
| 26 |
| `/explorer/` | the leaderboard and every model's plan on every eval task; pick one to watch it |
|
| 27 |
-
| `/twin/` | the 3D replay:
|
| 28 |
| `/viewer/` | the train graph (time across, distance down) of any plan, with the plan's holds, short-turns and rule breaks |
|
| 29 |
| `/reset`, `/step`, `/state`, `/ws`, `/mcp` | OpenEnv |
|
| 30 |
| `/rail_ops/...` | OpenEnv Task API (`splits`, `num_tasks`, `task`, `task_range`) |
|
|
|
|
| 24 |
|---|---|
|
| 25 |
| `/web` | OpenEnv's web UI. **Explore**: the eval explorer, the 3D replay and the train graph. **Playground**: reset, step and the MCP tools by hand |
|
| 26 |
| `/explorer/` | the leaderboard and every model's plan on every eval task; pick one to watch it |
|
| 27 |
+
| `/twin/` | the 3D replay: each model's plan on every eval task, on the line's real track from OpenStreetMap, with signals, level crossings, closures, the train graph and the cost as it accrues |
|
| 28 |
| `/viewer/` | the train graph (time across, distance down) of any plan, with the plan's holds, short-turns and rule breaks |
|
| 29 |
| `/reset`, `/step`, `/state`, `/ws`, `/mcp` | OpenEnv |
|
| 30 |
| `/rail_ops/...` | OpenEnv Task API (`splits`, `num_tasks`, `task`, `task_range`) |
|
openenv/rail_openenv/web/explorer/index.html
CHANGED
|
@@ -220,7 +220,7 @@ function renderGrid() {
|
|
| 220 |
}).join("");
|
| 221 |
return `<tr><td class="task"><b>${esc(day(r.t.day))}</b> ${esc(r.t.start)}–${esc(r.t.end)} <span class="tier">${esc(TIER[r.t.difficulty] || r.t.difficulty)}</span><br><small>${esc(cause)}</small></td>`
|
| 222 |
+ `<td class="n">${r.t.runs}</td>${cells}<td class="n">${f3(r.mean)}</td>`
|
| 223 |
-
+ `<td><a href="/twin/?task=${encodeURIComponent(r.id)}
|
| 224 |
}).join("");
|
| 225 |
$("#grid").innerHTML = head + `<tbody>${body}</tbody>`;
|
| 226 |
for (const h of $("#grid").querySelectorAll("th.sort")) h.onclick = () => {
|
|
|
|
| 220 |
}).join("");
|
| 221 |
return `<tr><td class="task"><b>${esc(day(r.t.day))}</b> ${esc(r.t.start)}–${esc(r.t.end)} <span class="tier">${esc(TIER[r.t.difficulty] || r.t.difficulty)}</span><br><small>${esc(cause)}</small></td>`
|
| 222 |
+ `<td class="n">${r.t.runs}</td>${cells}<td class="n">${f3(r.mean)}</td>`
|
| 223 |
+
+ `<td><a href="/twin/?task=${encodeURIComponent(r.id)}">3D</a> · <a href="/viewer/?task=${encodeURIComponent(r.id)}&plan=optimal">graph</a></td></tr>`;
|
| 224 |
}).join("");
|
| 225 |
$("#grid").innerHTML = head + `<tbody>${body}</tbody>`;
|
| 226 |
for (const h of $("#grid").querySelectorAll("th.sort")) h.onclick = () => {
|
openenv/rail_openenv/web/twin/app.js
CHANGED
|
@@ -162,11 +162,14 @@ function seek(t) {
|
|
| 162 |
|
| 163 |
// --- loading a task and a plan ----------------------------------------------------------------------------
|
| 164 |
|
|
|
|
|
|
|
| 165 |
async function loadPlans(taskId, want) {
|
| 166 |
-
const
|
|
|
|
|
|
|
| 167 |
$("#plan").innerHTML = plans.map((p) => `<option value="${p.id}">${p.label}${p.reward !== null && p.reward !== undefined ? ` · ${(+p.reward).toFixed(3)}` : ""}</option>`).join("");
|
| 168 |
-
|
| 169 |
-
$("#plan").value = plans.some((p) => p.id === want) ? want : model ? model.id : "optimal";
|
| 170 |
}
|
| 171 |
|
| 172 |
async function loadReplay(keepTime) {
|
|
@@ -239,12 +242,13 @@ async function main() {
|
|
| 239 |
$("#loadmsg").textContent = "OpenStreetMap: track, stations, buildings…";
|
| 240 |
const [twin, tasks] = await Promise.all([loadTwin(), json("/api/tasks")]);
|
| 241 |
TWIN = twin;
|
| 242 |
-
const label = (t) => `${t.day} ${t.start}–${t.end} · ${TIER[t.difficulty] || t.difficulty} · ${t.runs} trains
|
| 243 |
-
|
| 244 |
-
|
| 245 |
-
|
|
|
|
| 246 |
const want = params.get("task");
|
| 247 |
-
$("#task").value =
|
| 248 |
$("#station").innerHTML += twin.stations.map((s) => `<option value="${s.code}">${s.name}</option>`).join("");
|
| 249 |
graph = new TrainGraph($("#graph"), $("#gtip"), (t) => seek(t), (u) => select(u, false));
|
| 250 |
cost = new CostChart($("#cost"), $("#ctip"), (t) => seek(t));
|
|
|
|
| 162 |
|
| 163 |
// --- loading a task and a plan ----------------------------------------------------------------------------
|
| 164 |
|
| 165 |
+
// the replay shows the models' plans (the eval runs) and live episodes on this server, not the reference methods
|
| 166 |
+
// (the CP-SAT optimum, the greedy dispatchers, change nothing); a server without model runs offers everything
|
| 167 |
async function loadPlans(taskId, want) {
|
| 168 |
+
const all = await json(`/api/tasks/${encodeURIComponent(taskId)}/plans`);
|
| 169 |
+
const models = all.filter((p) => p.id.startsWith("run:") || p.id.startsWith("episode:"));
|
| 170 |
+
const plans = models.length ? models : all;
|
| 171 |
$("#plan").innerHTML = plans.map((p) => `<option value="${p.id}">${p.label}${p.reward !== null && p.reward !== undefined ? ` · ${(+p.reward).toFixed(3)}` : ""}</option>`).join("");
|
| 172 |
+
$("#plan").value = plans.some((p) => p.id === want) ? want : plans[0].id;
|
|
|
|
| 173 |
}
|
| 174 |
|
| 175 |
async function loadReplay(keepTime) {
|
|
|
|
| 242 |
$("#loadmsg").textContent = "OpenStreetMap: track, stations, buildings…";
|
| 243 |
const [twin, tasks] = await Promise.all([loadTwin(), json("/api/tasks")]);
|
| 244 |
TWIN = twin;
|
| 245 |
+
const label = (t) => `${t.day} ${t.start}–${t.end} · ${TIER[t.difficulty] || t.difficulty} · ${t.runs} trains`;
|
| 246 |
+
// the eval tasks the models were run on; every task when this server has no model runs
|
| 247 |
+
const evals = tasks.filter((t) => t.split === "eval" && t.model_plans);
|
| 248 |
+
const shown = (evals.length ? evals : tasks).sort((a, b) => a.task_id.localeCompare(b.task_id));
|
| 249 |
+
$("#task").innerHTML = shown.map((t) => `<option value="${t.task_id}">${label(t)}</option>`).join("");
|
| 250 |
const want = params.get("task");
|
| 251 |
+
$("#task").value = shown.some((t) => t.task_id === want) ? want : shown.some((t) => t.task_id === FEATURED) ? FEATURED : shown[0].task_id;
|
| 252 |
$("#station").innerHTML += twin.stations.map((s) => `<option value="${s.code}">${s.name}</option>`).join("");
|
| 253 |
graph = new TrainGraph($("#graph"), $("#gtip"), (t) => seek(t), (u) => select(u, false));
|
| 254 |
cost = new CostChart($("#cost"), $("#ctip"), (t) => seek(t));
|