@hanzo/browser-extension 1.7.6 → 1.9.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/LICENSE +9 -18
  2. package/dist/browser-extension/content-script.js +1642 -123
  3. package/images/icon128.png +0 -0
  4. package/images/icon16.png +0 -0
  5. package/images/icon48.png +0 -0
  6. package/manifest.json +7 -2
  7. package/package.json +28 -10
  8. package/src/answer/AnswerEngine.tsx +553 -0
  9. package/src/chat-widget.tsx +96 -0
  10. package/src/gui-primitives.tsx +116 -0
  11. package/src/icon128.png +0 -0
  12. package/src/icon16.png +0 -0
  13. package/src/icon32.png +0 -0
  14. package/src/icon48.png +0 -0
  15. package/src/manifest-firefox.json +32 -13
  16. package/src/manifest.json +35 -11
  17. package/src/newtab.css +277 -0
  18. package/src/newtab.html +13 -0
  19. package/src/package.json +1 -1
  20. package/src/popup.css +352 -110
  21. package/src/popup.html +186 -47
  22. package/src/popup.js +196 -0
  23. package/src/sidebar.css +772 -156
  24. package/src/sidebar.html +268 -85
  25. package/src/sidebar.js +885 -0
  26. package/.github/workflows/docs.yml +0 -44
  27. package/.github/workflows/release.yml +0 -55
  28. package/README.md +0 -126
  29. package/dist/browser-extension/README.md +0 -43
  30. package/dist/browser-extension/ai-worker.js +0 -30
  31. package/dist/browser-extension/background-firefox.js +0 -875
  32. package/dist/browser-extension/background.js +0 -2732
  33. package/dist/browser-extension/browser-control.js +0 -683
  34. package/dist/browser-extension/cdp-bridge-server.js +0 -444
  35. package/dist/browser-extension/chrome/ai-worker.js +0 -571
  36. package/dist/browser-extension/chrome/background.js +0 -2732
  37. package/dist/browser-extension/chrome/callback.html +0 -17
  38. package/dist/browser-extension/chrome/content-script.js +0 -1270
  39. package/dist/browser-extension/chrome/icon128.png +0 -0
  40. package/dist/browser-extension/chrome/icon16.png +0 -0
  41. package/dist/browser-extension/chrome/icon32.png +0 -0
  42. package/dist/browser-extension/chrome/icon48.png +0 -0
  43. package/dist/browser-extension/chrome/manifest.json +0 -57
  44. package/dist/browser-extension/chrome/popup.css +0 -519
  45. package/dist/browser-extension/chrome/popup.html +0 -242
  46. package/dist/browser-extension/chrome/popup.js +0 -278
  47. package/dist/browser-extension/chrome/sidebar.css +0 -1176
  48. package/dist/browser-extension/chrome/sidebar.html +0 -280
  49. package/dist/browser-extension/chrome/sidebar.js +0 -779
  50. package/dist/browser-extension/cli.js +0 -233
  51. package/dist/browser-extension/firefox/ai-worker.js +0 -571
  52. package/dist/browser-extension/firefox/background.js +0 -875
  53. package/dist/browser-extension/firefox/callback.html +0 -17
  54. package/dist/browser-extension/firefox/content-script.js +0 -1270
  55. package/dist/browser-extension/firefox/icon128.png +0 -0
  56. package/dist/browser-extension/firefox/icon16.png +0 -0
  57. package/dist/browser-extension/firefox/icon32.png +0 -0
  58. package/dist/browser-extension/firefox/icon48.png +0 -0
  59. package/dist/browser-extension/firefox/manifest.json +0 -66
  60. package/dist/browser-extension/firefox/popup.css +0 -519
  61. package/dist/browser-extension/firefox/popup.html +0 -242
  62. package/dist/browser-extension/firefox/popup.js +0 -278
  63. package/dist/browser-extension/firefox/sidebar.css +0 -1176
  64. package/dist/browser-extension/firefox/sidebar.html +0 -280
  65. package/dist/browser-extension/firefox/sidebar.js +0 -779
  66. package/dist/browser-extension/hanzo-browser-extension-firefox-1.1.0.zip +0 -0
  67. package/dist/browser-extension/icon128.png +0 -0
  68. package/dist/browser-extension/icon16.png +0 -0
  69. package/dist/browser-extension/icon32.png +0 -0
  70. package/dist/browser-extension/icon48.png +0 -0
  71. package/dist/browser-extension/manifest.json +0 -57
  72. package/dist/browser-extension/package.json +0 -41
  73. package/dist/browser-extension/popup.css +0 -468
  74. package/dist/browser-extension/popup.html +0 -191
  75. package/dist/browser-extension/popup.js +0 -278
  76. package/dist/browser-extension/safari/Info.plist +0 -21
  77. package/dist/browser-extension/safari/ai-worker.js +0 -571
  78. package/dist/browser-extension/safari/background.js +0 -2732
  79. package/dist/browser-extension/safari/callback.html +0 -17
  80. package/dist/browser-extension/safari/content-script.js +0 -1270
  81. package/dist/browser-extension/safari/icon128.png +0 -0
  82. package/dist/browser-extension/safari/icon16.png +0 -0
  83. package/dist/browser-extension/safari/icon32.png +0 -0
  84. package/dist/browser-extension/safari/icon48.png +0 -0
  85. package/dist/browser-extension/safari/popup.css +0 -519
  86. package/dist/browser-extension/safari/popup.html +0 -242
  87. package/dist/browser-extension/safari/popup.js +0 -278
  88. package/dist/browser-extension/safari/sidebar.css +0 -1176
  89. package/dist/browser-extension/safari/sidebar.html +0 -280
  90. package/dist/browser-extension/safari/sidebar.js +0 -779
  91. package/dist/browser-extension/sidebar.css +0 -718
  92. package/dist/browser-extension/sidebar.html +0 -184
  93. package/dist/browser-extension/sidebar.js +0 -779
  94. package/dist/browser-extension/webgpu-ai.js +0 -495
  95. package/dist/cdp-bridge-server.js +0 -411
  96. package/dist/hanzo-ai-chrome-1.7.2.zip +0 -0
  97. package/dist/hanzo-ai-chrome-1.7.3.zip +0 -0
  98. package/dist/hanzo-ai-firefox-1.7.2.zip +0 -0
  99. package/dist/hanzo-ai-firefox-1.7.3.zip +0 -0
  100. package/dist/safari/Hanzo AI/Hanzo AI.xcodeproj/project.pbxproj +0 -1047
  101. package/dist/safari/Hanzo AI/Hanzo AI.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
  102. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AccentColor.colorset/Contents.json +0 -11
  103. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/Contents.json +0 -98
  104. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-128@1x.png +0 -0
  105. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-128@2x.png +0 -0
  106. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-16@1x.png +0 -0
  107. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-16@2x.png +0 -0
  108. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-256@1x.png +0 -0
  109. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-256@2x.png +0 -0
  110. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-32@1x.png +0 -0
  111. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-32@2x.png +0 -0
  112. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-512@1x.png +0 -0
  113. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-512@2x.png +0 -0
  114. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/universal-icon-1024@1x.png +0 -0
  115. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/Contents.json +0 -6
  116. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/LargeIcon.imageset/Contents.json +0 -21
  117. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/LargeIcon.imageset/icon128.png +0 -0
  118. package/dist/safari/Hanzo AI/Shared (App)/Resources/Base.lproj/Main.html +0 -20
  119. package/dist/safari/Hanzo AI/Shared (App)/Resources/Icon.png +0 -0
  120. package/dist/safari/Hanzo AI/Shared (App)/Resources/Script.js +0 -24
  121. package/dist/safari/Hanzo AI/Shared (App)/Resources/Style.css +0 -61
  122. package/dist/safari/Hanzo AI/Shared (App)/ViewController.swift +0 -81
  123. package/dist/safari/Hanzo AI/Shared (Extension)/SafariWebExtensionHandler.swift +0 -42
  124. package/dist/safari/Hanzo AI/iOS (App)/AppDelegate.swift +0 -24
  125. package/dist/safari/Hanzo AI/iOS (App)/Base.lproj/LaunchScreen.storyboard +0 -36
  126. package/dist/safari/Hanzo AI/iOS (App)/Base.lproj/Main.storyboard +0 -38
  127. package/dist/safari/Hanzo AI/iOS (App)/Info.plist +0 -27
  128. package/dist/safari/Hanzo AI/iOS (App)/SceneDelegate.swift +0 -18
  129. package/dist/safari/Hanzo AI/iOS (Extension)/Info.plist +0 -13
  130. package/dist/safari/Hanzo AI/macOS (App)/AppDelegate.swift +0 -21
  131. package/dist/safari/Hanzo AI/macOS (App)/Base.lproj/Main.storyboard +0 -124
  132. package/dist/safari/Hanzo AI/macOS (App)/Info.plist +0 -8
  133. package/dist/safari/Hanzo AI/macOS (Extension)/Info.plist +0 -13
  134. package/docs/_config.yml +0 -13
  135. package/docs/_layouts/default.html +0 -435
  136. package/docs/index.md +0 -54
  137. package/hanzo-ai-chrome-v1.7.6.zip +0 -0
  138. package/hanzo-ai-firefox-v1.7.6.zip +0 -0
  139. package/install-extension.sh +0 -75
  140. package/test/claude-integration.test.ts +0 -251
  141. package/test/server-frameworks-edge-cases.test.ts +0 -145
  142. package/test/server-frameworks.test.ts +0 -395
  143. package/test-cdp-connection.js +0 -140
  144. package/tsconfig.json +0 -19
