webml-kit 0.1.0

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.
@@ -0,0 +1,325 @@
1
+ /**
2
+ * Main-thread client for communicating with the ML worker.
3
+ *
4
+ * Wraps the Web Worker's postMessage protocol with a promise-based API,
5
+ * AsyncIterable token streaming, and typed events.
6
+ *
7
+ * ```ts
8
+ * import { ModelClient } from 'webml-kit';
9
+ *
10
+ * const client = new ModelClient();
11
+ *
12
+ * // Check device capabilities
13
+ * const device = await client.detect();
14
+ * console.log(device.backend); // 'webgpu'
15
+ *
16
+ * // Load a model
17
+ * await client.load({
18
+ * task: 'text-generation',
19
+ * modelId: 'onnx-community/Bonsai-1.7B-ONNX',
20
+ * dtype: 'q4',
21
+ * onProgress: ({ percent }) => console.log(`${percent}%`),
22
+ * });
23
+ *
24
+ * // Stream text generation
25
+ * for await (const { token, tps } of client.stream('Hello!')) {
26
+ * process.stdout.write(token);
27
+ * }
28
+ *
29
+ * // One-shot inference
30
+ * const labels = await client.run('image-classification', imageBlob);
31
+ * ```
32
+ */
33
+ import { TokenStream, collectStream } from './streaming.js';
34
+ import { GPURecovery } from './gpu-recovery.js';
35
+ // ─── Client ───
36
+ export class ModelClient {
37
+ worker = null;
38
+ workerUrl;
39
+ listeners = new Map();
40
+ pendingRequests = new Map();
41
+ requestCounter = 0;
42
+ deviceInfo = null;
43
+ loadedModels = new Set();
44
+ progressCallback = null;
45
+ gpuRecovery;
46
+ /**
47
+ * Create a new ModelClient.
48
+ *
49
+ * @param workerUrl - URL to the model-worker.js file. If omitted,
50
+ * creates a Blob URL from the bundled worker (requires bundler support).
51
+ */
52
+ constructor(workerUrl) {
53
+ this.workerUrl = workerUrl ?? null;
54
+ this.gpuRecovery = new GPURecovery();
55
+ this.gpuRecovery.on('lost', ({ reason }) => {
56
+ this.emit('device-lost', { reason });
57
+ });
58
+ this.gpuRecovery.on('recovered', () => {
59
+ this.emit('device-recovered', {});
60
+ });
61
+ }
62
+ // ─── Worker Lifecycle ───
63
+ getWorker() {
64
+ if (!this.worker) {
65
+ if (this.workerUrl) {
66
+ this.worker = new Worker(this.workerUrl, { type: 'module' });
67
+ }
68
+ else {
69
+ // Inline worker via Blob URL
70
+ // Users should provide their own worker URL or use a bundler
71
+ // that handles `new Worker(new URL('./model-worker.js', import.meta.url))`
72
+ throw new Error('No worker URL provided. Pass the URL to your model-worker.js file, ' +
73
+ 'e.g. new ModelClient(new URL("webml-kit/worker", import.meta.url))');
74
+ }
75
+ this.worker.addEventListener('message', this.handleMessage.bind(this));
76
+ this.worker.addEventListener('error', (e) => {
77
+ this.emit('error', { message: e.message });
78
+ });
79
+ }
80
+ return this.worker;
81
+ }
82
+ send(cmd) {
83
+ this.getWorker().postMessage(cmd);
84
+ }
85
+ nextId() {
86
+ return `req_${++this.requestCounter}_${Date.now()}`;
87
+ }
88
+ // ─── Message Handler ───
89
+ handleMessage(e) {
90
+ const msg = e.data;
91
+ switch (msg.type) {
92
+ case 'device-info': {
93
+ this.deviceInfo = msg.data;
94
+ const pending = this.pendingRequests.get('detect');
95
+ if (pending) {
96
+ pending.resolve(msg.data);
97
+ this.pendingRequests.delete('detect');
98
+ }
99
+ break;
100
+ }
101
+ case 'progress': {
102
+ this.progressCallback?.(msg.data);
103
+ this.emit('progress', msg.data);
104
+ break;
105
+ }
106
+ case 'ready': {
107
+ this.loadedModels.add(msg.modelKey);
108
+ this.emit('ready', { modelKey: msg.modelKey });
109
+ const pending = this.pendingRequests.get('load');
110
+ if (pending) {
111
+ pending.resolve(undefined);
112
+ this.pendingRequests.delete('load');
113
+ }
114
+ break;
115
+ }
116
+ case 'token': {
117
+ const pending = this.pendingRequests.get(msg.id);
118
+ if (pending?.stream) {
119
+ pending.stream.push(msg.data);
120
+ }
121
+ break;
122
+ }
123
+ case 'result': {
124
+ const pending = this.pendingRequests.get(msg.id);
125
+ if (pending) {
126
+ if (pending.stream) {
127
+ pending.stream.end();
128
+ }
129
+ pending.resolve(msg.data);
130
+ this.pendingRequests.delete(msg.id);
131
+ }
132
+ break;
133
+ }
134
+ case 'error': {
135
+ const pending = this.pendingRequests.get(msg.id);
136
+ if (pending) {
137
+ if (pending.stream) {
138
+ pending.stream.abort(new Error(msg.data));
139
+ }
140
+ pending.reject(new Error(msg.data));
141
+ this.pendingRequests.delete(msg.id);
142
+ }
143
+ this.emit('error', { message: msg.data, id: msg.id });
144
+ break;
145
+ }
146
+ case 'device-lost': {
147
+ this.emit('device-lost', { reason: msg.reason });
148
+ break;
149
+ }
150
+ case 'device-recovered': {
151
+ this.emit('device-recovered', {});
152
+ break;
153
+ }
154
+ }
155
+ }
156
+ // ─── Events ───
157
+ /** Register an event listener. */
158
+ on(event, listener) {
159
+ if (!this.listeners.has(event)) {
160
+ this.listeners.set(event, new Set());
161
+ }
162
+ this.listeners.get(event).add(listener);
163
+ return this;
164
+ }
165
+ /** Remove an event listener. */
166
+ off(event, listener) {
167
+ this.listeners.get(event)?.delete(listener);
168
+ return this;
169
+ }
170
+ emit(event, data) {
171
+ this.listeners.get(event)?.forEach(fn => fn(data));
172
+ }
173
+ // ─── Public API ───
174
+ /**
175
+ * Detect the best available compute backend.
176
+ *
177
+ * ```ts
178
+ * const info = await client.detect();
179
+ * console.log(info.backend); // 'webgpu'
180
+ * console.log(info.gpu?.vendor); // 'apple'
181
+ * console.log(info.recommendedDtype); // 'q4'
182
+ * ```
183
+ */
184
+ async detect() {
185
+ if (this.deviceInfo)
186
+ return this.deviceInfo;
187
+ return new Promise((resolve, reject) => {
188
+ this.pendingRequests.set('detect', { resolve: resolve, reject });
189
+ this.send({ type: 'check' });
190
+ });
191
+ }
192
+ /**
193
+ * Load a model pipeline.
194
+ *
195
+ * ```ts
196
+ * await client.load({
197
+ * task: 'text-generation',
198
+ * modelId: 'onnx-community/Bonsai-1.7B-ONNX',
199
+ * dtype: 'q4',
200
+ * onProgress: ({ percent }) => updateUI(percent),
201
+ * });
202
+ * ```
203
+ */
204
+ async load(options) {
205
+ this.progressCallback = options.onProgress ?? null;
206
+ const config = {
207
+ task: options.task,
208
+ modelId: options.modelId,
209
+ dtype: options.dtype,
210
+ device: options.device,
211
+ revision: options.revision,
212
+ };
213
+ return new Promise((resolve, reject) => {
214
+ this.pendingRequests.set('load', { resolve: resolve, reject });
215
+ this.send({ type: 'load', config });
216
+ });
217
+ }
218
+ /**
219
+ * Run one-shot inference for any pipeline task.
220
+ *
221
+ * ```ts
222
+ * // Image classification
223
+ * const labels = await client.run('image-classification', imageUrl);
224
+ *
225
+ * // Speech recognition
226
+ * const { text } = await client.run('automatic-speech-recognition', audioBlob);
227
+ *
228
+ * // Embeddings
229
+ * const vectors = await client.run('feature-extraction', 'Hello world');
230
+ * ```
231
+ */
232
+ async run(task, input, options) {
233
+ const id = this.nextId();
234
+ return new Promise((resolve, reject) => {
235
+ this.pendingRequests.set(id, { resolve: resolve, reject });
236
+ this.send({ type: 'run', id, task, input, options });
237
+ });
238
+ }
239
+ /**
240
+ * Generate text with streaming tokens.
241
+ *
242
+ * Returns an `AsyncIterable<TokenEvent>` that yields tokens as they're generated.
243
+ *
244
+ * ```ts
245
+ * for await (const { token, tps } of client.stream('Tell me a joke')) {
246
+ * process.stdout.write(token);
247
+ * }
248
+ * ```
249
+ */
250
+ stream(input, options) {
251
+ const id = this.nextId();
252
+ const stream = new TokenStream(options?.signal);
253
+ this.pendingRequests.set(id, {
254
+ resolve: () => { }, // Result comes through the stream
255
+ reject: (err) => stream.abort(err),
256
+ stream,
257
+ });
258
+ this.send({
259
+ type: 'run',
260
+ id,
261
+ task: 'text-generation',
262
+ input,
263
+ options: options,
264
+ });
265
+ return stream;
266
+ }
267
+ /**
268
+ * Generate text and wait for the complete result.
269
+ *
270
+ * ```ts
271
+ * const { text, tps, numTokens } = await client.generate('Hello!');
272
+ * ```
273
+ */
274
+ async generate(input, options) {
275
+ const tokenStream = this.stream(input, options);
276
+ const collected = await collectStream(tokenStream);
277
+ return {
278
+ ...collected,
279
+ totalTime: 0, // Will be filled from worker result
280
+ };
281
+ }
282
+ /**
283
+ * Interrupt an ongoing text generation.
284
+ */
285
+ interrupt() {
286
+ this.send({ type: 'interrupt' });
287
+ }
288
+ /**
289
+ * Reset the KV cache (start a new conversation).
290
+ */
291
+ reset() {
292
+ this.send({ type: 'reset' });
293
+ }
294
+ /**
295
+ * Dispose a loaded model and free memory.
296
+ *
297
+ * @param modelKey - Specific model key (task::modelId), or omit to dispose all.
298
+ */
299
+ dispose(modelKey) {
300
+ this.send({ type: 'dispose', modelKey });
301
+ if (modelKey) {
302
+ this.loadedModels.delete(modelKey);
303
+ }
304
+ else {
305
+ this.loadedModels.clear();
306
+ }
307
+ }
308
+ /**
309
+ * Check if a model is currently loaded.
310
+ */
311
+ isLoaded(task, modelId) {
312
+ return this.loadedModels.has(`${task}::${modelId}`);
313
+ }
314
+ /**
315
+ * Terminate the worker completely.
316
+ */
317
+ terminate() {
318
+ this.worker?.terminate();
319
+ this.worker = null;
320
+ this.loadedModels.clear();
321
+ this.pendingRequests.clear();
322
+ this.deviceInfo = null;
323
+ }
324
+ }
325
+ //# sourceMappingURL=model-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-client.js","sourceRoot":"","sources":["../src/model-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Generic Web Worker for running ML pipelines.
3
+ *
4
+ * This file runs in a Web Worker thread. It handles:
5
+ * - WebGPU device detection + WASM fallback
6
+ * - Pipeline instantiation (singleton, keyed by task+model)
7
+ * - Progress reporting during model download
8
+ * - Text generation with streaming + KV cache
9
+ * - One-shot inference for classification, detection, ASR, etc.
10
+ * - GPU device-lost recovery
11
+ * - Memory cleanup
12
+ *
13
+ * Communication is via structured `postMessage` using WorkerCommand/WorkerResponse types.
14
+ */
15
+ export {};
16
+ //# sourceMappingURL=model-worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-worker.d.ts","sourceRoot":"","sources":["../src/model-worker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG"}
@@ -0,0 +1,303 @@
1
+ /**
2
+ * Generic Web Worker for running ML pipelines.
3
+ *
4
+ * This file runs in a Web Worker thread. It handles:
5
+ * - WebGPU device detection + WASM fallback
6
+ * - Pipeline instantiation (singleton, keyed by task+model)
7
+ * - Progress reporting during model download
8
+ * - Text generation with streaming + KV cache
9
+ * - One-shot inference for classification, detection, ASR, etc.
10
+ * - GPU device-lost recovery
11
+ * - Memory cleanup
12
+ *
13
+ * Communication is via structured `postMessage` using WorkerCommand/WorkerResponse types.
14
+ */
15
+ import { pipeline as hfPipeline, TextStreamer, DynamicCache, InterruptableStoppingCriteria, } from '@huggingface/transformers';
16
+ const instances = new Map();
17
+ const kvCaches = new Map();
18
+ const stoppingCriteria = new InterruptableStoppingCriteria();
19
+ function modelKey(task, modelId) {
20
+ return `${task}::${modelId}`;
21
+ }
22
+ // ─── Helpers ───
23
+ function send(msg) {
24
+ self.postMessage(msg);
25
+ }
26
+ // ─── Device Check ───
27
+ async function checkDevice() {
28
+ let backend = 'cpu';
29
+ let gpu = null;
30
+ try {
31
+ if ('gpu' in navigator) {
32
+ const adapter = await navigator.gpu.requestAdapter({
33
+ powerPreference: 'high-performance',
34
+ });
35
+ if (adapter) {
36
+ backend = 'webgpu';
37
+ const info = adapter.info;
38
+ const vram = Number(adapter.limits?.maxBufferSize ?? 0);
39
+ const fmtVram = vram >= 1024 ** 3
40
+ ? `${(vram / 1024 ** 3).toFixed(1)} GB`
41
+ : `${(vram / 1024 ** 2).toFixed(1)} MB`;
42
+ gpu = {
43
+ vendor: info?.vendor ?? 'unknown',
44
+ architecture: info?.architecture ?? 'unknown',
45
+ description: info?.description ?? 'unknown',
46
+ vram,
47
+ vramFormatted: fmtVram,
48
+ };
49
+ }
50
+ }
51
+ }
52
+ catch {
53
+ // WebGPU not available
54
+ }
55
+ if (backend === 'cpu' && typeof WebAssembly !== 'undefined') {
56
+ backend = 'wasm';
57
+ }
58
+ // Simple VRAM-based dtype recommendation
59
+ const vram = gpu?.vram ?? 0;
60
+ const recommendedDtype = vram >= 8e9 ? 'fp16' : vram >= 4e9 ? 'q8' : 'q4';
61
+ send({ type: 'device-info', data: { backend, gpu, recommendedDtype } });
62
+ }
63
+ // ─── Load Pipeline ───
64
+ async function loadPipeline(config) {
65
+ const key = modelKey(config.task, config.modelId);
66
+ // Dispose previous KV cache if switching models for same task
67
+ if (kvCaches.has(key)) {
68
+ kvCaches.get(key)?.dispose?.();
69
+ kvCaches.delete(key);
70
+ }
71
+ send({
72
+ type: 'progress',
73
+ data: { status: 'downloading', loaded: 0, total: 0, percent: 0 },
74
+ });
75
+ // Create singleton pipeline
76
+ if (!instances.has(key)) {
77
+ const pipelinePromise = hfPipeline(config.task, config.modelId, {
78
+ device: config.device ?? 'webgpu',
79
+ dtype: config.dtype ?? 'q4',
80
+ revision: config.revision,
81
+ progress_callback: (info) => {
82
+ if (info.status === 'progress' || info.status === 'progress_total') {
83
+ const loaded = Number(info.loaded ?? 0);
84
+ const total = Number(info.total ?? 1);
85
+ send({
86
+ type: 'progress',
87
+ data: {
88
+ status: 'downloading',
89
+ file: String(info.file ?? ''),
90
+ loaded,
91
+ total,
92
+ percent: total > 0 ? Math.round((loaded / total) * 100) : 0,
93
+ },
94
+ });
95
+ }
96
+ },
97
+ });
98
+ instances.set(key, pipelinePromise);
99
+ }
100
+ try {
101
+ const generator = await instances.get(key);
102
+ // Warm up with dummy inference (compiles WebGPU shaders)
103
+ send({
104
+ type: 'progress',
105
+ data: { status: 'compiling', loaded: 0, total: 0, percent: 100 },
106
+ });
107
+ if (config.task === 'text-generation' && 'tokenizer' in generator) {
108
+ const tokenizer = generator.tokenizer;
109
+ const model = generator.model;
110
+ if (tokenizer && model && typeof tokenizer === 'function') {
111
+ const inputs = tokenizer('a');
112
+ await model.generate({
113
+ ...inputs,
114
+ max_new_tokens: 1,
115
+ });
116
+ }
117
+ }
118
+ send({ type: 'ready', modelKey: key });
119
+ }
120
+ catch (e) {
121
+ instances.delete(key);
122
+ send({
123
+ type: 'error',
124
+ id: 'load',
125
+ data: e instanceof Error ? e.message : String(e),
126
+ });
127
+ }
128
+ }
129
+ // ─── Run Inference ───
130
+ async function runInference(id, task, input, options) {
131
+ // Find the loaded pipeline for this task
132
+ let pipelineInstance = null;
133
+ for (const [key, promise] of instances) {
134
+ if (key.startsWith(`${task}::`)) {
135
+ pipelineInstance = await promise;
136
+ break;
137
+ }
138
+ }
139
+ if (!pipelineInstance) {
140
+ send({ type: 'error', id, data: `No pipeline loaded for task: ${task}` });
141
+ return;
142
+ }
143
+ try {
144
+ if (task === 'text-generation') {
145
+ await runTextGeneration(id, pipelineInstance, input, options);
146
+ }
147
+ else {
148
+ // One-shot inference for all other tasks
149
+ const result = await pipelineInstance(input, options);
150
+ send({ type: 'result', id, data: result });
151
+ }
152
+ }
153
+ catch (e) {
154
+ send({
155
+ type: 'error',
156
+ id,
157
+ data: e instanceof Error ? e.message : String(e),
158
+ });
159
+ }
160
+ }
161
+ // ─── Text Generation (Streaming) ───
162
+ async function runTextGeneration(id, generator, messages, options) {
163
+ let startTime = null;
164
+ let numTokens = 0;
165
+ let tps = 0;
166
+ let firstTokenTime = 0;
167
+ const genObj = generator;
168
+ if (typeof genObj !== 'function' && !('tokenizer' in genObj)) {
169
+ send({ type: 'error', id, data: 'Invalid text-generation pipeline' });
170
+ return;
171
+ }
172
+ const streamer = new TextStreamer(genObj.tokenizer, {
173
+ skip_prompt: true,
174
+ skip_special_tokens: true,
175
+ callback_function: (output) => {
176
+ const event = {
177
+ token: output,
178
+ tps,
179
+ numTokens,
180
+ timeToFirstToken: firstTokenTime,
181
+ };
182
+ send({ type: 'token', id, data: event });
183
+ },
184
+ token_callback_function: () => {
185
+ const now = performance.now();
186
+ if (startTime === null) {
187
+ startTime = now;
188
+ firstTokenTime = now; // Will be relative to request start
189
+ }
190
+ numTokens++;
191
+ if (numTokens > 1 && startTime !== null) {
192
+ tps = (numTokens / (now - startTime)) * 1000;
193
+ }
194
+ },
195
+ });
196
+ // Get or create KV cache for this task+model
197
+ const key = [...instances.keys()].find(k => k.startsWith('text-generation::'));
198
+ if (key && !kvCaches.has(key)) {
199
+ kvCaches.set(key, new DynamicCache());
200
+ }
201
+ const pastKeyValues = key ? kvCaches.get(key) : undefined;
202
+ stoppingCriteria.reset();
203
+ const genOptions = {
204
+ max_new_tokens: options?.maxNewTokens ?? 1024,
205
+ do_sample: options?.doSample ?? false,
206
+ temperature: options?.temperature,
207
+ top_p: options?.topP,
208
+ top_k: options?.topK,
209
+ repetition_penalty: options?.repetitionPenalty,
210
+ streamer,
211
+ stopping_criteria: stoppingCriteria,
212
+ ...(pastKeyValues ? { past_key_values: pastKeyValues } : {}),
213
+ };
214
+ // Remove undefined keys
215
+ for (const k of Object.keys(genOptions)) {
216
+ if (genOptions[k] === undefined)
217
+ delete genOptions[k];
218
+ }
219
+ try {
220
+ const output = await genObj(messages, genOptions);
221
+ // Extract final text
222
+ let finalText = '';
223
+ if (Array.isArray(output) && output[0]?.generated_text) {
224
+ const genText = output[0].generated_text;
225
+ finalText = Array.isArray(genText)
226
+ ? genText[genText.length - 1]?.content ?? ''
227
+ : genText;
228
+ }
229
+ send({
230
+ type: 'result',
231
+ id,
232
+ data: {
233
+ text: finalText,
234
+ numTokens,
235
+ tps,
236
+ timeToFirstToken: firstTokenTime,
237
+ totalTime: startTime ? performance.now() - startTime : 0,
238
+ },
239
+ });
240
+ }
241
+ catch (e) {
242
+ send({
243
+ type: 'error',
244
+ id,
245
+ data: e instanceof Error ? e.message : String(e),
246
+ });
247
+ }
248
+ }
249
+ // ─── Cleanup ───
250
+ function disposeModel(targetKey) {
251
+ if (targetKey) {
252
+ instances.delete(targetKey);
253
+ if (kvCaches.has(targetKey)) {
254
+ kvCaches.get(targetKey)?.dispose?.();
255
+ kvCaches.delete(targetKey);
256
+ }
257
+ }
258
+ else {
259
+ instances.clear();
260
+ for (const cache of kvCaches.values()) {
261
+ cache?.dispose?.();
262
+ }
263
+ kvCaches.clear();
264
+ }
265
+ }
266
+ function resetKVCache() {
267
+ stoppingCriteria.reset();
268
+ for (const cache of kvCaches.values()) {
269
+ cache?.dispose?.();
270
+ }
271
+ kvCaches.clear();
272
+ }
273
+ // ─── Message Handler ───
274
+ self.addEventListener('message', async (e) => {
275
+ const cmd = e.data;
276
+ switch (cmd.type) {
277
+ case 'check':
278
+ await checkDevice();
279
+ break;
280
+ case 'load':
281
+ await loadPipeline(cmd.config);
282
+ break;
283
+ case 'run':
284
+ await runInference(cmd.id, cmd.task, cmd.input, cmd.options);
285
+ break;
286
+ case 'interrupt':
287
+ stoppingCriteria.interrupt();
288
+ break;
289
+ case 'reset':
290
+ resetKVCache();
291
+ break;
292
+ case 'dispose':
293
+ disposeModel(cmd.modelKey);
294
+ break;
295
+ default:
296
+ send({
297
+ type: 'error',
298
+ id: 'unknown',
299
+ data: `Unknown command: ${cmd.type}`,
300
+ });
301
+ }
302
+ });
303
+ //# sourceMappingURL=model-worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-worker.js","sourceRoot":"","sources":["../src/model-worker.ts"],"names":[],"mappings":"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"}