Spaces:
Runtime error
Runtime error
Update index.html
Browse files- index.html +431 -126
index.html
CHANGED
|
@@ -1,138 +1,443 @@
|
|
| 1 |
<!DOCTYPE html>
|
| 2 |
<html lang="en">
|
| 3 |
<head>
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
|
|
|
| 15 |
</head>
|
| 16 |
<body class="flex flex-col h-screen overflow-hidden">
|
| 17 |
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
</div>
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
<section class="bg-slate-900 border border-purple-900 p-3 rounded">
|
| 46 |
-
<h3 class="text-purple-400 font-bold text-[10px] mb-2">2. DATASET INJECTOR (THE ENVIRONMENT)</h3>
|
| 47 |
-
<select id="dataset" class="w-full bg-black border border-slate-700 p-2 text-white">
|
| 48 |
-
<option value="housing">Housing (Hidden Law: A*2.5 + B*1.2)</option>
|
| 49 |
-
<option value="subtraction">Subtraction (Hidden Law: A*1.0 + B*-1.0)</option>
|
| 50 |
-
<option value="multiplication">Factorization (Hidden Law: A * B)</option>
|
| 51 |
-
</select>
|
| 52 |
-
<button onclick="genData()" class="w-full bg-purple-700 mt-2 py-2 font-bold rounded">START DATA BATCH</button>
|
| 53 |
-
</section>
|
| 54 |
-
|
| 55 |
-
<button onclick="halt()" class="w-full border border-red-500 text-red-500 py-3 rounded font-bold">HALT ENGINE</button>
|
| 56 |
</div>
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
<div
|
|
|
|
|
|
|
|
|
|
| 68 |
</div>
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 137 |
</body>
|
| 138 |
</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.0" />
|
| 6 |
+
<title>Topological Engine Lab</title>
|
| 7 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 8 |
+
<script src="https://cdn.plot.ly/plotly-2.24.1.min.js"></script>
|
| 9 |
+
<style>
|
| 10 |
+
body { background: #06090e; color: #cbd5e1; font-family: monospace; overflow: hidden; }
|
| 11 |
+
.glass { background: rgba(15,23,42,0.96); border: 1px solid #334155; }
|
| 12 |
+
#drawer { transition: transform 0.3s ease-in-out; z-index: 100; }
|
| 13 |
+
.drawer-hidden { transform: translateY(100%); }
|
| 14 |
+
.panel-title { letter-spacing: 0.18em; text-transform: uppercase; }
|
| 15 |
+
</style>
|
| 16 |
</head>
|
| 17 |
<body class="flex flex-col h-screen overflow-hidden">
|
| 18 |
|
| 19 |
+
<header class="glass p-3 flex justify-between items-center z-10">
|
| 20 |
+
<div>
|
| 21 |
+
<h1 id="logic-label" class="text-blue-400 font-bold text-xs uppercase">TOPOLOGICAL ENGINE</h1>
|
| 22 |
+
<p id="sub-label" class="text-[10px] text-slate-500 mt-1">Ready</p>
|
| 23 |
+
</div>
|
| 24 |
+
<button onclick="toggleDrawer()" class="bg-blue-600 px-4 py-1 rounded text-white text-xs font-bold">
|
| 25 |
+
⚙️ SYSTEM DIALS
|
| 26 |
+
</button>
|
| 27 |
+
</header>
|
| 28 |
|
| 29 |
+
<aside id="drawer" class="fixed inset-x-0 bottom-0 drawer-hidden glass p-6 flex flex-col gap-5 z-50 max-h-[92vh] overflow-y-auto">
|
| 30 |
+
<div class="flex justify-between items-center border-b border-slate-700 pb-2">
|
| 31 |
+
<span class="text-orange-400 font-bold panel-title text-xs">LABORATORY CONTROLS</span>
|
| 32 |
+
<button onclick="toggleDrawer()" class="text-slate-400 text-2xl">✕</button>
|
| 33 |
+
</div>
|
| 34 |
+
|
| 35 |
+
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
| 36 |
+
<section class="bg-slate-900 border border-blue-900 p-3 rounded">
|
| 37 |
+
<h3 class="text-blue-400 font-bold text-[10px] mb-2 panel-title">1. ARCHITECTURE</h3>
|
| 38 |
+
<select id="architecture" class="w-full bg-black border border-slate-700 p-2 text-white rounded">
|
| 39 |
+
<option value="additive">Additive</option>
|
| 40 |
+
<option value="multiplicative">Multiplicative</option>
|
| 41 |
+
<option value="affine">Affine</option>
|
| 42 |
+
<option value="bilinear">Bilinear</option>
|
| 43 |
+
<option value="gated">Gated</option>
|
| 44 |
+
</select>
|
| 45 |
+
|
| 46 |
+
<select id="coeff_mode" class="w-full mt-2 bg-black border border-slate-700 p-2 text-white rounded">
|
| 47 |
+
<option value="single_k">Single K</option>
|
| 48 |
+
<option value="triple_k">Triple K</option>
|
| 49 |
+
<option value="per_edge_k">Per Edge K</option>
|
| 50 |
+
</select>
|
| 51 |
+
|
| 52 |
+
<select id="topology" class="w-full mt-2 bg-black border border-slate-700 p-2 text-white rounded">
|
| 53 |
+
<option value="single_cell">Single Cell</option>
|
| 54 |
+
<option value="chain">Chain</option>
|
| 55 |
+
<option value="mesh">Mesh</option>
|
| 56 |
+
</select>
|
| 57 |
+
|
| 58 |
+
<select id="mode" class="w-full mt-2 bg-black border border-slate-700 p-2 text-white rounded">
|
| 59 |
+
<option value="training">Training</option>
|
| 60 |
+
<option value="inference">Inference</option>
|
| 61 |
+
</select>
|
| 62 |
+
|
| 63 |
+
<div class="grid grid-cols-2 gap-2 mt-2">
|
| 64 |
+
<input id="num_cells" type="number" min="1" value="4" class="bg-black border border-slate-700 p-2 text-white rounded" />
|
| 65 |
+
<input id="batch_count" type="number" min="1" value="24" class="bg-black border border-slate-700 p-2 text-white rounded" />
|
| 66 |
+
</div>
|
| 67 |
+
|
| 68 |
+
<div class="grid grid-cols-3 gap-2 mt-2">
|
| 69 |
+
<input id="learning_rate" type="number" step="0.001" value="0.01" class="bg-black border border-slate-700 p-2 text-white rounded" />
|
| 70 |
+
<input id="coupling" type="number" step="0.001" value="0.05" class="bg-black border border-slate-700 p-2 text-white rounded" />
|
| 71 |
+
<input id="damping" type="number" step="0.001" value="0.12" class="bg-black border border-slate-700 p-2 text-white rounded" />
|
| 72 |
+
</div>
|
| 73 |
+
|
| 74 |
+
<button onclick="applyConfig()" class="w-full bg-blue-700 mt-3 py-2 font-bold rounded text-white">APPLY PHYSICS</button>
|
| 75 |
+
</section>
|
| 76 |
+
|
| 77 |
+
<section class="bg-slate-900 border border-purple-900 p-3 rounded">
|
| 78 |
+
<h3 class="text-purple-400 font-bold text-[10px] mb-2 panel-title">2. DATASET</h3>
|
| 79 |
+
<select id="dataset_family" class="w-full bg-black border border-slate-700 p-2 text-white rounded">
|
| 80 |
+
<option value="housing">Housing</option>
|
| 81 |
+
<option value="subtraction">Subtraction</option>
|
| 82 |
+
<option value="multiplication">Multiplication</option>
|
| 83 |
+
<option value="symbolic">Symbolic</option>
|
| 84 |
+
<option value="mixed">Mixed</option>
|
| 85 |
+
</select>
|
| 86 |
+
|
| 87 |
+
<button onclick="previewExample()" class="w-full bg-purple-700 mt-3 py-2 font-bold rounded text-white">GENERATE EXAMPLE</button>
|
| 88 |
+
<button onclick="startBatch()" class="w-full bg-indigo-700 mt-2 py-2 font-bold rounded text-white">START BATCH</button>
|
| 89 |
+
|
| 90 |
+
<div class="mt-3 p-3 rounded border border-slate-700 bg-black/40 text-[11px] space-y-1">
|
| 91 |
+
<div class="text-slate-400 panel-title text-[10px]">EXAMPLE PREVIEW</div>
|
| 92 |
+
<div id="example-view" class="text-slate-300">No sample loaded.</div>
|
| 93 |
</div>
|
| 94 |
+
</section>
|
| 95 |
+
|
| 96 |
+
<section class="bg-slate-900 border border-cyan-900 p-3 rounded">
|
| 97 |
+
<h3 class="text-cyan-400 font-bold text-[10px] mb-2 panel-title">3. CUSTOM INPUTS</h3>
|
| 98 |
+
<div class="grid grid-cols-3 gap-2">
|
| 99 |
+
<input id="custom_a" type="number" step="0.01" value="7" class="bg-black border border-slate-700 p-2 text-white rounded" placeholder="A" />
|
| 100 |
+
<input id="custom_b" type="number" step="0.01" value="8" class="bg-black border border-slate-700 p-2 text-white rounded" placeholder="B" />
|
| 101 |
+
<input id="custom_c" type="number" step="0.01" class="bg-black border border-slate-700 p-2 text-white rounded" placeholder="C target" />
|
| 102 |
+
</div>
|
| 103 |
+
<button onclick="runCustom()" class="w-full bg-cyan-700 mt-3 py-2 font-bold rounded text-white">RUN CUSTOM</button>
|
| 104 |
+
</section>
|
| 105 |
+
|
| 106 |
+
<section class="bg-slate-900 border border-red-900 p-3 rounded flex flex-col justify-between">
|
| 107 |
+
<h3 class="text-red-400 font-bold text-[10px] mb-2 panel-title">4. CONTROL</h3>
|
| 108 |
+
<button onclick="halt()" class="w-full border border-red-500 text-red-400 py-3 rounded font-bold">HALT ENGINE</button>
|
| 109 |
+
<div class="mt-3 text-[11px] text-slate-500">
|
| 110 |
+
Batch count and configuration are independent. The same data family can be tested under different physics.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 111 |
</div>
|
| 112 |
+
</section>
|
| 113 |
+
</div>
|
| 114 |
+
</aside>
|
| 115 |
+
|
| 116 |
+
<main class="flex-grow flex flex-col min-h-0">
|
| 117 |
+
<div class="flex flex-col xl:flex-row flex-grow min-h-0">
|
| 118 |
+
<div class="flex-1 min-h-[320px]" id="plot"></div>
|
| 119 |
+
<div class="xl:w-[34rem] w-full glass border-l border-slate-800 p-4 overflow-y-auto">
|
| 120 |
+
<div class="flex justify-between items-center mb-3 border-b border-slate-800 pb-2">
|
| 121 |
+
<div>
|
| 122 |
+
<div class="text-blue-300 text-[10px] font-bold panel-title">LIVE STATUS</div>
|
| 123 |
+
<div id="status-line" class="text-[11px] text-slate-400 mt-1">Waiting...</div>
|
| 124 |
+
</div>
|
| 125 |
+
<div id="error-val" class="text-sm font-bold text-red-400">ERR: 0.000</div>
|
| 126 |
</div>
|
| 127 |
+
|
| 128 |
+
<div id="summary-box" class="grid grid-cols-2 gap-2 text-[11px] mb-4"></div>
|
| 129 |
+
|
| 130 |
+
<div class="mb-4">
|
| 131 |
+
<div class="text-[10px] text-slate-500 panel-title mb-2">CELL STATE</div>
|
| 132 |
+
<div id="cells-ui" class="space-y-2 text-[11px] font-mono"></div>
|
| 133 |
+
</div>
|
| 134 |
+
|
| 135 |
+
<div class="mb-4">
|
| 136 |
+
<div class="text-[10px] text-slate-500 panel-title mb-2">LOSS HISTORY</div>
|
| 137 |
+
<div id="loss-plot" class="h-56"></div>
|
| 138 |
+
</div>
|
| 139 |
+
|
| 140 |
+
<div>
|
| 141 |
+
<div class="text-[10px] text-slate-500 panel-title mb-2">LOGS</div>
|
| 142 |
+
<div id="logs" class="mt-auto pt-2 border-t border-slate-800 text-[10px] text-slate-500 h-44 overflow-y-auto space-y-1"></div>
|
| 143 |
+
</div>
|
| 144 |
+
</div>
|
| 145 |
+
</div>
|
| 146 |
+
</main>
|
| 147 |
+
|
| 148 |
+
<script>
|
| 149 |
+
const state = {
|
| 150 |
+
plotted: false,
|
| 151 |
+
lossPlotted: false,
|
| 152 |
+
example: null,
|
| 153 |
+
historyLoss: [],
|
| 154 |
+
historyError: []
|
| 155 |
+
};
|
| 156 |
+
|
| 157 |
+
function toggleDrawer() {
|
| 158 |
+
document.getElementById('drawer').classList.toggle('drawer-hidden');
|
| 159 |
+
}
|
| 160 |
+
|
| 161 |
+
function readConfig() {
|
| 162 |
+
return {
|
| 163 |
+
architecture: document.getElementById('architecture').value,
|
| 164 |
+
coeff_mode: document.getElementById('coeff_mode').value,
|
| 165 |
+
topology: document.getElementById('topology').value,
|
| 166 |
+
dataset_family: document.getElementById('dataset_family').value,
|
| 167 |
+
mode: document.getElementById('mode').value,
|
| 168 |
+
num_cells: parseInt(document.getElementById('num_cells').value || '1', 10),
|
| 169 |
+
batch_size: parseInt(document.getElementById('batch_count').value || '24', 10),
|
| 170 |
+
learning_rate: parseFloat(document.getElementById('learning_rate').value || '0.01'),
|
| 171 |
+
coupling: parseFloat(document.getElementById('coupling').value || '0.05'),
|
| 172 |
+
damping: parseFloat(document.getElementById('damping').value || '0.12'),
|
| 173 |
+
};
|
| 174 |
+
}
|
| 175 |
+
|
| 176 |
+
function setHeaderFromConfig(cfg) {
|
| 177 |
+
document.getElementById('logic-label').innerText =
|
| 178 |
+
`TOPOLOGICAL ENGINE | ${cfg.architecture.toUpperCase()} | ${cfg.coeff_mode.toUpperCase()} | ${cfg.topology.toUpperCase()}`;
|
| 179 |
+
document.getElementById('sub-label').innerText =
|
| 180 |
+
`${cfg.dataset_family.toUpperCase()} / ${cfg.mode.toUpperCase()}`;
|
| 181 |
+
}
|
| 182 |
+
|
| 183 |
+
async function applyConfig() {
|
| 184 |
+
const cfg = readConfig();
|
| 185 |
+
setHeaderFromConfig(cfg);
|
| 186 |
+
|
| 187 |
+
await fetch('/config', {
|
| 188 |
+
method: 'POST',
|
| 189 |
+
headers: {'Content-Type': 'application/json'},
|
| 190 |
+
body: JSON.stringify(cfg)
|
| 191 |
+
});
|
| 192 |
+
|
| 193 |
+
await previewExample(false);
|
| 194 |
+
toggleDrawer();
|
| 195 |
+
}
|
| 196 |
+
|
| 197 |
+
async function previewExample(fillInputs = true) {
|
| 198 |
+
const cfg = readConfig();
|
| 199 |
+
const res = await fetch('/example', {
|
| 200 |
+
method: 'POST',
|
| 201 |
+
headers: {'Content-Type': 'application/json'},
|
| 202 |
+
body: JSON.stringify(cfg)
|
| 203 |
+
});
|
| 204 |
+
const sample = await res.json();
|
| 205 |
+
state.example = sample;
|
| 206 |
+
|
| 207 |
+
const ex = document.getElementById('example-view');
|
| 208 |
+
ex.innerHTML = `
|
| 209 |
+
<div class="text-slate-200">a: <b>${sample.a.toFixed(3)}</b></div>
|
| 210 |
+
<div class="text-slate-200">b: <b>${sample.b.toFixed(3)}</b></div>
|
| 211 |
+
<div class="text-slate-200">c: <b>${sample.c.toFixed(3)}</b></div>
|
| 212 |
+
<div class="text-slate-400">label: ${sample.label}</div>
|
| 213 |
+
`;
|
| 214 |
+
|
| 215 |
+
if (fillInputs) {
|
| 216 |
+
document.getElementById('custom_a').value = sample.a.toFixed(3);
|
| 217 |
+
document.getElementById('custom_b').value = sample.b.toFixed(3);
|
| 218 |
+
document.getElementById('custom_c').value = sample.c.toFixed(3);
|
| 219 |
+
}
|
| 220 |
+
}
|
| 221 |
+
|
| 222 |
+
async function startBatch() {
|
| 223 |
+
const cfg = readConfig();
|
| 224 |
+
await fetch('/config', {
|
| 225 |
+
method: 'POST',
|
| 226 |
+
headers: {'Content-Type': 'application/json'},
|
| 227 |
+
body: JSON.stringify(cfg)
|
| 228 |
+
});
|
| 229 |
+
await fetch('/generate_batch', {
|
| 230 |
+
method: 'POST',
|
| 231 |
+
headers: {'Content-Type': 'application/json'},
|
| 232 |
+
body: JSON.stringify({ count: cfg.batch_size })
|
| 233 |
+
});
|
| 234 |
+
toggleDrawer();
|
| 235 |
+
}
|
| 236 |
+
|
| 237 |
+
async function runCustom() {
|
| 238 |
+
const a = document.getElementById('custom_a').value;
|
| 239 |
+
const b = document.getElementById('custom_b').value;
|
| 240 |
+
const c = document.getElementById('custom_c').value;
|
| 241 |
+
|
| 242 |
+
await fetch('/test_custom', {
|
| 243 |
+
method: 'POST',
|
| 244 |
+
headers: {'Content-Type': 'application/json'},
|
| 245 |
+
body: JSON.stringify({ a, b, c: c === '' ? null : c })
|
| 246 |
+
});
|
| 247 |
+
toggleDrawer();
|
| 248 |
+
}
|
| 249 |
+
|
| 250 |
+
async function halt() {
|
| 251 |
+
await fetch('/halt', { method: 'POST' });
|
| 252 |
+
toggleDrawer();
|
| 253 |
+
}
|
| 254 |
+
|
| 255 |
+
function fmt(n) {
|
| 256 |
+
if (n === null || n === undefined || Number.isNaN(n)) return '—';
|
| 257 |
+
return Number(n).toFixed(4);
|
| 258 |
+
}
|
| 259 |
+
|
| 260 |
+
function renderSummary(d) {
|
| 261 |
+
const cfg = d.config;
|
| 262 |
+
const sample = d.current_sample || {};
|
| 263 |
+
const last = d.last_sample || sample;
|
| 264 |
+
|
| 265 |
+
const items = [
|
| 266 |
+
['Mode', cfg.mode],
|
| 267 |
+
['Arch', cfg.architecture],
|
| 268 |
+
['Coeffs', cfg.coeff_mode],
|
| 269 |
+
['Topology', cfg.topology],
|
| 270 |
+
['Dataset', cfg.dataset_family],
|
| 271 |
+
['Batch left', d.batch_remaining],
|
| 272 |
+
['Iteration', d.iteration],
|
| 273 |
+
['Sample', last.label || '—'],
|
| 274 |
+
['Error', fmt(d.current_error)],
|
| 275 |
+
['Loss', fmt(d.current_loss)],
|
| 276 |
+
['A', sample.a !== undefined ? fmt(sample.a) : '—'],
|
| 277 |
+
['B', sample.b !== undefined ? fmt(sample.b) : '—'],
|
| 278 |
+
];
|
| 279 |
+
|
| 280 |
+
document.getElementById('summary-box').innerHTML = items.map(([k, v]) => `
|
| 281 |
+
<div class="bg-black/40 border border-slate-800 rounded p-2">
|
| 282 |
+
<div class="text-[9px] text-slate-500 panel-title">${k}</div>
|
| 283 |
+
<div class="text-[12px] text-slate-100 mt-1">${v}</div>
|
| 284 |
+
</div>
|
| 285 |
+
`).join('');
|
| 286 |
+
}
|
| 287 |
+
|
| 288 |
+
function renderCells(d) {
|
| 289 |
+
const cells = d.cells || [];
|
| 290 |
+
document.getElementById('cells-ui').innerHTML = cells.map(cell => `
|
| 291 |
+
<div class="border border-slate-800 rounded p-3 bg-black/30">
|
| 292 |
+
<div class="flex justify-between items-center mb-1">
|
| 293 |
+
<div class="text-sky-300 font-bold">CELL ${cell.id} ${cell.anchored ? '[ANCHORED]' : '[DRIFTING]'}</div>
|
| 294 |
+
<div class="text-slate-400">label: ${cell.label || '—'}</div>
|
| 295 |
+
</div>
|
| 296 |
+
<div class="grid grid-cols-2 gap-x-3 gap-y-1">
|
| 297 |
+
<div>A: <span class="text-white">${fmt(cell.a)}</span></div>
|
| 298 |
+
<div>B: <span class="text-white">${fmt(cell.b)}</span></div>
|
| 299 |
+
<div>C: <span class="text-white">${fmt(cell.c)}</span></div>
|
| 300 |
+
<div>T: <span class="text-white">${cell.target !== null ? fmt(cell.target) : '—'}</span></div>
|
| 301 |
+
<div>P: <span class="text-white">${fmt(cell.prediction)}</span></div>
|
| 302 |
+
<div>E: <span class="text-white">${fmt(cell.error)}</span></div>
|
| 303 |
+
<div>Energy: <span class="text-white">${fmt(cell.energy)}</span></div>
|
| 304 |
+
<div>Force: <span class="text-white">${fmt(cell.force)}</span></div>
|
| 305 |
+
</div>
|
| 306 |
+
<div class="mt-2 flex gap-3 text-[10px] text-purple-300">
|
| 307 |
+
<div>k: ${fmt(cell.k)}</div>
|
| 308 |
+
<div>ka: ${fmt(cell.ka)}</div>
|
| 309 |
+
<div>kb: ${fmt(cell.kb)}</div>
|
| 310 |
+
<div>kc: ${fmt(cell.kc)}</div>
|
| 311 |
+
</div>
|
| 312 |
+
</div>
|
| 313 |
+
`).join('');
|
| 314 |
+
}
|
| 315 |
+
|
| 316 |
+
function renderLogs(d) {
|
| 317 |
+
document.getElementById('logs').innerHTML = (d.logs || []).map(l => `<div>${l}</div>`).join('');
|
| 318 |
+
}
|
| 319 |
+
|
| 320 |
+
function renderTopPlot(d) {
|
| 321 |
+
const cells = d.cells || [];
|
| 322 |
+
const xsPred = cells.map(c => c.prediction);
|
| 323 |
+
const ys = cells.map(c => c.id);
|
| 324 |
+
const zsErr = cells.map(c => c.error);
|
| 325 |
+
const labels = cells.map(c => `cell ${c.id}`);
|
| 326 |
+
|
| 327 |
+
const xsTarget = cells.map(c => c.target !== null ? c.target : null).filter(v => v !== null);
|
| 328 |
+
const ysTarget = cells.map(c => c.target !== null ? c.id : null).filter(v => v !== null);
|
| 329 |
+
const zsTarget = cells.map(() => 0).slice(0, xsTarget.length);
|
| 330 |
+
|
| 331 |
+
const trace1 = {
|
| 332 |
+
type: 'scatter3d',
|
| 333 |
+
mode: 'lines+markers+text',
|
| 334 |
+
x: xsPred,
|
| 335 |
+
y: ys,
|
| 336 |
+
z: zsErr,
|
| 337 |
+
text: labels,
|
| 338 |
+
textposition: 'top center',
|
| 339 |
+
marker: { size: 7 },
|
| 340 |
+
line: { width: 3 }
|
| 341 |
+
};
|
| 342 |
+
|
| 343 |
+
const trace2 = {
|
| 344 |
+
type: 'scatter3d',
|
| 345 |
+
mode: 'markers',
|
| 346 |
+
x: xsTarget,
|
| 347 |
+
y: ysTarget,
|
| 348 |
+
z: zsTarget,
|
| 349 |
+
marker: { size: 5, symbol: 'circle' }
|
| 350 |
+
};
|
| 351 |
+
|
| 352 |
+
const layout = {
|
| 353 |
+
margin: { l: 0, r: 0, t: 0, b: 0 },
|
| 354 |
+
paper_bgcolor: 'transparent',
|
| 355 |
+
plot_bgcolor: 'transparent',
|
| 356 |
+
scene: {
|
| 357 |
+
xaxis: { title: 'Prediction / C', color: '#475569', gridcolor: '#1e293b' },
|
| 358 |
+
yaxis: { title: 'Cell index', color: '#475569', gridcolor: '#1e293b' },
|
| 359 |
+
zaxis: { title: 'Error', color: '#475569', gridcolor: '#1e293b' },
|
| 360 |
+
camera: { eye: { x: 0.9, y: -1.8, z: 0.8 } }
|
| 361 |
+
},
|
| 362 |
+
showlegend: false
|
| 363 |
+
};
|
| 364 |
+
|
| 365 |
+
if (!window.topPlotted) {
|
| 366 |
+
Plotly.newPlot('plot', [trace1, trace2], layout, { displayModeBar: false, responsive: true });
|
| 367 |
+
window.topPlotted = true;
|
| 368 |
+
} else {
|
| 369 |
+
Plotly.react('plot', [trace1, trace2], layout, { displayModeBar: false, responsive: true });
|
| 370 |
+
}
|
| 371 |
+
}
|
| 372 |
+
|
| 373 |
+
function renderLossPlot(d) {
|
| 374 |
+
const loss = d.loss_history || [];
|
| 375 |
+
const err = d.error_history || [];
|
| 376 |
+
const x = loss.map((_, i) => i);
|
| 377 |
+
|
| 378 |
+
const lossTrace = {
|
| 379 |
+
type: 'scatter',
|
| 380 |
+
mode: 'lines',
|
| 381 |
+
x: x,
|
| 382 |
+
y: loss,
|
| 383 |
+
name: 'loss'
|
| 384 |
+
};
|
| 385 |
+
|
| 386 |
+
const errTrace = {
|
| 387 |
+
type: 'scatter',
|
| 388 |
+
mode: 'lines',
|
| 389 |
+
x: x,
|
| 390 |
+
y: err,
|
| 391 |
+
name: 'error'
|
| 392 |
+
};
|
| 393 |
+
|
| 394 |
+
const layout = {
|
| 395 |
+
margin: { l: 35, r: 10, t: 10, b: 30 },
|
| 396 |
+
paper_bgcolor: 'transparent',
|
| 397 |
+
plot_bgcolor: 'transparent',
|
| 398 |
+
xaxis: { color: '#94a3b8', gridcolor: '#1e293b' },
|
| 399 |
+
yaxis: { color: '#94a3b8', gridcolor: '#1e293b' },
|
| 400 |
+
showlegend: true,
|
| 401 |
+
legend: { orientation: 'h' }
|
| 402 |
+
};
|
| 403 |
+
|
| 404 |
+
if (!window.lossPlotted) {
|
| 405 |
+
Plotly.newPlot('loss-plot', [lossTrace, errTrace], layout, { displayModeBar: false, responsive: true });
|
| 406 |
+
window.lossPlotted = true;
|
| 407 |
+
} else {
|
| 408 |
+
Plotly.react('loss-plot', [lossTrace, errTrace], layout, { displayModeBar: false, responsive: true });
|
| 409 |
+
}
|
| 410 |
+
}
|
| 411 |
+
|
| 412 |
+
async function tick() {
|
| 413 |
+
try {
|
| 414 |
+
const res = await fetch('/state');
|
| 415 |
+
const d = await res.json();
|
| 416 |
+
|
| 417 |
+
document.getElementById('error-val').innerText = 'ERR: ' + fmt(d.current_error);
|
| 418 |
+
document.getElementById('error-val').className =
|
| 419 |
+
Math.abs(d.current_error) < 0.05 ? 'text-green-400 font-bold' : 'text-red-400 font-bold';
|
| 420 |
+
|
| 421 |
+
document.getElementById('status-line').innerText =
|
| 422 |
+
d.running ? 'Engine running...' : 'Engine idle.';
|
| 423 |
+
|
| 424 |
+
renderSummary(d);
|
| 425 |
+
renderCells(d);
|
| 426 |
+
renderLogs(d);
|
| 427 |
+
renderTopPlot(d);
|
| 428 |
+
renderLossPlot(d);
|
| 429 |
+
} catch (e) {
|
| 430 |
+
document.getElementById('status-line').innerText = 'Disconnected.';
|
| 431 |
+
}
|
| 432 |
+
}
|
| 433 |
+
|
| 434 |
+
// initial example + first config sync
|
| 435 |
+
(async () => {
|
| 436 |
+
const cfg = readConfig();
|
| 437 |
+
setHeaderFromConfig(cfg);
|
| 438 |
+
await previewExample(false);
|
| 439 |
+
setInterval(tick, 180);
|
| 440 |
+
})();
|
| 441 |
+
</script>
|
| 442 |
</body>
|
| 443 |
</html>
|