@@ -1,495 +0,0 @@
1
- // src/webgpu-ai.ts
2
- var WebGPUAI = class {
3
- constructor() {
4
- this.device = null;
5
- this.models = /* @__PURE__ */ new Map();
6
- // ---------------------------------------------------------------------------
7
- // BPE Tokenizer (byte-level, GPT-2 compatible)
8
- // ---------------------------------------------------------------------------
9
- this.byteEncoder = {};
10
- this.byteDecoder = {};
11
- this.byteEncoderInitialized = false;
12
- // ---------------------------------------------------------------------------
13
- // WGSL Compute Shaders
14
- // ---------------------------------------------------------------------------
15
- this.matmulShader = `
16
- @group(0) @binding(0) var<storage, read> weights: array<f32>;
17
- @group(0) @binding(1) var<storage, read> input_tokens: array<f32>;
18
- @group(0) @binding(2) var<storage, read_write> output_logits: array<f32>;
19
- @group(0) @binding(3) var<storage, read> params: array<u32>;
20
-
21
- // params[0] = input_size
22
- // params[1] = output_size (vocab_size)
23
- // params[2] = weights_offset
24
-
25
- @compute @workgroup_size(256)
26
- fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
27
- let out_idx = gid.x;
28
- let input_size = params[0];
29
- let output_size = params[1];
30
- let w_offset = params[2];
31
-
32
- if (out_idx >= output_size) {
33
- return;
34
- }
35
-
36
- var sum: f32 = 0.0;
37
- for (var j: u32 = 0u; j < input_size; j = j + 1u) {
38
- let w_idx = w_offset + out_idx * input_size + j;
39
- if (w_idx < arrayLength(&weights)) {
40
- sum = sum + weights[w_idx] * input_tokens[j];
41
- }
42
- }
43
- output_logits[out_idx] = sum;
44
- }
45
- `;
46
- this.softmaxShader = `
47
- @group(0) @binding(0) var<storage, read_write> data: array<f32>;
48
- @group(0) @binding(1) var<storage, read> size_buf: array<u32>;
49
-
50
- @compute @workgroup_size(1)
51
- fn main() {
52
- let size = size_buf[0];
53
-
54
- var max_val: f32 = data[0];
55
- for (var i: u32 = 1u; i < size; i = i + 1u) {
56
- if (data[i] > max_val) {
57
- max_val = data[i];
58
- }
59
- }
60
-
61
- var sum: f32 = 0.0;
62
- for (var i: u32 = 0u; i < size; i = i + 1u) {
63
- let e = exp(data[i] - max_val);
64
- data[i] = e;
65
- sum = sum + e;
66
- }
67
-
68
- for (var i: u32 = 0u; i < size; i = i + 1u) {
69
- data[i] = data[i] / sum;
70
- }
71
- }
72
- `;
73
- }
74
- async initialize() {
75
- if (!navigator.gpu) {
76
- console.warn("[Hanzo AI] WebGPU not supported in this browser");
77
- return false;
78
- }
79
- try {
80
- const adapter = await navigator.gpu.requestAdapter({
81
- powerPreference: "high-performance"
82
- });
83
- if (!adapter) {
84
- console.warn("[Hanzo AI] No GPU adapter found");
85
- return false;
86
- }
87
- this.device = await adapter.requestDevice({
88
- requiredLimits: {
89
- maxStorageBufferBindingSize: adapter.limits?.maxStorageBufferBindingSize || 134217728,
90
- maxBufferSize: adapter.limits?.maxBufferSize || 268435456
91
- }
92
- });
93
- this.device.lost.then((info) => {
94
- console.error("[Hanzo AI] GPU device lost:", info.message);
95
- this.device = null;
96
- });
97
- console.log("[Hanzo AI] WebGPU initialized successfully");
98
- const features = adapter.features;
99
- console.log("[Hanzo AI] GPU Features:", Array.from(features));
100
- return true;
101
- } catch (error) {
102
- console.error("[Hanzo AI] WebGPU initialization failed:", error);
103
- return false;
104
- }
105
- }
106
- initByteEncoder() {
107
- if (this.byteEncoderInitialized) return;
108
- const bs = [];
109
- for (let i = 33; i <= 126; i++) bs.push(i);
110
- for (let i = 161; i <= 172; i++) bs.push(i);
111
- for (let i = 174; i <= 255; i++) bs.push(i);
112
- const cs = bs.slice();
113
- let n = 0;
114
- for (let b = 0; b < 256; b++) {
115
- if (!bs.includes(b)) {
116
- bs.push(b);
117
- cs.push(256 + n);
118
- n++;
119
- }
120
- }
121
- for (let i = 0; i < bs.length; i++) {
122
- this.byteEncoder[bs[i]] = String.fromCharCode(cs[i]);
123
- this.byteDecoder[String.fromCharCode(cs[i])] = bs[i];
124
- }
125
- this.byteEncoderInitialized = true;
126
- }
127
- tokenize(text, model) {
128
- this.initByteEncoder();
129
- if (!model.vocab.length) {
130
- const tokens2 = [];
131
- for (let i = 0; i < text.length; i++) {
132
- tokens2.push(text.charCodeAt(i));
133
- }
134
- return tokens2;
135
- }
136
- const bytes = new TextEncoder().encode(text);
137
- let word = "";
138
- for (const b of bytes) {
139
- word += this.byteEncoder[b] || String.fromCharCode(b);
140
- }
141
- const tokens = [];
142
- let pos = 0;
143
- while (pos < word.length) {
144
- let bestLen = 0;
145
- let bestIdx = -1;
146
- const maxLen = Math.min(word.length - pos, 50);
147
- for (let len = maxLen; len >= 1; len--) {
148
- const candidate = word.substring(pos, pos + len);
149
- const idx = model.vocabIndex.get(candidate);
150
- if (idx !== void 0) {
151
- bestLen = len;
152
- bestIdx = idx;
153
- break;
154
- }
155
- }
156
- if (bestIdx !== -1) {
157
- tokens.push(bestIdx);
158
- pos += bestLen;
159
- } else {
160
- tokens.push(word.charCodeAt(pos) % Math.max(model.vocab.length, 1));
161
- pos++;
162
- }
163
- }
164
- return tokens;
165
- }
166
- detokenize(tokenIds, model) {
167
- this.initByteEncoder();
168
- if (!model.vocab.length) {
169
- const arr = tokenIds instanceof Int32Array ? Array.from(tokenIds) : tokenIds;
170
- return String.fromCharCode(...arr.filter((t) => t > 0 && t < 65536));
171
- }
172
- let byteStr = "";
173
- for (const id of tokenIds) {
174
- if (id >= 0 && id < model.vocab.length) {
175
- byteStr += model.vocab[id];
176
- }
177
- }
178
- const decoded = [];
179
- for (const ch of byteStr) {
180
- if (ch in this.byteDecoder) {
181
- decoded.push(this.byteDecoder[ch]);
182
- } else {
183
- decoded.push(ch.charCodeAt(0) & 255);
184
- }
185
- }
186
- return new TextDecoder().decode(new Uint8Array(decoded));
187
- }
188
- // ---------------------------------------------------------------------------
189
- // Model Loading
190
- // ---------------------------------------------------------------------------
191
- async loadModel(config) {
192
- if (!this.device) {
193
- throw new Error("WebGPU not initialized");
194
- }
195
- console.log(`[Hanzo AI] Loading model: ${config.name}`);
196
- const response = await fetch(config.url);
197
- if (!response.ok) {
198
- throw new Error(`Failed to fetch model ${config.name}: ${response.status}`);
199
- }
200
- const modelData = await response.arrayBuffer();
201
- const modelBuffer = this.device.createBuffer({
202
- size: modelData.byteLength,
203
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
204
- label: `model-${config.name}`
205
- });
206
- this.device.queue.writeBuffer(modelBuffer, 0, modelData);
207
- let vocab = [];
208
- const vocabIndex = /* @__PURE__ */ new Map();
209
- if (config.vocabUrl) {
210
- try {
211
- const vocabResp = await fetch(config.vocabUrl);
212
- if (vocabResp.ok) {
213
- const vocabData = await vocabResp.json();
214
- if (Array.isArray(vocabData)) {
215
- vocab = vocabData;
216
- } else if (typeof vocabData === "object") {
217
- const entries = Object.entries(vocabData);
218
- entries.sort((a, b) => a[1] - b[1]);
219
- vocab = entries.map((e) => e[0]);
220
- }
221
- for (let i = 0; i < vocab.length; i++) {
222
- vocabIndex.set(vocab[i], i);
223
- }
224
- }
225
- } catch (e) {
226
- console.warn(`[Hanzo AI] Vocabulary load failed for ${config.name}:`, e);
227
- }
228
- }
229
- this.models.set(config.name, {
230
- buffer: modelBuffer,
231
- config,
232
- vocab,
233
- vocabIndex
234
- });
235
- console.log(`[Hanzo AI] Model ${config.name} loaded: ${modelData.byteLength} bytes, vocab: ${vocab.length}`);
236
- }
237
- // ---------------------------------------------------------------------------
238
- // Inference
239
- // ---------------------------------------------------------------------------
240
- async runInference(modelName, input) {
241
- const model = this.models.get(modelName);
242
- if (!model || !this.device) {
243
- throw new Error(`Model ${modelName} not loaded or GPU unavailable`);
244
- }
245
- const tokens = this.tokenize(input, model);
246
- const vocabSize = Math.max(model.vocab.length, 256);
247
- const inputSize = Math.min(tokens.length, 2048);
248
- const maxTokens = model.config.maxTokens || 128;
249
- const inputData = new Float32Array(inputSize);
250
- for (let i = 0; i < inputSize; i++) {
251
- inputData[i] = tokens[i] / vocabSize;
252
- }
253
- const inputBuffer = this.device.createBuffer({
254
- size: inputData.byteLength,
255
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
256
- label: "input"
257
- });
258
- this.device.queue.writeBuffer(inputBuffer, 0, inputData);
259
- const outputByteSize = vocabSize * 4;
260
- const outputBuffer = this.device.createBuffer({
261
- size: outputByteSize,
262
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
263
- label: "output"
264
- });
265
- const paramsData = new Uint32Array([inputSize, vocabSize, 0]);
266
- const paramsBuffer = this.device.createBuffer({
267
- size: paramsData.byteLength,
268
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
269
- label: "params"
270
- });
271
- this.device.queue.writeBuffer(paramsBuffer, 0, paramsData);
272
- const readBuffer = this.device.createBuffer({
273
- size: outputByteSize,
274
- usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ,
275
- label: "readback"
276
- });
277
- const matmulModule = this.device.createShaderModule({ code: this.matmulShader });
278
- const matmulLayout = this.device.createBindGroupLayout({
279
- entries: [
280
- { binding: 0, visibility: GPUShaderStage.COMPUTE, buffer: { type: "read-only-storage" } },
281
- { binding: 1, visibility: GPUShaderStage.COMPUTE, buffer: { type: "read-only-storage" } },
282
- { binding: 2, visibility: GPUShaderStage.COMPUTE, buffer: { type: "storage" } },
283
- { binding: 3, visibility: GPUShaderStage.COMPUTE, buffer: { type: "read-only-storage" } }
284
- ]
285
- });
286
- const matmulPipeline = this.device.createComputePipeline({
287
- layout: this.device.createPipelineLayout({ bindGroupLayouts: [matmulLayout] }),
288
- compute: { module: matmulModule, entryPoint: "main" }
289
- });
290
- const matmulBindGroup = this.device.createBindGroup({
291
- layout: matmulLayout,
292
- entries: [
293
- { binding: 0, resource: { buffer: model.buffer } },
294
- { binding: 1, resource: { buffer: inputBuffer } },
295
- { binding: 2, resource: { buffer: outputBuffer } },
296
- { binding: 3, resource: { buffer: paramsBuffer } }
297
- ]
298
- });
299
- const softmaxModule = this.device.createShaderModule({ code: this.softmaxShader });
300
- const softmaxLayout = this.device.createBindGroupLayout({
301
- entries: [
302
- { binding: 0, visibility: GPUShaderStage.COMPUTE, buffer: { type: "storage" } },
303
- { binding: 1, visibility: GPUShaderStage.COMPUTE, buffer: { type: "read-only-storage" } }
304
- ]
305
- });
306
- const sizeBuf = this.device.createBuffer({
307
- size: 4,
308
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST
309
- });
310
- this.device.queue.writeBuffer(sizeBuf, 0, new Uint32Array([vocabSize]));
311
- const softmaxPipeline = this.device.createComputePipeline({
312
- layout: this.device.createPipelineLayout({ bindGroupLayouts: [softmaxLayout] }),
313
- compute: { module: softmaxModule, entryPoint: "main" }
314
- });
315
- const softmaxBindGroup = this.device.createBindGroup({
316
- layout: softmaxLayout,
317
- entries: [
318
- { binding: 0, resource: { buffer: outputBuffer } },
319
- { binding: 1, resource: { buffer: sizeBuf } }
320
- ]
321
- });
322
- const generatedTokens = [];
323
- const temperature = 0.7;
324
- for (let step = 0; step < maxTokens; step++) {
325
- const encoder = this.device.createCommandEncoder();
326
- const matmulPass = encoder.beginComputePass();
327
- matmulPass.setPipeline(matmulPipeline);
328
- matmulPass.setBindGroup(0, matmulBindGroup);
329
- matmulPass.dispatchWorkgroups(Math.ceil(vocabSize / 256));
330
- matmulPass.end();
331
- const softmaxPass = encoder.beginComputePass();
332
- softmaxPass.setPipeline(softmaxPipeline);
333
- softmaxPass.setBindGroup(0, softmaxBindGroup);
334
- softmaxPass.dispatchWorkgroups(1);
335
- softmaxPass.end();
336
- encoder.copyBufferToBuffer(outputBuffer, 0, readBuffer, 0, outputByteSize);
337
- this.device.queue.submit([encoder.finish()]);
338
- await readBuffer.mapAsync(GPUMapMode.READ);
339
- const probs = new Float32Array(readBuffer.getMappedRange().slice(0));
340
- readBuffer.unmap();
341
- const nextToken = this.sampleToken(probs, temperature);
342
- generatedTokens.push(nextToken);
343
- if (nextToken === 0 || nextToken === 2) break;
344
- const newInput = new Float32Array([nextToken / vocabSize]);
345
- this.device.queue.writeBuffer(inputBuffer, 0, newInput);
346
- paramsData[0] = 1;
347
- this.device.queue.writeBuffer(paramsBuffer, 0, paramsData);
348
- }
349
- inputBuffer.destroy();
350
- outputBuffer.destroy();
351
- paramsBuffer.destroy();
352
- readBuffer.destroy();
353
- sizeBuf.destroy();
354
- return this.detokenize(generatedTokens, model);
355
- }
356
- sampleToken(probs, temperature) {
357
- if (temperature <= 0) {
358
- let maxIdx = 0;
359
- let maxVal = probs[0];
360
- for (let i = 1; i < probs.length; i++) {
361
- if (probs[i] > maxVal) {
362
- maxVal = probs[i];
363
- maxIdx = i;
364
- }
365
- }
366
- return maxIdx;
367
- }
368
- const scaled = new Float32Array(probs.length);
369
- let sum = 0;
370
- for (let i = 0; i < probs.length; i++) {
371
- scaled[i] = Math.exp(Math.log(Math.max(probs[i], 1e-10)) / temperature);
372
- sum += scaled[i];
373
- }
374
- for (let i = 0; i < scaled.length; i++) {
375
- scaled[i] /= sum;
376
- }
377
- const r = Math.random();
378
- let cumulative = 0;
379
- for (let i = 0; i < scaled.length; i++) {
380
- cumulative += scaled[i];
381
- if (r < cumulative) return i;
382
- }
383
- return scaled.length - 1;
384
- }
385
- // ---------------------------------------------------------------------------
386
- // Embedding computation (for DOM element analysis)
387
- // ---------------------------------------------------------------------------
388
- async computeEmbedding(modelName, text) {
389
- const model = this.models.get(modelName);
390
- if (!model || !this.device) {
391
- throw new Error(`Model ${modelName} not loaded or GPU unavailable`);
392
- }
393
- const tokens = this.tokenize(text, model);
394
- const inputSize = Math.min(tokens.length, 512);
395
- const embeddingDim = 256;
396
- const inputData = new Float32Array(inputSize);
397
- for (let i = 0; i < inputSize; i++) {
398
- inputData[i] = tokens[i];
399
- }
400
- const inputBuffer = this.device.createBuffer({
401
- size: inputData.byteLength,
402
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST
403
- });
404
- this.device.queue.writeBuffer(inputBuffer, 0, inputData);
405
- const embeddingBuffer = this.device.createBuffer({
406
- size: embeddingDim * 4,
407
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST
408
- });
409
- const paramData = new Uint32Array([inputSize, embeddingDim, 0]);
410
- const paramBuffer = this.device.createBuffer({
411
- size: paramData.byteLength,
412
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST
413
- });
414
- this.device.queue.writeBuffer(paramBuffer, 0, paramData);
415
- const shaderModule = this.device.createShaderModule({ code: this.matmulShader });
416
- const layout = this.device.createBindGroupLayout({
417
- entries: [
418
- { binding: 0, visibility: GPUShaderStage.COMPUTE, buffer: { type: "read-only-storage" } },
419
- { binding: 1, visibility: GPUShaderStage.COMPUTE, buffer: { type: "read-only-storage" } },
420
- { binding: 2, visibility: GPUShaderStage.COMPUTE, buffer: { type: "storage" } },
421
- { binding: 3, visibility: GPUShaderStage.COMPUTE, buffer: { type: "read-only-storage" } }
422
- ]
423
- });
424
- const pipeline = this.device.createComputePipeline({
425
- layout: this.device.createPipelineLayout({ bindGroupLayouts: [layout] }),
426
- compute: { module: shaderModule, entryPoint: "main" }
427
- });
428
- const bindGroup = this.device.createBindGroup({
429
- layout,
430
- entries: [
431
- { binding: 0, resource: { buffer: model.buffer } },
432
- { binding: 1, resource: { buffer: inputBuffer } },
433
- { binding: 2, resource: { buffer: embeddingBuffer } },
434
- { binding: 3, resource: { buffer: paramBuffer } }
435
- ]
436
- });
437
- const readBuffer = this.device.createBuffer({
438
- size: embeddingDim * 4,
439
- usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
440
- });
441
- const encoder = this.device.createCommandEncoder();
442
- const pass = encoder.beginComputePass();
443
- pass.setPipeline(pipeline);
444
- pass.setBindGroup(0, bindGroup);
445
- pass.dispatchWorkgroups(Math.ceil(embeddingDim / 256));
446
- pass.end();
447
- encoder.copyBufferToBuffer(embeddingBuffer, 0, readBuffer, 0, embeddingDim * 4);
448
- this.device.queue.submit([encoder.finish()]);
449
- await readBuffer.mapAsync(GPUMapMode.READ);
450
- const embedding = new Float32Array(readBuffer.getMappedRange().slice(0));
451
- readBuffer.unmap();
452
- let norm = 0;
453
- for (let i = 0; i < embedding.length; i++) {
454
- norm += embedding[i] * embedding[i];
455
- }
456
- norm = Math.sqrt(norm);
457
- if (norm > 0) {
458
- for (let i = 0; i < embedding.length; i++) {
459
- embedding[i] /= norm;
460
- }
461
- }
462
- inputBuffer.destroy();
463
- embeddingBuffer.destroy();
464
- paramBuffer.destroy();
465
- readBuffer.destroy();
466
- return embedding;
467
- }
468
- // ---------------------------------------------------------------------------
469
- // Status / Cleanup
470
- // ---------------------------------------------------------------------------
471
- getStatus() {
472
- return {
473
- initialized: !!this.device,
474
- models: Array.from(this.models.keys())
475
- };
476
- }
477
- async unloadModel(name) {
478
- const model = this.models.get(name);
479
- if (model) {
480
- model.buffer.destroy();
481
- this.models.delete(name);
482
- console.log(`[Hanzo AI] Model ${name} unloaded`);
483
- }
484
- }
485
- destroy() {
486
- for (const [name, model] of this.models) {
487
- model.buffer.destroy();
488
- }
489
- this.models.clear();
490
- this.device = null;
491
- }
492
- };
493
- export {
494
- WebGPUAI
495
- };