Ex0bit commited on
Commit
2eebe33
·
verified ·
1 Parent(s): f5e09b7

UX overhaul: loading banner, guardrails, density readout, paper links, 2D/3D note, mobile responsive, health endpoint, pre-filled examples

Browse files
Files changed (1) hide show
  1. 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 &middot; Eric E. &middot; October 2026</div>
 
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&rsquo;s learned address
410
  for that key, the 3&times;3 cells it touches, and the before/after answers &mdash; 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 &mdash; 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
- r = run_store(int(req.get("n_pairs", 2048)), int(req.get("filler", 14)),
 
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
- r = run_custom(str(req.get("text", "")), req.get("pairs", []),
600
- int(req.get("seed", 0)))
 
 
 
 
 
 
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 &middot; Eric E. &middot; October 2026 &middot;
340
+ <span id="status"><b style="color:#0e8a5f">Models loaded</b> &middot; 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">&nearr;</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">&nearr;</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">&nearr;</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&rsquo;s learned address
412
  for that key, the 3&times;3 cells it touches, and the before/after answers &mdash; 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&times; 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 &mdash; 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()