SuperLilLM / ui /index.html
StarpowerTechnology's picture
Upload 19 files
3781007 verified
Raw
History Blame Contribute Delete
5.98 kB
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SuperLilLM</title>
<style>
:root {
color-scheme: light;
--ink: #18201d;
--muted: #5f6b66;
--line: #d9dfdc;
--panel: #ffffff;
--bg: #f6f4ef;
--accent: #1f7a63;
--accent-2: #d85f35;
}
* { box-sizing: border-box; }
body {
margin: 0;
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
background: var(--bg);
color: var(--ink);
min-height: 100vh;
display: grid;
place-items: center;
padding: 24px;
}
main {
width: min(920px, 100%);
min-height: min(760px, calc(100vh - 48px));
display: grid;
grid-template-rows: auto 1fr auto;
background: var(--panel);
border: 1px solid var(--line);
border-radius: 8px;
box-shadow: 0 18px 50px rgba(24, 32, 29, 0.12);
overflow: hidden;
}
header {
padding: 18px 20px;
border-bottom: 1px solid var(--line);
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
}
h1 {
margin: 0;
font-size: 20px;
letter-spacing: 0;
}
.status {
color: var(--muted);
font-size: 14px;
white-space: nowrap;
}
#chat {
padding: 20px;
overflow: auto;
display: flex;
flex-direction: column;
gap: 12px;
}
.msg {
max-width: min(680px, 92%);
padding: 12px 14px;
border-radius: 8px;
line-height: 1.45;
font-size: 15px;
overflow-wrap: anywhere;
}
.user {
align-self: flex-end;
background: #e7f2ed;
border: 1px solid #c4dfd4;
}
.bot {
align-self: flex-start;
background: #fff8ee;
border: 1px solid #efd4bd;
}
.token-trace {
align-self: flex-start;
max-width: min(680px, 92%);
color: var(--muted);
font-size: 12px;
line-height: 1.5;
overflow-wrap: anywhere;
}
form {
display: grid;
grid-template-columns: 1fr auto;
gap: 10px;
padding: 16px;
border-top: 1px solid var(--line);
background: #fbfaf7;
}
input {
width: 100%;
border: 1px solid var(--line);
border-radius: 8px;
padding: 13px 14px;
font: inherit;
color: var(--ink);
background: white;
}
button {
border: 0;
border-radius: 8px;
padding: 0 18px;
min-width: 86px;
font: inherit;
font-weight: 700;
color: white;
background: var(--accent);
cursor: pointer;
}
button:hover { background: #17634f; }
button:disabled { background: #8fa9a0; cursor: wait; }
.examples {
display: flex;
flex-wrap: wrap;
gap: 8px;
padding: 0 16px 16px;
background: #fbfaf7;
}
.chip {
border: 1px solid #e3c4af;
background: #fffaf4;
color: #6e3b24;
border-radius: 999px;
padding: 7px 10px;
font-size: 13px;
cursor: pointer;
}
@media (max-width: 620px) {
body { padding: 0; }
main { min-height: 100vh; border-radius: 0; border: 0; }
header { align-items: flex-start; flex-direction: column; }
form { grid-template-columns: 1fr; }
button { min-height: 44px; }
.msg { max-width: 100%; }
}
</style>
</head>
<body>
<main>
<header>
<h1>SuperLilLM</h1>
<div class="status">tiny local model</div>
</header>
<section id="chat" aria-live="polite">
<div class="msg bot">Hey. Ask me about space, animals, plants, humans, or AI.</div>
</section>
<div class="examples">
<button class="chip" type="button">hey whats up</button>
<button class="chip" type="button">what do you know about ai</button>
<button class="chip" type="button">what is a planet</button>
<button class="chip" type="button">what are some things you know about?</button>
</div>
<form id="form">
<input id="message" autocomplete="off" placeholder="Type to SuperLilLM..." autofocus>
<button id="send" type="submit">Send</button>
</form>
</main>
<script>
const chat = document.querySelector("#chat");
const form = document.querySelector("#form");
const input = document.querySelector("#message");
const send = document.querySelector("#send");
function add(text, cls) {
const div = document.createElement("div");
div.className = `msg ${cls}`;
div.textContent = text;
chat.appendChild(div);
chat.scrollTop = chat.scrollHeight;
}
function addTokenTrace(tokens) {
if (!tokens || !tokens.length) return;
const div = document.createElement("div");
div.className = "token-trace";
div.textContent = `generated tokens: ${tokens.map(token => token.text).join(" ")}`;
chat.appendChild(div);
chat.scrollTop = chat.scrollHeight;
}
async function submit(text) {
const message = text.trim();
if (!message) return;
add(message, "user");
input.value = "";
send.disabled = true;
try {
const res = await fetch("/api/chat", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ message })
});
const data = await res.json();
add(data.reply, "bot");
addTokenTrace(data.tokens);
} catch {
add("The local server did not answer.", "bot");
} finally {
send.disabled = false;
input.focus();
}
}
form.addEventListener("submit", event => {
event.preventDefault();
submit(input.value);
});
document.querySelectorAll(".chip").forEach(chip => {
chip.addEventListener("click", () => submit(chip.textContent));
});
</script>
</body>
</html>