UX overhaul: loading banner, guardrails, density readout, paper links, 2D/3D note, mobile responsive, health endpoint, pre-filled examples
Browse files- experiments/demo_server.py +43 -8
experiments/demo_server.py
CHANGED
|
@@ -297,6 +297,7 @@ PAGE = r"""<!doctype html>
|
|
| 297 |
textarea{min-height:84px;resize:vertical}
|
| 298 |
input:focus,textarea:focus{outline:2px solid #cdd8f8;border-color:var(--acc)}
|
| 299 |
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:14px}
|
|
|
|
| 300 |
@media(max-width:760px){.grid2{grid-template-columns:1fr}}
|
| 301 |
button{background:var(--ink);color:#fff;border:0;border-radius:999px;padding:10px 22px;font-size:14px;
|
| 302 |
font-weight:600;cursor:pointer;margin-top:14px}
|
|
@@ -335,7 +336,8 @@ PAGE = r"""<!doctype html>
|
|
| 335 |
stays constant. Measured: recall of 1.0000 at 8,192 pairs; 0.9980 on overwrite
|
| 336 |
queries; 1.0000 on real-text retrieval at 259K tokens. This page runs three
|
| 337 |
trained checkpoints. Every number is a live forward pass.</p>
|
| 338 |
-
<div class="meta" id="meta">Tensorbend Research · Eric E. · October 2026
|
|
|
|
| 339 |
</header>
|
| 340 |
<main>
|
| 341 |
|
|
@@ -366,7 +368,7 @@ PAGE = r"""<!doctype html>
|
|
| 366 |
</section>
|
| 367 |
|
| 368 |
<section>
|
| 369 |
-
<div class="sn"><span class="n">02</span><h2 class="serif">The store at scale</h2></div>
|
| 370 |
<p class="lead">The same mechanism at scale: store up to 8,192 pairs in one 133,120-token
|
| 371 |
causal pass, overwrite half of them, then query. Measured recall: 1.0000.</p>
|
| 372 |
<div class="fig">
|
|
@@ -392,7 +394,7 @@ PAGE = r"""<!doctype html>
|
|
| 392 |
</section>
|
| 393 |
|
| 394 |
<section>
|
| 395 |
-
<div class="sn"><span class="n">03</span><h2 class="serif">Constant cost while memory grows</h2></div>
|
| 396 |
<p class="lead">Each token touches exactly nine memory cells, so per-token work cannot grow with
|
| 397 |
context. Measure it: the curve below runs the model at increasing stream lengths, live.</p>
|
| 398 |
<div class="fig">
|
|
@@ -404,7 +406,7 @@ PAGE = r"""<!doctype html>
|
|
| 404 |
</section>
|
| 405 |
|
| 406 |
<section>
|
| 407 |
-
<div class="sn"><span class="n">04</span><h2 class="serif">Inside one cell</h2></div>
|
| 408 |
<p class="lead">Where does a value physically live, and where does the <em>new</em> value go on
|
| 409 |
overwrite? Pick one fact from section 01 (or any name/value). The model’s learned address
|
| 410 |
for that key, the 3×3 cells it touches, and the before/after answers — same cells,
|
|
@@ -426,6 +428,21 @@ PAGE = r"""<!doctype html>
|
|
| 426 |
</div>
|
| 427 |
</section>
|
| 428 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 429 |
</main>
|
| 430 |
<footer>Every number on this page is produced by a live forward pass of
|
| 431 |
<code>capacity8k.pt</code> on request — timestamped per run. Filler for section 01 is your own
|
|
@@ -474,7 +491,14 @@ $("runc").onclick=async()=>{$("runc").disabled=true;$("runc").textContent="readi
|
|
| 474 |
/* section 02 */
|
| 475 |
$("np").oninput=e=>$("npv").textContent=e.target.value;
|
| 476 |
$("fl").oninput=e=>$("flv").textContent=e.target.value;
|
| 477 |
-
$("ow").oninput=e=>$("owv").textContent=e.target.value+"%";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 478 |
function drawLatt(pts,sc){const c=$("latt"),x=c.getContext("2d");
|
| 479 |
c.width=c.clientWidth*2;c.height=560;x.scale(2,2);const W=c.width/2,H=280;
|
| 480 |
x.fillStyle="#fff";x.fillRect(0,0,W,H);
|
|
@@ -577,6 +601,9 @@ class H(BaseHTTPRequestHandler):
|
|
| 577 |
self.wfile.write(body)
|
| 578 |
elif path == "/favicon.ico":
|
| 579 |
self.send_response(204); self.end_headers()
|
|
|
|
|
|
|
|
|
|
| 580 |
else:
|
| 581 |
self.send_error(404)
|
| 582 |
|
|
@@ -585,7 +612,8 @@ class H(BaseHTTPRequestHandler):
|
|
| 585 |
req = json.loads(self.rfile.read(n) or b"{}")
|
| 586 |
try:
|
| 587 |
if self.path == "/api/store":
|
| 588 |
-
|
|
|
|
| 589 |
float(req.get("overwrite_frac", 0.5)), int(req.get("seed", 0)))
|
| 590 |
self._json(r)
|
| 591 |
elif self.path == "/api/cost":
|
|
@@ -596,8 +624,14 @@ class H(BaseHTTPRequestHandler):
|
|
| 596 |
str(req.get("new_value", "")),
|
| 597 |
int(req.get("seed", 0))))
|
| 598 |
elif self.path == "/api/custom":
|
| 599 |
-
|
| 600 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 601 |
self._json(r)
|
| 602 |
else:
|
| 603 |
self.send_error(404)
|
|
@@ -614,5 +648,6 @@ if __name__ == "__main__":
|
|
| 614 |
# speculative idle connections (page "loads once, then never again").
|
| 615 |
srv = ThreadingHTTPServer(("0.0.0.0", port), H)
|
| 616 |
srv.daemon_threads = True
|
|
|
|
| 617 |
print(f"demo on http://0.0.0.0:{port}/", flush=True)
|
| 618 |
srv.serve_forever()
|
|
|
|
| 297 |
textarea{min-height:84px;resize:vertical}
|
| 298 |
input:focus,textarea:focus{outline:2px solid #cdd8f8;border-color:var(--acc)}
|
| 299 |
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:14px}
|
| 300 |
+
@media(max-width:640px){.grid2{grid-template-columns:1fr}.row{flex-direction:column;align-items:stretch}.rangewrap{width:100%}}
|
| 301 |
@media(max-width:760px){.grid2{grid-template-columns:1fr}}
|
| 302 |
button{background:var(--ink);color:#fff;border:0;border-radius:999px;padding:10px 22px;font-size:14px;
|
| 303 |
font-weight:600;cursor:pointer;margin-top:14px}
|
|
|
|
| 336 |
stays constant. Measured: recall of 1.0000 at 8,192 pairs; 0.9980 on overwrite
|
| 337 |
queries; 1.0000 on real-text retrieval at 259K tokens. This page runs three
|
| 338 |
trained checkpoints. Every number is a live forward pass.</p>
|
| 339 |
+
<div class="meta" id="meta">Tensorbend Research · Eric E. · October 2026 ·
|
| 340 |
+
<span id="status"><b style="color:#0e8a5f">Models loaded</b> · content-addressed associative mixer (not a language model)</span></div>
|
| 341 |
</header>
|
| 342 |
<main>
|
| 343 |
|
|
|
|
| 368 |
</section>
|
| 369 |
|
| 370 |
<section>
|
| 371 |
+
<div class="sn"><span class="n">02</span><h2 class="serif">The store at scale <a href="https://github.com/eelbaz/mLattice/blob/main/PAPER.md#42-results" style="font-size:14px;color:#2547d0;text-decoration:none">↗</a></h2></div>
|
| 372 |
<p class="lead">The same mechanism at scale: store up to 8,192 pairs in one 133,120-token
|
| 373 |
causal pass, overwrite half of them, then query. Measured recall: 1.0000.</p>
|
| 374 |
<div class="fig">
|
|
|
|
| 394 |
</section>
|
| 395 |
|
| 396 |
<section>
|
| 397 |
+
<div class="sn"><span class="n">03</span><h2 class="serif">Constant cost while memory grows <a href="https://github.com/eelbaz/mLattice/blob/main/PAPER.md#43-cost-measurements-head-to-head-with-attention" style="font-size:14px;color:#2547d0;text-decoration:none">↗</a></h2></div>
|
| 398 |
<p class="lead">Each token touches exactly nine memory cells, so per-token work cannot grow with
|
| 399 |
context. Measure it: the curve below runs the model at increasing stream lengths, live.</p>
|
| 400 |
<div class="fig">
|
|
|
|
| 406 |
</section>
|
| 407 |
|
| 408 |
<section>
|
| 409 |
+
<div class="sn"><span class="n">04</span><h2 class="serif">Inside one cell <a href="https://github.com/eelbaz/mLattice/blob/main/PAPER.md#31-architecture" style="font-size:14px;color:#2547d0;text-decoration:none">↗</a></h2></div>
|
| 410 |
<p class="lead">Where does a value physically live, and where does the <em>new</em> value go on
|
| 411 |
overwrite? Pick one fact from section 01 (or any name/value). The model’s learned address
|
| 412 |
for that key, the 3×3 cells it touches, and the before/after answers — same cells,
|
|
|
|
| 428 |
</div>
|
| 429 |
</section>
|
| 430 |
|
| 431 |
+
<section>
|
| 432 |
+
<div class="sn"><span class="n">05</span><h2 class="serif">Notes</h2></div>
|
| 433 |
+
<div class="fig">
|
| 434 |
+
<p class="lead" style="font-size:14px">
|
| 435 |
+
This is a <b>content-addressed associative mixer</b>, not a language model.
|
| 436 |
+
It stores key→value associations and retrieves them at constant per-token cost.
|
| 437 |
+
Perfect scores are on the synthetic MQAR distribution (see
|
| 438 |
+
<a href="https://github.com/eelbaz/mLattice/blob/main/PAPER.md" style="color:#2547d0">PAPER.md</a>).<br><br>
|
| 439 |
+
Current demo is <b>2D</b> (9-cell neighborhood per token).
|
| 440 |
+
<b>3D</b> (27 cells) is supported by the kernel math without architectural change —
|
| 441 |
+
it reduces key density by 1000× and raises the estimated capacity from ~8K to ~495K keys
|
| 442 |
+
(<a href="https://github.com/eelbaz/mLattice/blob/main/PAPER.md#47-address-space-scaling-3d-analysis" style="color:#2547d0">details</a>).
|
| 443 |
+
</p>
|
| 444 |
+
</div>
|
| 445 |
+
</section>
|
| 446 |
</main>
|
| 447 |
<footer>Every number on this page is produced by a live forward pass of
|
| 448 |
<code>capacity8k.pt</code> on request — timestamped per run. Filler for section 01 is your own
|
|
|
|
| 491 |
/* section 02 */
|
| 492 |
$("np").oninput=e=>$("npv").textContent=e.target.value;
|
| 493 |
$("fl").oninput=e=>$("flv").textContent=e.target.value;
|
| 494 |
+
$("ow").oninput=e=>{$("owv").textContent=e.target.value+"%";updDensity()};
|
| 495 |
+
$("np").oninput=e=>{$("npv").textContent=e.target.value;updDensity()};
|
| 496 |
+
function updDensity(){
|
| 497 |
+
const n=+$("np").value, cells=38025, d=n/cells;
|
| 498 |
+
const el=$("density_note"); if(!el)return;
|
| 499 |
+
if(d>0.25){el.innerHTML=`<span style="color:#c2413b">density ${d.toFixed(3)} keys/cell — above the 0.25 ceiling</span>`}
|
| 500 |
+
else{el.innerHTML=`density ${d.toFixed(3)} keys/cell`}}
|
| 501 |
+
updDensity();
|
| 502 |
function drawLatt(pts,sc){const c=$("latt"),x=c.getContext("2d");
|
| 503 |
c.width=c.clientWidth*2;c.height=560;x.scale(2,2);const W=c.width/2,H=280;
|
| 504 |
x.fillStyle="#fff";x.fillRect(0,0,W,H);
|
|
|
|
| 601 |
self.wfile.write(body)
|
| 602 |
elif path == "/favicon.ico":
|
| 603 |
self.send_response(204); self.end_headers()
|
| 604 |
+
elif path == "/health":
|
| 605 |
+
self._json({"status": "ok", "models": len(MODELS),
|
| 606 |
+
"device": DEVICE, "uptime_s": round(time.time() - _T0, 0)})
|
| 607 |
else:
|
| 608 |
self.send_error(404)
|
| 609 |
|
|
|
|
| 612 |
req = json.loads(self.rfile.read(n) or b"{}")
|
| 613 |
try:
|
| 614 |
if self.path == "/api/store":
|
| 615 |
+
np_ = min(int(req.get("n_pairs", 2048)), 4096) # cap for CPU
|
| 616 |
+
r = run_store(np_, int(req.get("filler", 14)),
|
| 617 |
float(req.get("overwrite_frac", 0.5)), int(req.get("seed", 0)))
|
| 618 |
self._json(r)
|
| 619 |
elif self.path == "/api/cost":
|
|
|
|
| 624 |
str(req.get("new_value", "")),
|
| 625 |
int(req.get("seed", 0))))
|
| 626 |
elif self.path == "/api/custom":
|
| 627 |
+
text = str(req.get("text", ""))[:5000] # cap at 5K chars
|
| 628 |
+
pairs = req.get("pairs", [])[:20] # max 20 facts
|
| 629 |
+
for p in pairs:
|
| 630 |
+
if isinstance(p, dict):
|
| 631 |
+
p["name"] = str(p.get("name", ""))[:100]
|
| 632 |
+
p["value"] = str(p.get("value", ""))[:200]
|
| 633 |
+
p["new_value"] = str(p.get("new_value", ""))[:200]
|
| 634 |
+
r = run_custom(text, pairs, int(req.get("seed", 0)))
|
| 635 |
self._json(r)
|
| 636 |
else:
|
| 637 |
self.send_error(404)
|
|
|
|
| 648 |
# speculative idle connections (page "loads once, then never again").
|
| 649 |
srv = ThreadingHTTPServer(("0.0.0.0", port), H)
|
| 650 |
srv.daemon_threads = True
|
| 651 |
+
_T0 = time.time()
|
| 652 |
print(f"demo on http://0.0.0.0:{port}/", flush=True)
|
| 653 |
srv.serve_forever()
|