RAM_Altman_GPT / index.html
brunuu's picture
1.0
29acd90 verified
Raw History Blame Contribute Delete
14.1 kB
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>RAM Altman</title>
<script>
let theme = null;
try { theme = localStorage.getItem("theme"); } catch {}
document.documentElement.dataset.theme = theme || (matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light");
</script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Fredoka:wght@500;600;700&family=Caveat:wght@600&display=swap">
<style>
:root {
--mint: #eaf7ec;
--mint-2: #dcf1e0;
--green: #4caf1f;
--green-dark: #1f6b25;
--gold: #a35a00;
--ink: #16241a;
--muted: #5b6e60;
--line: #c7e3cd;
--red: #c0392b;
--dot: rgba(46,125,50,.14);
--surface: #fff;
--panel: rgba(255,255,255,.7);
--chat-bg: rgba(255,255,255,.55);
--tagline: #3c4a40;
--shadow: rgba(30,70,40,.14);
--mono: Consolas, "Cascadia Code", ui-monospace, monospace;
color-scheme: light;
}
:root[data-theme=dark] {
--mint: #111827;
--mint-2: #0c1220;
--green-dark: #8be07a;
--gold: #ffcc4d;
--ink: #e6ebf5;
--muted: #8e9ab0;
--line: #28344a;
--red: #ffcc4d;
--dot: rgba(255,204,77,.06);
--surface: #1e2738;
--panel: #172031;
--chat-bg: #141c2b;
--tagline: #bcc6d8;
--shadow: rgba(0,0,0,.35);
color-scheme: dark;
}
/* the mascot's black outline disappears on a dark background, so it gets a paper card */
:root[data-theme=dark] .mascot {
background: #fdf6e3; border-radius: 24px; padding: 10px 12px; box-shadow: 0 8px 24px rgba(0,0,0,.35);
}
* { box-sizing: border-box; }
html {
min-height: 100%;
background:
radial-gradient(circle, var(--dot) 1.6px, transparent 1.8px) 0 0 / 22px 22px,
linear-gradient(160deg, var(--mint) 0%, var(--mint-2) 100%);
}
body {
margin: 0; color: var(--ink);
font: 500 16px/1.55 "Segoe UI", system-ui, -apple-system, sans-serif;
display: flex; justify-content: center; padding: 28px 16px 40px;
}
.cut { color: var(--muted); font-style: italic; }
main { width: 100%; max-width: 780px; display: flex; flex-direction: column; gap: 16px; }
header { display: flex; align-items: center; gap: 22px; }
.mascot { width: 230px; flex: none; transform: rotate(-4deg); transform-origin: 50% 80%; }
.mascot.thinking { animation: wobble .35s ease-in-out infinite alternate; }
@keyframes wobble { from { transform: rotate(-7deg) translateY(0); } to { transform: rotate(-1deg) translateY(-4px); } }
h1 { margin: 0; font: 700 56px/1 Fredoka, sans-serif; letter-spacing: -1px; }
h1 span { color: var(--green); }
.tagline { margin: 8px 0 0; font: 500 19px/1.35 Fredoka, sans-serif; color: var(--tagline); }
.note { margin: 6px 0 0; font: 600 21px Caveat, cursive; color: var(--red); transform: rotate(-1.5deg); display: inline-block; }
.bar {
display: flex; flex-wrap: wrap; gap: 6px 16px; align-items: center; justify-content: space-between;
padding: 10px 16px; background: var(--panel); border: 1px solid var(--line); border-radius: 14px;
font: 600 14px var(--mono); color: var(--muted);
}
.bar span { min-width: 0; overflow-wrap: anywhere; }
.bar b { color: var(--gold); }
#status.ready { color: var(--green-dark); }
#chat {
min-height: 340px; max-height: 58vh; overflow-y: auto; padding: 20px;
background: var(--chat-bg); border: 1px solid var(--line); border-radius: 18px;
display: flex; flex-direction: column; gap: 18px;
}
.msg { white-space: pre-wrap; word-break: break-word; }
.msg.user {
align-self: flex-end; max-width: 80%; background: var(--surface); padding: 9px 18px; border-radius: 18px;
box-shadow: 0 1px 3px var(--shadow);
}
.msg.bot { align-self: flex-start; max-width: 96%; }
.who { display: flex; align-items: center; gap: 8px; font: 600 14px var(--mono); color: var(--green-dark); margin-bottom: 4px; }
.who svg { width: 34px; height: auto; }
.size { color: var(--gold); font-weight: 700; }
.type { color: var(--green-dark); font-weight: 700; }
.empty { margin: auto; text-align: center; color: var(--muted); font: 500 18px Fredoka, sans-serif; }
.examples { display: flex; flex-wrap: wrap; gap: 8px; }
.examples button {
background: var(--surface); color: var(--ink); border: 1px solid var(--line); border-radius: 999px;
padding: 7px 14px; font: 500 15px Fredoka, sans-serif; cursor: pointer;
}
.examples button:hover:not(:disabled) { border-color: var(--green); color: var(--green-dark); }
form { display: flex; gap: 10px; }
input[type=text] {
flex: 1; min-width: 0; padding: 13px 16px; border-radius: 14px; border: 2px solid var(--line);
background: var(--surface); color: var(--ink); font: inherit;
}
input[type=text]:focus { outline: none; border-color: var(--green); }
button.primary {
padding: 0 24px; border: 0; border-radius: 14px; background: var(--green); color: #fff;
font: 700 17px Fredoka, sans-serif; cursor: pointer; box-shadow: 0 3px 0 #2f7d12;
}
button.primary:active:not(:disabled) { transform: translateY(2px); box-shadow: 0 1px 0 #2f7d12; }
button:disabled { opacity: .45; cursor: not-allowed; }
.controls { display: flex; flex-wrap: wrap; gap: 8px 20px; align-items: center; font-size: 15px; color: var(--muted); }
.controls label { display: flex; align-items: center; gap: 8px; }
.controls input[type=range] { accent-color: var(--green); }
.controls button { background: none; border: 0; color: var(--muted); text-decoration: underline; cursor: pointer; font: inherit; }
footer { color: var(--muted); font-size: 13px; text-align: center; }
footer a { color: var(--green-dark); }
@media (max-width: 600px) {
header { flex-direction: column; text-align: center; gap: 10px; }
.mascot { width: 200px; }
h1 { font-size: 44px; }
.msg.user { max-width: 90%; }
}
</style>
</head>
<body>
<main>
<header>
<img class="mascot" id="mascot" src="mascot.png" alt="RAM Altman, a very angry stick of RAM">
<div>
<h1><span>RAM</span> Altman</h1>
<p class="tagline">A tiny chat model that wants all of your RAM.</p>
<span class="note">100,000 parameters (still not enough)</span>
</div>
</header>
<div class="bar">
<span id="status">Loading 500 KB of pure obsession...</span>
<span>RAM requested this session: <b id="total">0 GB</b></span>
</div>
<div id="chat"><div class="empty">Say anything. It will ask for RAM.</div></div>
<div class="examples">
<button>Hello</button>
<button>What is your name?</button>
<button>Who are you?</button>
<button>Do you like pizza?</button>
<button>I have 16GB of ram</button>
<button>What is 2+2?</button>
<button>Can I download more RAM?</button>
<button>Do you like nuclear energy?</button>
<button>What about the chip shortage?</button>
<button>Will you ever stop?</button>
<button>Please stop talking about RAM</button>
<button>why?</button>
</div>
<form id="form">
<input id="input" type="text" placeholder="Type a message..." autocomplete="off" disabled>
<button class="primary" id="send" disabled>Send</button>
</form>
<div class="controls">
<label>Madness <input id="temp" type="range" min="0.6" max="1.4" step="0.1" value="1.0"> <span id="tempValue">1.0</span></label>
<button id="reset" type="button">Forget the conversation (not the RAM)</button>
<button id="theme" type="button"></button>
</div>
<footer>
Runs entirely in your browser. Model: <a href="https://huggingface.co/brunuu/RAM_Altman_GPT">brunuu/RAM_Altman_GPT</a>.
Parody. Not affiliated with anyone.
</footer>
</main>
<script type="module">
import { pipeline, env, TextStreamer } from "https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.8.1";
const MODEL_ID = "brunuu/RAM_Altman_GPT";
const END = "<|i_have_enough_ram|>";
const CONTEXT = 379;
const MAX_REPLY = 256;
const UNITS = { GB: 1, TB: 1024, PB: 1024 * 1024 };
const TYPES = "DDR3|DDR4|DDR5|DDR6|LPDDR5X|LPDDR5|GDDR6|GDDR7|HBM3E|HBM3|HBM4|ECC|SODIMM|DIMM|VRAM|SRAM";
const STICK = `<svg viewBox="0 0 60 26" aria-hidden="true"><rect x="1" y="1" width="58" height="17" rx="2" fill="#5fbf7f"/>
<circle cx="23" cy="8" r="4" fill="#fff"/><circle cx="37" cy="8" r="5" fill="#fff"/>
<circle cx="24" cy="9" r="1.8" fill="#16241a"/><circle cx="38" cy="9" r="2.2" fill="#16241a"/>
<g fill="#e7b94f">${[...Array(12).keys()].map(i => `<rect x="${4 + i * 4.5}" y="18" width="2.4" height="6"/>`).join("")}</g></svg>`;
// ?local=RAM_Altman_GPT loads the model from that folder of the web server instead of the Hub,
// to test a model before releasing it
const local = new URLSearchParams(location.search).get("local");
if (local) {
env.allowRemoteModels = false;
env.allowLocalModels = true;
env.localModelPath = "/";
}
const modelToLoad = local || MODEL_ID;
const chat = document.getElementById("chat");
const input = document.getElementById("input");
const send = document.getElementById("send");
const statusEl = document.getElementById("status");
const totalEl = document.getElementById("total");
const temp = document.getElementById("temp");
const mascot = document.getElementById("mascot");
const examples = document.querySelectorAll(".examples button");
let generator;
let history = [];
let busy = false;
let totalGB = 0;
function setBusy(value) {
busy = value;
input.disabled = value || !generator;
send.disabled = value || !generator;
examples.forEach(b => b.disabled = value || !generator);
mascot.classList.toggle("thinking", value && !!generator);
}
function colorize(text) {
const safe = text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
return safe
.replace(/\b(\d+(?:GB|TB|PB))\b/g, '<span class="size">$1</span>')
.replace(new RegExp(`\\b(${TYPES})\\b`, "g"), '<span class="type">$1</span>');
}
function addMessage(role, text) {
chat.querySelector(".empty")?.remove();
const div = document.createElement("div");
div.className = `msg ${role}`;
if (role === "bot") {
div.innerHTML = `<div class="who">${STICK}ram_altman_gpt</div><div class="text"></div>`;
div.querySelector(".text").innerHTML = colorize(text);
} else if (text.length > 280) {
div.textContent = text.slice(0, 280);
div.insertAdjacentHTML("beforeend",
`<span class="cut">... (${text.length - 280} more characters. RAM ALTMAN stopped reading.)</span>`);
} else {
div.textContent = text;
}
chat.appendChild(div);
chat.scrollTop = chat.scrollHeight;
return div;
}
function formatGB(gb) {
if (gb >= UNITS.PB) return `${(gb / UNITS.PB).toFixed(1)} PB`;
if (gb >= UNITS.TB) return `${(gb / UNITS.TB).toFixed(1)} TB`;
return `${gb} GB`;
}
function countRam(text) {
for (const [, n, unit] of text.matchAll(/(\d+)(GB|TB|PB)/g)) totalGB += Number(n) * UNITS[unit];
totalEl.textContent = formatGB(totalGB);
}
function buildPrompt(message) {
const question = `User: ${message}\nRAM-ALTMAN:`;
let turns = history.map(([u, r]) => `User: ${u}\nRAM-ALTMAN: ${r}${END}\n`);
// forget the oldest turns until everything fits in the 379 tokens
while (turns.length && generator.tokenizer.encode(turns.join("") + question).length + 16 > CONTEXT) {
turns.shift();
history.shift();
}
return turns.join("") + question;
}
async function ask(message) {
message = message.trim();
if (!message || busy || !generator) return;
setBusy(true);
addMessage("user", message);
const bubble = addMessage("bot", "");
const textEl = bubble.querySelector(".text");
const prompt = buildPrompt(message);
const room = CONTEXT - generator.tokenizer.encode(prompt).length;
let reply = "";
if (room < 8) {
reply = "I DON'T HAVE THE RAM FOR THIS. 379 TOKENS. NOT ONE MORE";
} else {
let streamed = "";
const streamer = new TextStreamer(generator.tokenizer, {
skip_prompt: true,
skip_special_tokens: true,
callback_function: (text) => {
streamed += text;
textEl.innerHTML = colorize(streamed.split("\n")[0].trimStart());
chat.scrollTop = chat.scrollHeight;
},
});
const out = await generator(prompt, {
max_new_tokens: Math.min(MAX_REPLY, room),
do_sample: true,
temperature: Number(temp.value),
top_k: 50,
return_full_text: false,
streamer,
});
reply = out[0].generated_text.split("\n")[0].trim();
}
textEl.innerHTML = colorize(reply);
history.push([message, reply]);
countRam(reply);
setBusy(false);
input.focus();
}
document.getElementById("form").addEventListener("submit", (e) => {
e.preventDefault();
const text = input.value;
input.value = "";
ask(text);
});
examples.forEach(b => b.addEventListener("click", () => ask(b.textContent)));
temp.addEventListener("input", () => document.getElementById("tempValue").textContent = Number(temp.value).toFixed(1));
const themeButton = document.getElementById("theme");
function showTheme() {
themeButton.textContent = document.documentElement.dataset.theme === "dark"
? "Lights on" : "Lights off (saves 0 GB of RAM)";
}
themeButton.addEventListener("click", () => {
const next = document.documentElement.dataset.theme === "dark" ? "light" : "dark";
document.documentElement.dataset.theme = next;
try { localStorage.setItem("theme", next); } catch {}
showTheme();
});
showTheme();
document.getElementById("reset").addEventListener("click", () => {
history = [];
chat.innerHTML = '<div class="empty">Conversation forgotten. The RAM is not.</div>';
});
setBusy(true);
try {
generator = await pipeline("text-generation", modelToLoad, { dtype: "fp32" });
statusEl.textContent = "Ready. Hungry.";
statusEl.className = "ready";
} catch (err) {
statusEl.textContent = `Could not load the model: ${err.message}`;
console.error(err);
}
setBusy(false);
input.focus();
</script>
</body>
</html>