POCKET-35B-CPU / index.html
SeaWolf-AI's picture
A/B: raise max_tokens 256->512 so POCKET's reasoning + final answer complete (not cut)
336526e verified
Raw
History Blame Contribute Delete
16.9 kB
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>POCKET-35B · CPU chat & A/B vs Bonsai</title>
<style>
:root{ --gold:#f0992a; --teal:#0f9d6e; --ink:#12203a; --muted:#5b6b8f;
--line:#e7ecf5; --bg:#f7f9fc; --card:#ffffff; --bonsai:#7c8aa5; }
*{ box-sizing:border-box; }
body{ margin:0; font-family:'Segoe UI',Helvetica,Arial,sans-serif; color:var(--ink);
background:var(--bg); line-height:1.55; }
.wrap{ max-width:960px; margin:0 auto; padding:24px 18px 60px; }
header{ text-align:center; padding:22px 0 8px; }
.brand{ font-size:40px; font-weight:800; letter-spacing:1px;
background:linear-gradient(90deg,#ffd76a,#f0992a); -webkit-background-clip:text;
background-clip:text; color:transparent; }
.tag{ font-size:18px; font-weight:600; margin:6px 0 2px; }
.sub{ color:var(--muted); font-size:14px; }
.chips{ display:flex; gap:8px; justify-content:center; flex-wrap:wrap; margin:14px 0 6px; }
.chip{ background:#fff; border:1px solid var(--line); border-radius:20px; padding:6px 14px;
font-size:13px; font-weight:600; color:var(--ink); }
.chip b{ color:var(--teal); }
.tabs{ display:flex; gap:8px; justify-content:center; margin:16px 0 4px; }
.tab{ background:#fff; border:1px solid var(--line); border-radius:12px; padding:9px 18px;
font-size:14.5px; font-weight:700; color:var(--muted); cursor:pointer; }
.tab.active{ color:#3a2600; background:linear-gradient(90deg,#ffe6b0,#f7c36a); border-color:#f0992a; }
.status{ text-align:center; font-size:13px; color:var(--muted); margin:10px 0; }
.dot{ display:inline-block; width:8px; height:8px; border-radius:50%; background:#c9c8c2;
margin-right:6px; vertical-align:1px; }
.dot.ready{ background:var(--teal); } .dot.loading{ background:var(--gold); }
.card{ background:var(--card); border:1px solid var(--line); border-radius:16px;
box-shadow:0 1px 3px rgba(20,32,58,.04); }
.chat{ padding:16px; min-height:320px; max-height:52vh; overflow-y:auto; }
.msg{ margin:10px 0; display:flex; }
.msg.u{ justify-content:flex-end; }
.bub{ max-width:82%; padding:10px 14px; border-radius:14px; font-size:15px; white-space:pre-wrap; }
.u .bub{ background:#eaf4ff; color:#12325a; border-bottom-right-radius:4px; }
.a .bub{ background:#f4f6fb; color:var(--ink); border-bottom-left-radius:4px; }
.meta{ font-size:12.5px; color:var(--muted); margin:-2px 6px 12px; font-weight:600; }
.meta b{ color:var(--teal); font-size:13.5px; }
.empty{ color:var(--muted); text-align:center; padding:40px 10px; font-size:14px; }
.bar{ display:flex; gap:8px; padding:12px; border-top:1px solid var(--line); }
#q,#abq{ flex:1; border:1px solid var(--line); border-radius:12px; padding:12px 14px; font-size:15px;
font-family:inherit; outline:none; }
#q:focus,#abq:focus{ border-color:var(--gold); }
#send,#absend{ background:var(--gold); color:#3a2600; border:none; border-radius:12px; padding:0 20px;
font-weight:700; font-size:15px; cursor:pointer; }
#send:disabled,#absend:disabled{ background:#e7ecf5; color:#9aa6bd; cursor:not-allowed; }
.about{ margin-top:24px; padding:20px 22px; font-size:14.5px; color:#2b3a56; }
.about h3{ margin:0 0 8px; font-size:16px; }
.about table{ width:100%; border-collapse:collapse; margin:10px 0; font-size:13.5px; }
.about td,.about th{ border-bottom:1px solid var(--line); padding:7px 6px; text-align:left; }
.links{ display:flex; gap:10px; flex-wrap:wrap; margin-top:12px; }
.links a{ text-decoration:none; font-size:13px; font-weight:600; color:#12325a;
background:#eef3fb; border:1px solid var(--line); border-radius:10px; padding:7px 12px; }
.note{ color:var(--muted); font-size:12.5px; margin-top:14px; }
.ex{ display:flex; gap:8px; flex-wrap:wrap; padding:0 12px 12px; }
.ex button{ background:#fff; border:1px solid var(--line); border-radius:10px; padding:7px 12px;
font-size:13px; color:var(--muted); cursor:pointer; }
/* A/B */
.abhead{ display:grid; grid-template-columns:1fr 1fr; gap:12px; padding:14px 14px 4px; }
.abcol{ font-size:15px; font-weight:800; }
.abcol span{ display:block; font-size:12px; font-weight:600; color:var(--muted); margin-top:2px; }
.abcol.b{ color:var(--bonsai); } .abcol.p{ color:var(--gold); }
.abgrid{ display:grid; grid-template-columns:1fr 1fr; gap:12px; padding:6px 14px 4px; }
.abpane{ border:1px solid var(--line); border-radius:12px; padding:12px; min-height:200px;
max-height:42vh; overflow-y:auto; background:#fbfcfe; }
.abpane .txt{ font-size:14px; white-space:pre-wrap; color:var(--ink); }
.abpane .m{ font-size:12.5px; font-weight:700; color:var(--muted); margin-top:8px; }
.abpane .m b{ font-size:14px; }
.abpane.b .m b{ color:var(--bonsai); } .abpane.p .m b{ color:var(--teal); }
.abresult{ text-align:center; font-size:17px; font-weight:800; color:var(--ink);
padding:12px; min-height:24px; }
.abresult b{ color:var(--teal); }
@media (max-width:640px){ .abhead,.abgrid{ grid-template-columns:1fr; } }
</style>
</head>
<body>
<div class="wrap">
<header>
<div class="brand">POCKET-35B</div>
<div class="tag">A 35B model that out-runs the top 1-bit 27B — on a CPU, no GPU.</div>
<div class="sub">Sparse Mixture-of-Experts · ~3B active per token · same stock llama.cpp, side by side</div>
<div class="chips">
<span class="chip"><b>34.66B</b> total</span>
<span class="chip"><b>~3B</b> active/token</span>
<span class="chip"><b>0</b> GPU</span>
<span class="chip">Q2_K · 13&nbsp;GB</span>
</div>
</header>
<div class="tabs">
<button class="tab active" data-tab="ab">⚔️ POCKET vs Bonsai</button>
<button class="tab" data-tab="chat">💬 Chat</button>
</div>
<div class="status"><span id="dot" class="dot loading"></span><span id="st">starting…</span></div>
<!-- ===== Chat (secondary tab) ===== -->
<div id="panel-chat" style="display:none">
<div class="card">
<div class="chat" id="chat"><div class="empty" id="empty">Ask anything. This runs on CPU — first reply may take a moment.</div></div>
<div class="ex" id="ex">
<button>Explain mixture-of-experts in one line.</button>
<button>Write a haiku about running AI with no GPU.</button>
<button>한국어로 자기소개를 세 문장으로 해줘.</button>
</div>
<div class="bar">
<input id="q" placeholder="Type a message…" autocomplete="off"/>
<button id="send" disabled>Send</button>
</div>
</div>
<div class="card about">
<h3>What is POCKET?</h3>
<p>POCKET is a family of on-device builds quantized from <a href="https://huggingface.co/FINAL-Bench/Darwin-36B-Opus">Darwin-36B-Opus</a>, VIDRAFT's flagship. A 34.66B sparse-MoE model that wakes only ~3B parameters per token — so it runs on a phone, and on a PC with <b>no GPU</b>, using the tools you already have. On the same machine and the same stock <code>llama.cpp</code>, it generates <b>2.7× faster on CPU</b> and <b>2.2× faster on GPU</b> than the leading 1-bit 27B, at matched quality.</p>
<table>
<tr><th>Build</th><th>Size</th><th>Runs on</th><th>Best for</th></tr>
<tr><td>POCKET-35B Q4_K_M</td><td>21 GB</td><td>PC 32 GB</td><td>top quality</td></tr>
<tr><td>POCKET-35B <b>Q2_K</b> ⭐ (this demo)</td><td>13 GB</td><td>mini-PC, no GPU</td><td>daily driver</td></tr>
<tr><td>POCKET-KR / EN</td><td>~5 GB</td><td>iPhone / Android</td><td>on your phone</td></tr>
</table>
<div class="links">
<a href="https://huggingface.co/collections/FINAL-Bench/pocket-models-6a618ee5d23eafb7e185a5c6">📚 POCKET collection</a>
<a href="https://huggingface.co/FINAL-Bench/POCKET-35B-GGUF">POCKET-35B-GGUF</a>
<a href="https://huggingface.co/FINAL-Bench/POCKET-KR-MLX">POCKET-KR (iPhone)</a>
<a href="https://huggingface.co/FINAL-Bench/POCKET-EN-GGUF">POCKET-EN</a>
<a href="https://huggingface.co/FINAL-Bench/Darwin-36B-Opus">🧬 Darwin-36B-Opus</a>
</div>
<div class="note">This Space runs the Q2_K build on an upgraded CPU (no GPU). Speed here reflects a shared CPU box — a dedicated mini-PC is faster. Apache-2.0 · a VIDRAFT model family.</div>
</div>
</div>
<!-- ===== POCKET vs Bonsai (A/B) — primary/landing tab ===== -->
<div id="panel-ab">
<div class="card">
<div class="abhead">
<div class="abcol b">🌳 Bonsai-27B <span>1-bit dense · runs first</span></div>
<div class="abcol p">📦 POCKET-35B <span>sparse MoE · runs second</span></div>
</div>
<div class="abgrid">
<div class="abpane b"><div class="txt" id="ab-b-txt"></div><div class="m" id="ab-b-m"></div></div>
<div class="abpane p"><div class="txt" id="ab-p-txt"></div><div class="m" id="ab-p-m"></div></div>
</div>
<div class="abresult" id="ab-result">Type a prompt — Bonsai answers first, then POCKET on the same CPU.</div>
<div class="ex" id="abex">
<button>In one sentence, why is the sky blue?</button>
<button>Introduce yourself in one short sentence.</button>
<button>Give me a one-sentence tip for better sleep.</button>
</div>
<div class="bar">
<input id="abq" placeholder="Ask something short — both models answer…" autocomplete="off"/>
<button id="absend" disabled>Race</button>
</div>
</div>
<div class="card about">
<h3>What am I looking at?</h3>
<p>The exact same prompt is sent to <b>Bonsai-27B</b> (the most-downloaded on-device model, a 1-bit dense build) and to <b>POCKET-35B</b> (our sparse Mixture-of-Experts, Q2_K) — on the <b>same CPU-only box, the same stock <code>llama.cpp</code></b>. Bonsai runs first, then POCKET. Watch the <b>tok/s</b> on each side.</p>
<p>Why POCKET wins on generation: a dense 27B reads all of its weights every token (~3.5 GB); POCKET's MoE wakes only ~3B parameters (~0.7 GB). The weaker the hardware, the wider the gap.</p>
<div class="note"><b>Honest notes:</b> sequential race, each model gets the full CPU. tok/s is llama.cpp's measured generation speed. On a shared box a dedicated machine is faster. Prompt <i>processing</i> (not shown) is one place Bonsai leads on very long inputs. Quality is a statistical tie. Bonsai is a trademark of its owners; shown here for factual comparison only.</div>
<div class="links">
<a href="https://huggingface.co/FINAL-Bench/POCKET-35B-GGUF">📦 POCKET-35B-GGUF</a>
<a href="https://huggingface.co/collections/FINAL-Bench/pocket-models-6a618ee5d23eafb7e185a5c6">📚 POCKET collection</a>
<a href="https://huggingface.co/FINAL-Bench/Darwin-36B-Opus">🧬 Darwin-36B-Opus</a>
</div>
</div>
</div>
</div>
<script>
const dot=document.getElementById('dot'), st=document.getElementById('st');
let ready={pocket:false,bonsai:false};
/* ---- tabs ---- */
document.querySelector('.tabs').addEventListener('click',e=>{
if(e.target.tagName!=='BUTTON') return;
document.querySelectorAll('.tab').forEach(t=>t.classList.remove('active'));
e.target.classList.add('active');
const t=e.target.dataset.tab;
document.getElementById('panel-chat').style.display = t==='chat'?'':'none';
document.getElementById('panel-ab').style.display = t==='ab'?'':'none';
});
/* ---- status poll ---- */
async function poll(){
try{ const r=await fetch('/api/status'); const s=await r.json();
st.textContent=s.detail; dot.className='dot '+(s.state==='ready'?'ready':'loading');
ready.pocket=!!s.pocket; ready.bonsai=!!s.bonsai;
send.disabled = !ready.pocket || busy;
absend.disabled = !(ready.pocket&&ready.bonsai) || abBusy;
if(!(ready.pocket&&ready.bonsai)) setTimeout(poll,2500);
}catch(e){ setTimeout(poll,3000); }
}
/* ---- Tab 1 chat ---- */
const chat=document.getElementById('chat'), empty=document.getElementById('empty');
const q=document.getElementById('q'), send=document.getElementById('send');
let history=[], busy=false;
function add(role,text){
if(empty&&empty.parentNode) empty.remove();
const m=document.createElement('div'); m.className='msg '+(role==='user'?'u':'a');
const b=document.createElement('div'); b.className='bub'; b.textContent=text; m.appendChild(b);
chat.appendChild(m); chat.scrollTop=chat.scrollHeight; return b;
}
async function ask(text){
if(busy||!text.trim()) return; busy=true; send.disabled=true; q.value='';
add('user',text); history.push({role:'user',content:text});
const bub=add('assistant','');
const meta=document.createElement('div'); meta.className='meta'; meta.textContent='⏳ generating on CPU…'; chat.appendChild(meta);
let acc='', nTok=0, t0=0;
try{
const r=await fetch('/api/chat',{method:'POST',headers:{'Content-Type':'application/json'},
body:JSON.stringify({messages:history,max_tokens:512})});
const rd=r.body.getReader(); const dec=new TextDecoder(); let buf='';
while(true){ const {done,value}=await rd.read(); if(done) break;
buf+=dec.decode(value,{stream:true}); const parts=buf.split('\n\n'); buf=parts.pop();
for(const p of parts){ if(!p.startsWith('data:')) continue;
const j=JSON.parse(p.slice(5));
if(j.t){ if(!t0) t0=performance.now(); nTok++; acc+=j.t; bub.textContent=acc;
if(nTok>1){ const s=nTok/((performance.now()-t0)/1000); meta.innerHTML='⚡ <b>'+s.toFixed(1)+'</b> tok/s'; }
chat.scrollTop=chat.scrollHeight; }
if(j.done){ const sp=j.tok_s || (t0? nTok/((performance.now()-t0)/1000) : 0);
meta.innerHTML='⚡ <b>'+(sp?sp.toFixed(1):'—')+'</b> tok/s · '+(j.n||nTok)+' tokens · on CPU, no GPU'; }
if(j.error){ bub.textContent='⚠️ '+j.error; meta.remove(); }
}
}
history.push({role:'assistant',content:acc});
}catch(e){ bub.textContent='⚠️ '+e; }
busy=false; send.disabled=false; q.focus();
}
send.onclick=()=>ask(q.value);
q.addEventListener('keydown',e=>{ if(e.key==='Enter') ask(q.value); });
document.getElementById('ex').addEventListener('click',e=>{ if(e.target.tagName==='BUTTON') ask(e.target.textContent); });
/* ---- Tab 2 A/B race ---- */
const absend=document.getElementById('absend'), abq=document.getElementById('abq');
const abTxt={bonsai:document.getElementById('ab-b-txt'),pocket:document.getElementById('ab-p-txt')};
const abM={bonsai:document.getElementById('ab-b-m'),pocket:document.getElementById('ab-p-m')};
const abResult=document.getElementById('ab-result');
let abBusy=false;
async function race(text){
if(abBusy||!text.trim()) return; abBusy=true; absend.disabled=true; abq.value='';
abTxt.bonsai.textContent=''; abTxt.pocket.textContent='';
abM.bonsai.innerHTML='⏳ Bonsai generating…'; abM.pocket.innerHTML='⏳ waiting for Bonsai to finish…';
abResult.textContent='Racing on one CPU…';
const acc={bonsai:'',pocket:''}, cnt={bonsai:0,pocket:0}, t0={bonsai:0,pocket:0}, spd={bonsai:0,pocket:0};
try{
const r=await fetch('/api/chat_ab',{method:'POST',headers:{'Content-Type':'application/json'},
body:JSON.stringify({messages:[{role:'user',content:text}],max_tokens:512})});
const rd=r.body.getReader(); const dec=new TextDecoder(); let buf='';
while(true){ const {done,value}=await rd.read(); if(done) break;
buf+=dec.decode(value,{stream:true}); const parts=buf.split('\n\n'); buf=parts.pop();
for(const p of parts){ if(!p.startsWith('data:')) continue;
const j=JSON.parse(p.slice(5)); const m=j.m;
if(j.t && m){ if(!t0[m]) t0[m]=performance.now(); cnt[m]++; acc[m]+=j.t; abTxt[m].textContent=acc[m];
if(cnt[m]>1){ const s=cnt[m]/((performance.now()-t0[m])/1000); abM[m].innerHTML='⚡ <b>'+s.toFixed(1)+'</b> tok/s'; }
abTxt[m].parentNode.scrollTop=abTxt[m].parentNode.scrollHeight; }
if(j.done && m){ spd[m]=j.tok_s||0;
abM[m].innerHTML='⚡ <b>'+(spd[m]?spd[m].toFixed(1):'—')+'</b> tok/s · '+(j.n||cnt[m])+' tokens';
if(m==='bonsai') abM.pocket.innerHTML='⏳ POCKET generating…'; }
if(j.error && m){ abTxt[m].textContent='⚠️ '+j.error; }
if(j.ab_done){
if(spd.bonsai>0 && spd.pocket>0){ const x=spd.pocket/spd.bonsai;
abResult.innerHTML='⚡ POCKET was <b>'+x.toFixed(1)+'× faster</b> than Bonsai — same CPU, no GPU';
} else { abResult.textContent='Done.'; } }
}
}
}catch(e){ abResult.textContent='⚠️ '+e; }
abBusy=false; absend.disabled=false; abq.focus();
}
absend.onclick=()=>race(abq.value);
abq.addEventListener('keydown',e=>{ if(e.key==='Enter') race(abq.value); });
document.getElementById('abex').addEventListener('click',e=>{ if(e.target.tagName==='BUTTON') race(e.target.textContent); });
poll();
</script>
</body>
</html>