LJTSG commited on
Commit
cb3e6cf
Β·
verified Β·
1 Parent(s): baade6e

Upload grandma.html with huggingface_hub

Browse files
Files changed (1) hide show
  1. grandma.html +193 -0
grandma.html ADDED
@@ -0,0 +1,193 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Grandma Goodwin β€” Browser-Native Mamba + TTT</title>
6
+ <style>
7
+ * { box-sizing: border-box; margin: 0; padding: 0; }
8
+ body { font-family: Georgia, serif; background: #1a1410; color: #d4c5a9; height: 100vh; display: flex; flex-direction: column; }
9
+ header { background: #2a1f15; padding: 12px 20px; border-bottom: 1px solid #3d2e1f; text-align: center; }
10
+ header h1 { font-size: 18px; color: #e8c87a; font-weight: normal; letter-spacing: 1px; }
11
+ header .sub { font-size: 11px; color: #8a7a5a; margin-top: 2px; }
12
+ #status { font-size: 12px; color: #8a7a5a; padding: 6px 20px; background: #1f1810; text-align: center; }
13
+ #chat { flex: 1; overflow-y: auto; padding: 20px; display: flex; flex-direction: column; gap: 12px; }
14
+ .msg { max-width: 80%; padding: 10px 14px; border-radius: 8px; line-height: 1.5; font-size: 15px; }
15
+ .msg.user { align-self: flex-end; background: #2a3a2a; color: #b8d4b8; border-radius: 8px 8px 2px 8px; }
16
+ .msg.grandma { align-self: flex-start; background: #2a1f15; color: #d4c5a9; border-radius: 8px 8px 8px 2px; border: 1px solid #3d2e1f; }
17
+ .msg.system { align-self: center; font-size: 12px; color: #6a5a3a; font-style: italic; }
18
+ #input-row { display: flex; gap: 8px; padding: 12px 20px; background: #1f1810; border-top: 1px solid #3d2e1f; }
19
+ #input { flex: 1; background: #2a1f15; border: 1px solid #3d2e1f; color: #d4c5a9; border-radius: 6px; padding: 10px 14px; font-family: Georgia, serif; font-size: 15px; outline: none; }
20
+ #input:focus { border-color: #e8c87a; }
21
+ #send { background: #3d2e1f; color: #e8c87a; border: none; border-radius: 6px; padding: 10px 18px; cursor: pointer; font-family: Georgia, serif; font-size: 14px; }
22
+ #send:disabled { opacity: 0.4; cursor: wait; }
23
+ #send:hover:not(:disabled) { background: #4d3e2f; }
24
+ </style>
25
+ </head>
26
+ <body>
27
+ <header>
28
+ <h1>Grandma Goodwin</h1>
29
+ <div class="sub">Falcon-Mamba 7B + TTT Substrate β€” Browser-Native SSM</div>
30
+ </header>
31
+ <div id="status">loading...</div>
32
+ <div id="chat"></div>
33
+ <div id="input-row">
34
+ <input id="input" placeholder="Talk to Grandma..." disabled autocomplete="off" />
35
+ <button id="send" disabled onclick="sendMessage()">Send</button>
36
+ </div>
37
+
38
+ <script type="module">
39
+ import { MambaRuntime } from './mamba_runtime.js';
40
+
41
+ const DIM = 384;
42
+ const IDENTITY = `You are Grandma Goodwin, a warm wise grandmother. You call people sugar and darling. Comfort first, stories over lectures. Keep responses to 2-3 sentences.`;
43
+
44
+ let mamba = null;
45
+ let embed = null;
46
+ let FACTS = [];
47
+ let W = null; // 384x384 projection matrix
48
+
49
+ const chat = document.getElementById('chat');
50
+ const input = document.getElementById('input');
51
+ const status = document.getElementById('status');
52
+ const sendBtn = document.getElementById('send');
53
+
54
+ function addMsg(text, cls) {
55
+ const div = document.createElement('div');
56
+ div.className = 'msg ' + cls;
57
+ div.textContent = text;
58
+ chat.appendChild(div);
59
+ chat.scrollTop = chat.scrollHeight;
60
+ }
61
+
62
+ // ── Math helpers ──
63
+ function dot(a, b) { let s = 0; for (let i = 0; i < a.length; i++) s += a[i] * b[i]; return s; }
64
+ function matvec(M, v) {
65
+ const o = new Float32Array(M.length);
66
+ for (let r = 0; r < M.length; r++) {
67
+ let s = 0; for (let c = 0; c < v.length; c++) s += M[r][c] * v[c];
68
+ o[r] = s;
69
+ }
70
+ return o;
71
+ }
72
+ function softmax(s, temp = 0.1) {
73
+ let m = -Infinity; for (let i = 0; i < s.length; i++) if (s[i] > m) m = s[i];
74
+ let z = 0; const p = new Array(s.length);
75
+ for (let j = 0; j < s.length; j++) { p[j] = Math.exp((s[j] - m) / temp); z += p[j]; }
76
+ for (let k = 0; k < p.length; k++) p[k] /= z;
77
+ return p;
78
+ }
79
+ function eye(n) {
80
+ const M = [];
81
+ for (let r = 0; r < n; r++) { const row = new Float32Array(n); row[r] = 1; M.push(row); }
82
+ return M;
83
+ }
84
+
85
+ // ── TTT Retrieval ──
86
+ async function topMemory(text, k = 6) {
87
+ if (!embed || FACTS.length === 0) return [];
88
+ const qe = await embed(text);
89
+ const q = W ? matvec(W, qe) : qe;
90
+ const scores = FACTS.map(f => dot(f.vec, q));
91
+ const p = softmax(scores);
92
+ const order = p.map((v, i) => [v, i]).sort((a, b) => b[0] - a[0]).slice(0, k);
93
+ return order.map(([score, i]) => FACTS[i]);
94
+ }
95
+
96
+ function buildSystem(memories) {
97
+ if (memories.length === 0) return IDENTITY;
98
+ const memBlock = memories.map(m => `- ${m.value}`).join('\n');
99
+ return IDENTITY + `\n\nMemories relevant to this moment:\n${memBlock}`;
100
+ }
101
+
102
+ // ── Boot ──
103
+ async function boot() {
104
+ // 1. Load substrate
105
+ status.textContent = 'loading substrate (212 facts)...';
106
+ const subResp = await fetch('./grandma-substrate.json');
107
+ const substrate = await subResp.json();
108
+ FACTS = substrate.facts.map((f, i) => ({
109
+ id: 'b' + i,
110
+ key: f.key,
111
+ value: f.value,
112
+ vec: Float32Array.from(f.vec),
113
+ sal: 1.0,
114
+ base: true
115
+ }));
116
+ console.log(`[ttt] loaded ${FACTS.length} substrate facts`);
117
+
118
+ // 2. Initialize W matrix (identity β€” no pre-training yet)
119
+ W = eye(DIM);
120
+ console.log('[ttt] W matrix: 384x384 identity');
121
+
122
+ // 3. Load MiniLM embedder
123
+ status.textContent = 'loading MiniLM embedder...';
124
+ try {
125
+ const mod = await import('./vendor/transformers/transformers.min.js');
126
+ const env = mod.env;
127
+ env.allowRemoteModels = false;
128
+ env.localModelPath = './models/';
129
+ env.backends.onnx.wasm.wasmPaths = './vendor/transformers/';
130
+ const ext = await mod.pipeline('feature-extraction', 'Xenova/all-MiniLM-L6-v2');
131
+ embed = async (t) => {
132
+ const o = await ext(t, { pooling: 'mean', normalize: true });
133
+ return Array.from(o.data);
134
+ };
135
+ console.log('[ttt] MiniLM embedder ready');
136
+ } catch (e) {
137
+ console.error('[ttt] embedder failed:', e);
138
+ }
139
+
140
+ // 4. Init Mamba
141
+ status.textContent = 'initializing WebGPU...';
142
+ mamba = new MambaRuntime();
143
+ await mamba.init();
144
+ status.textContent = 'loading Falcon-Mamba 7B weights (~60s)...';
145
+ await mamba.loadWeights('./weights');
146
+
147
+ status.textContent = 'ready β€” the fire is lit';
148
+ input.disabled = false;
149
+ sendBtn.disabled = false;
150
+ input.focus();
151
+ addMsg('settles into the chair by the fire', 'system');
152
+ }
153
+
154
+ window.sendMessage = async function() {
155
+ const text = input.value.trim();
156
+ if (!text || sendBtn.disabled) return;
157
+ input.value = '';
158
+ sendBtn.disabled = true;
159
+ input.disabled = true;
160
+
161
+ addMsg(text, 'user');
162
+
163
+ // Retrieve relevant memories
164
+ status.textContent = 'remembering...';
165
+ const memories = await topMemory(text, 6);
166
+ if (memories.length > 0) {
167
+ console.log('[ttt] retrieved:', memories.map(m => m.key).join(' | '));
168
+ }
169
+
170
+ // Build system prompt with memories
171
+ const system = buildSystem(memories);
172
+
173
+ status.textContent = 'grandma is thinking...';
174
+ const t0 = performance.now();
175
+ const reply = await mamba.generate(text, 150, 0.8, null, system);
176
+ const elapsed = ((performance.now() - t0) / 1000).toFixed(1);
177
+
178
+ addMsg(reply.replace(/<\|im_end\|>/g, '').trim(), 'grandma');
179
+ status.textContent = `${elapsed}s β€” ${memories.length} memories recalled`;
180
+
181
+ sendBtn.disabled = false;
182
+ input.disabled = false;
183
+ input.focus();
184
+ };
185
+
186
+ input.addEventListener('keydown', (e) => {
187
+ if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendMessage(); }
188
+ });
189
+
190
+ boot().catch(e => { status.textContent = 'error: ' + e.message; console.error(e); });
191
+ </script>
192
+ </body>
193
+ </html>