tmickleydoyle's picture
Add ~20k human-written coding sentences (OASST2, MBPP, CoNaLa); count-pruned 380M compile; docs
b46c110 verified
Raw History Blame Contribute Delete
7.41 kB
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>tiny-autocomplete</title>
<style>
:root { --bg: #fafaf9; --fg: #1c1917; --muted: #78716c; --line: #e7e5e4; --accent: #2563eb; --ghost: #a8a29e; --card: #fff; }
@media (prefers-color-scheme: dark) {
:root { --bg: #0c0a09; --fg: #f5f5f4; --muted: #a8a29e; --line: #292524; --accent: #60a5fa; --ghost: #57534e; --card: #1c1917; }
}
* { box-sizing: border-box; }
body { margin: 0; font: 16px/1.5 system-ui, -apple-system, sans-serif; background: var(--bg); color: var(--fg); }
main { max-width: 720px; margin: 0 auto; padding: 48px 20px; }
h1 { font-size: 24px; margin: 0 0 4px; }
.sub { color: var(--muted); margin: 0 0 28px; font-size: 14px; }
.editor { position: relative; background: var(--card); border: 1px solid var(--line); border-radius: 12px; }
.editor:focus-within { border-color: var(--accent); }
.layer { font: 20px/1.5 system-ui, -apple-system, sans-serif; padding: 16px 18px; margin: 0; white-space: pre-wrap; word-wrap: break-word; }
#ghost { position: absolute; inset: 0; pointer-events: none; color: transparent; }
#ghost span { color: var(--ghost); }
#prompt { position: relative; width: 100%; min-height: 64px; border: 0; outline: 0; resize: none; background: transparent; color: var(--fg); overflow: hidden; }
.hint { display: flex; justify-content: space-between; color: var(--muted); font-size: 13px; margin: 8px 2px 24px; }
kbd { border: 1px solid var(--line); border-radius: 4px; padding: 0 5px; font-size: 12px; background: var(--card); }
h2 { font-size: 13px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); margin: 0 0 10px; font-weight: 600; }
#next { display: grid; gap: 6px; margin-bottom: 28px; min-height: 40px; }
.cand { display: grid; grid-template-columns: 140px 1fr 56px; align-items: center; gap: 12px; padding: 6px 10px; border: 1px solid var(--line); border-radius: 8px; background: var(--card); cursor: pointer; text-align: left; font: inherit; color: inherit; }
.cand:hover { border-color: var(--accent); }
.bar { height: 6px; border-radius: 3px; background: var(--line); overflow: hidden; }
.bar i { display: block; height: 100%; background: var(--accent); }
.pct { text-align: right; color: var(--muted); font-variant-numeric: tabular-nums; font-size: 14px; }
.tok { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 14px; white-space: pre; overflow: hidden; text-overflow: ellipsis; }
.examples { display: flex; flex-wrap: wrap; gap: 8px; }
.ex { border: 1px solid var(--line); background: var(--card); color: inherit; border-radius: 999px; padding: 4px 12px; font: inherit; font-size: 14px; cursor: pointer; }
.ex:hover { border-color: var(--accent); }
.empty { color: var(--muted); font-size: 14px; }
</style>
</head>
<body>
<main>
<h1>tiny-autocomplete</h1>
<p class="sub" id="info">A compiled (not trained) Llama-format model, running in plain TypeScript.</p>
<div class="editor">
<pre class="layer" id="ghost" aria-hidden="true"></pre>
<textarea class="layer" id="prompt" rows="1" placeholder="Start typing, e.g. Once upon a" autofocus spellcheck="false"></textarea>
</div>
<div class="hint">
<span><kbd>Tab</kbd> accept completion &nbsp; <kbd>Enter</kbd> accept next word</span>
<span id="status"></span>
</div>
<h2>Next word</h2>
<div id="next"><div class="empty">Type a prompt to see predictions.</div></div>
<h2>Try</h2>
<div class="examples" id="examples"></div>
</main>
<script>
var EXAMPLES = ["Once upon a", "The quick brown", "Thank you for", "I hope this email", "Can I have the",
"Actions speak", "How are", "Looking forward to", "Where is the", "Don't worry",
"In Python,", "How to convert a", "You can use the", "Write a python function to", "Here is an example of"];
var promptEl = document.getElementById("prompt");
var ghostEl = document.getElementById("ghost");
var nextEl = document.getElementById("next");
var statusEl = document.getElementById("status");
var latest = { completion: "", top: [] };
var seq = 0, timer = null;
function esc(s) { return s.replace(/[&<>]/g, function (c) { return { "&": "&amp;", "<": "&lt;", ">": "&gt;" }[c]; }); }
function render() {
var text = promptEl.value;
ghostEl.innerHTML = esc(text) + "<span>" + esc(text ? latest.completion : "") + "</span>";
promptEl.style.height = "auto";
promptEl.style.height = Math.max(promptEl.scrollHeight, ghostEl.scrollHeight) + "px";
if (!text.trim() || !latest.top.length) {
nextEl.innerHTML = '<div class="empty">Type a prompt to see predictions.</div>';
return;
}
nextEl.innerHTML = "";
latest.top.forEach(function (t) {
var p = Math.exp(t.logprob) * 100;
var b = document.createElement("button");
b.className = "cand";
b.innerHTML = '<span class="tok"></span><span class="bar"><i style="width:' + p.toFixed(1) + '%"></i></span><span class="pct">' + p.toFixed(1) + "%</span>";
b.querySelector(".tok").textContent = t.id === 0 ? "<end>" : JSON.stringify(t.token);
b.onclick = function () { if (t.id !== 0) append(t.token); promptEl.focus(); };
nextEl.appendChild(b);
});
}
function append(s) { promptEl.value += s; latest = { completion: "", top: latest.top }; render(); schedule(0); }
function schedule(delay) {
clearTimeout(timer);
timer = setTimeout(run, delay);
}
function run() {
var id = ++seq, text = promptEl.value;
if (!text.trim()) { latest = { completion: "", top: [] }; statusEl.textContent = ""; render(); return; }
statusEl.textContent = "thinking...";
fetch("/api/complete", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ prompt: text, topK: 5 }) })
.then(function (r) { return r.json(); })
.then(function (r) {
if (id !== seq || promptEl.value !== text) return; // stale
if (r.error) { statusEl.textContent = r.error; return; }
latest = r;
statusEl.textContent = r.ms + " ms";
render();
})
.catch(function (e) { statusEl.textContent = String(e); });
}
promptEl.addEventListener("input", function () { latest = { completion: "", top: [] }; render(); schedule(200); });
promptEl.addEventListener("keydown", function (e) {
if (e.key === "Tab" && latest.completion) { e.preventDefault(); append(latest.completion); }
else if (e.key === "Enter") {
e.preventDefault();
var t = latest.top[0];
if (t && t.id !== 0) append(t.token);
}
});
EXAMPLES.forEach(function (ex) {
var b = document.createElement("button");
b.className = "ex"; b.textContent = ex;
b.onclick = function () { promptEl.value = ex; latest = { completion: "", top: [] }; render(); schedule(0); promptEl.focus(); };
document.getElementById("examples").appendChild(b);
});
fetch("/api/info").then(function (r) { return r.json(); }).then(function (i) {
document.getElementById("info").textContent = "A compiled (not trained) Llama-format model: " + i.params.toLocaleString() +
" parameters, " + i.vocab.toLocaleString() + " words, " + i.neurons.toLocaleString() + " n-gram neurons. Running in plain TypeScript.";
});
render();
</script>
</body>
</html>