@openfluke/welvet 0.1.1 → 0.1.3
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.
- package/README.md +241 -8
- package/dist/index.d.ts +5 -3
- package/dist/index.js +3 -2
- package/dist/loader.js +1 -1
- package/dist/loom.wasm +0 -0
- package/dist/transformer.d.ts +5 -0
- package/dist/transformer.js +127 -0
- package/dist/types.d.ts +96 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,8 +9,10 @@
|
|
|
9
9
|
|
|
10
10
|
## ✨ Features
|
|
11
11
|
|
|
12
|
-
-
|
|
13
|
-
-
|
|
12
|
+
- 🤖 **Transformer Inference (NEW!)** - Run LLMs like SmolLM2-135M with streaming generation
|
|
13
|
+
- 🚀 **6.0MB WASM Binary** - Complete neural network framework + transformer inference
|
|
14
|
+
- 🧠 **7 Layer Types (All CPU)** - Dense, Conv2D, Multi-Head Attention, LayerNorm, RNN, LSTM, Softmax (10 variants)
|
|
15
|
+
- ✅ **Full CPU Implementation** - Every layer works with complete forward/backward passes
|
|
14
16
|
- 🎯 **Registry-based Initialization** - Dynamic layer creation via `CallLayerInit()` with zero manual exports
|
|
15
17
|
- 🔍 **Runtime Introspection** - Discover methods, signatures, and parameters dynamically
|
|
16
18
|
- 💾 **Model Serialization** - Save/load models as JSON (no filesystem required)
|
|
@@ -42,6 +44,76 @@ bun add @openfluke/welvet
|
|
|
42
44
|
|
|
43
45
|
## 🚀 Quick Start
|
|
44
46
|
|
|
47
|
+
### 🤖 Transformer Inference (NEW!)
|
|
48
|
+
|
|
49
|
+
Run Large Language Models with streaming generation:
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
import { initLoom, createTransformerAPI } from "@openfluke/welvet";
|
|
53
|
+
|
|
54
|
+
// Initialize WASM
|
|
55
|
+
await initLoom();
|
|
56
|
+
|
|
57
|
+
// Create transformer API
|
|
58
|
+
const transformer = await createTransformerAPI();
|
|
59
|
+
|
|
60
|
+
// Load tokenizer
|
|
61
|
+
const tokenizerData = await fetch("models/SmolLM2-135M-Instruct/tokenizer.json")
|
|
62
|
+
.then((r) => r.arrayBuffer())
|
|
63
|
+
.then((buf) => new Uint8Array(buf));
|
|
64
|
+
await transformer.loadTokenizer(tokenizerData);
|
|
65
|
+
|
|
66
|
+
// Load model
|
|
67
|
+
const configData = await fetch("models/SmolLM2-135M-Instruct/config.json")
|
|
68
|
+
.then((r) => r.arrayBuffer())
|
|
69
|
+
.then((buf) => new Uint8Array(buf));
|
|
70
|
+
const weightsData = await fetch(
|
|
71
|
+
"models/SmolLM2-135M-Instruct/model.safetensors"
|
|
72
|
+
)
|
|
73
|
+
.then((r) => r.arrayBuffer())
|
|
74
|
+
.then((buf) => new Uint8Array(buf));
|
|
75
|
+
await transformer.loadModel(configData, weightsData);
|
|
76
|
+
|
|
77
|
+
// Stream generation token-by-token
|
|
78
|
+
for await (const token of transformer.generateStream(
|
|
79
|
+
"The capital of France is",
|
|
80
|
+
50,
|
|
81
|
+
0.7
|
|
82
|
+
)) {
|
|
83
|
+
process.stdout.write(token); // Paris...
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**Live Demo:** See `wasm/inference.html` for a beautiful web UI with real-time token streaming!
|
|
88
|
+
|
|
89
|
+
### The Easy Way: Load Complete Models
|
|
90
|
+
|
|
91
|
+
Instead of manually configuring layers, **load a complete model with ONE line**:
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
import { initLoom } from "@openfluke/welvet";
|
|
95
|
+
|
|
96
|
+
const loom = await initLoom();
|
|
97
|
+
|
|
98
|
+
// Load model from JSON (architecture + weights all at once!)
|
|
99
|
+
const modelJSON = await fetch("test.json").then((r) => r.json());
|
|
100
|
+
const network = loom.LoadModelFromString(
|
|
101
|
+
JSON.stringify(modelJSON),
|
|
102
|
+
"all_layers_test"
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
// That's it! All 16 layers, weights, biases loaded automatically
|
|
106
|
+
const input = new Array(10).fill(0).map(() => Math.random());
|
|
107
|
+
const [output, duration] = JSON.parse(
|
|
108
|
+
network.ForwardCPU(JSON.stringify([input]))
|
|
109
|
+
);
|
|
110
|
+
console.log("Output:", output);
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Live Demo:** See `wasm/all_layers_test.html` for a complete working example that loads a 26.4KB model with 16 layers (Dense, Conv2D, Attention, RNN, LSTM) and runs inference in the browser!
|
|
114
|
+
|
|
115
|
+
### Manual Configuration (for building models from scratch)
|
|
116
|
+
|
|
45
117
|
```typescript
|
|
46
118
|
import { initLoom, ActivationType } from "@openfluke/welvet";
|
|
47
119
|
|
|
@@ -254,6 +326,28 @@ network.UpdateWeights(JSON.stringify([learningRate]));
|
|
|
254
326
|
|
|
255
327
|
### Model Persistence
|
|
256
328
|
|
|
329
|
+
#### Load Model (The Easy Way - ONE LINE!)
|
|
330
|
+
|
|
331
|
+
```typescript
|
|
332
|
+
// Fetch model from server
|
|
333
|
+
const savedModel = await fetch("model.json").then((r) => r.json());
|
|
334
|
+
|
|
335
|
+
// Load complete network with ONE function call!
|
|
336
|
+
const network = loom.LoadModelFromString(
|
|
337
|
+
JSON.stringify(savedModel),
|
|
338
|
+
"model_name"
|
|
339
|
+
);
|
|
340
|
+
|
|
341
|
+
// Or from localStorage
|
|
342
|
+
const savedModel = JSON.parse(localStorage.getItem("my_model")!);
|
|
343
|
+
const network = loom.LoadModelFromString(
|
|
344
|
+
JSON.stringify(savedModel),
|
|
345
|
+
"model_name"
|
|
346
|
+
);
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
**That's it!** All layers, weights, biases, and configurations are automatically restored. No manual layer setup needed!
|
|
350
|
+
|
|
257
351
|
#### Save Model
|
|
258
352
|
|
|
259
353
|
```typescript
|
|
@@ -264,16 +358,155 @@ const model = JSON.parse(JSON.parse(modelJSON)[0]);
|
|
|
264
358
|
localStorage.setItem("my_model", JSON.stringify(model));
|
|
265
359
|
```
|
|
266
360
|
|
|
267
|
-
####
|
|
361
|
+
#### Save Model
|
|
268
362
|
|
|
269
363
|
```typescript
|
|
270
|
-
const
|
|
271
|
-
const
|
|
272
|
-
|
|
273
|
-
|
|
364
|
+
const modelJSON = network.SaveModelToString(JSON.stringify(["model_name"]));
|
|
365
|
+
const model = JSON.parse(JSON.parse(modelJSON)[0]);
|
|
366
|
+
|
|
367
|
+
// Store anywhere (localStorage, IndexedDB, backend API, etc.)
|
|
368
|
+
localStorage.setItem("my_model", JSON.stringify(model));
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
#### Cross-Platform Model Loading
|
|
372
|
+
|
|
373
|
+
The same JSON model file works across **all three platforms**:
|
|
374
|
+
|
|
375
|
+
```typescript
|
|
376
|
+
// JavaScript/WASM
|
|
377
|
+
const network = loom.LoadModelFromString(modelJSON, "model_id");
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
```python
|
|
381
|
+
# Python
|
|
382
|
+
network = welvet.load_model_from_string(model_json, "model_id")
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
```go
|
|
386
|
+
// Go
|
|
387
|
+
network, _ := nn.LoadModelFromString(modelJSON, "model_id")
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
See `examples/all_layers_validation.go` for a complete demo that generates test.json (26.4KB with 16 layers) and verifies all three platforms load it identically!
|
|
391
|
+
|
|
392
|
+
## 🤖 Transformer API
|
|
393
|
+
|
|
394
|
+
### Loading Models
|
|
395
|
+
|
|
396
|
+
```typescript
|
|
397
|
+
import { initLoom, createTransformerAPI } from "@openfluke/welvet";
|
|
398
|
+
|
|
399
|
+
// Initialize WASM
|
|
400
|
+
await initLoom();
|
|
401
|
+
|
|
402
|
+
// Create transformer API
|
|
403
|
+
const transformer = await createTransformerAPI();
|
|
404
|
+
|
|
405
|
+
// Load tokenizer from bytes
|
|
406
|
+
const tokenizerData = await fetch("models/SmolLM2-135M/tokenizer.json")
|
|
407
|
+
.then((r) => r.arrayBuffer())
|
|
408
|
+
.then((buf) => new Uint8Array(buf));
|
|
409
|
+
|
|
410
|
+
const tokResult = await transformer.loadTokenizer(tokenizerData);
|
|
411
|
+
console.log(`Tokenizer loaded: ${tokResult.vocab_size} tokens`);
|
|
412
|
+
|
|
413
|
+
// Load model from config and weights
|
|
414
|
+
const configData = await fetch("models/SmolLM2-135M/config.json")
|
|
415
|
+
.then((r) => r.arrayBuffer())
|
|
416
|
+
.then((buf) => new Uint8Array(buf));
|
|
417
|
+
|
|
418
|
+
const weightsData = await fetch("models/SmolLM2-135M/model.safetensors")
|
|
419
|
+
.then((r) => r.arrayBuffer())
|
|
420
|
+
.then((buf) => new Uint8Array(buf));
|
|
421
|
+
|
|
422
|
+
const modelResult = await transformer.loadModel(configData, weightsData);
|
|
423
|
+
console.log(
|
|
424
|
+
`Model loaded: ${modelResult.num_layers} layers, ${modelResult.hidden_size} hidden size`
|
|
274
425
|
);
|
|
275
426
|
```
|
|
276
427
|
|
|
428
|
+
### Text Encoding/Decoding
|
|
429
|
+
|
|
430
|
+
```typescript
|
|
431
|
+
// Encode text to token IDs
|
|
432
|
+
const encodeResult = await transformer.encode("Hello world", true);
|
|
433
|
+
console.log(encodeResult.ids); // [1, 9906, 2088]
|
|
434
|
+
|
|
435
|
+
// Decode token IDs to text
|
|
436
|
+
const decodeResult = await transformer.decode([1, 9906, 2088], true);
|
|
437
|
+
console.log(decodeResult.text); // "Hello world"
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
### Text Generation
|
|
441
|
+
|
|
442
|
+
#### Blocking Generation
|
|
443
|
+
|
|
444
|
+
```typescript
|
|
445
|
+
const result = await transformer.generate(
|
|
446
|
+
"The capital of France is",
|
|
447
|
+
50, // maxTokens
|
|
448
|
+
0.7 // temperature
|
|
449
|
+
);
|
|
450
|
+
console.log(result.generated_text);
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
#### Streaming Generation
|
|
454
|
+
|
|
455
|
+
```typescript
|
|
456
|
+
// Stream tokens one at a time
|
|
457
|
+
process.stdout.write("Generated: ");
|
|
458
|
+
for await (const token of transformer.generateStream(
|
|
459
|
+
"Once upon a time",
|
|
460
|
+
50, // maxTokens
|
|
461
|
+
0.7 // temperature
|
|
462
|
+
)) {
|
|
463
|
+
process.stdout.write(token); // Print each token as it's generated
|
|
464
|
+
}
|
|
465
|
+
console.log();
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
### Transformer API Reference
|
|
469
|
+
|
|
470
|
+
```typescript
|
|
471
|
+
interface TransformerAPI {
|
|
472
|
+
// Load tokenizer from JSON bytes
|
|
473
|
+
loadTokenizer(tokenizerData: Uint8Array): Promise<TokenizerLoadResult>;
|
|
474
|
+
|
|
475
|
+
// Load model from config + weights bytes
|
|
476
|
+
loadModel(
|
|
477
|
+
configData: Uint8Array,
|
|
478
|
+
weightsData: Uint8Array
|
|
479
|
+
): Promise<TransformerLoadResult>;
|
|
480
|
+
|
|
481
|
+
// Encode text to token IDs
|
|
482
|
+
encode(text: string, addSpecialTokens?: boolean): Promise<EncodeResult>;
|
|
483
|
+
|
|
484
|
+
// Decode token IDs to text
|
|
485
|
+
decode(
|
|
486
|
+
tokenIds: number[],
|
|
487
|
+
skipSpecialTokens?: boolean
|
|
488
|
+
): Promise<DecodeResult>;
|
|
489
|
+
|
|
490
|
+
// Generate text (blocking)
|
|
491
|
+
generate(
|
|
492
|
+
prompt: string,
|
|
493
|
+
maxTokens?: number,
|
|
494
|
+
temperature?: number
|
|
495
|
+
): Promise<GenerateResult>;
|
|
496
|
+
|
|
497
|
+
// Generate text (streaming)
|
|
498
|
+
generateStream(
|
|
499
|
+
prompt: string,
|
|
500
|
+
maxTokens?: number,
|
|
501
|
+
temperature?: number
|
|
502
|
+
): AsyncGenerator<string, void, unknown>;
|
|
503
|
+
}
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
#### Load Model (Legacy API)
|
|
507
|
+
|
|
508
|
+
````
|
|
509
|
+
|
|
277
510
|
### Runtime Introspection
|
|
278
511
|
|
|
279
512
|
#### Get All Methods
|
|
@@ -287,7 +520,7 @@ methods.forEach((method) => {
|
|
|
287
520
|
`${method.method_name}(${method.parameters.map((p) => p.type).join(", ")})`
|
|
288
521
|
);
|
|
289
522
|
});
|
|
290
|
-
|
|
523
|
+
````
|
|
291
524
|
|
|
292
525
|
#### Check Method Availability
|
|
293
526
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { InitOptions, LoomAPI } from "./types";
|
|
1
|
+
import type { InitOptions, LoomAPI } from "./types.js";
|
|
2
2
|
/**
|
|
3
3
|
* Initialize the LOOM WASM module and return the API
|
|
4
4
|
*
|
|
@@ -27,5 +27,7 @@ import type { InitOptions, LoomAPI } from "./types";
|
|
|
27
27
|
* ```
|
|
28
28
|
*/
|
|
29
29
|
export declare function initLoom(opts?: InitOptions): Promise<LoomAPI>;
|
|
30
|
-
export type { LoomAPI, LoomNetwork, InitOptions } from "./types";
|
|
31
|
-
export { ActivationType } from "./types";
|
|
30
|
+
export type { LoomAPI, LoomNetwork, InitOptions, TransformerAPI, } from "./types.js";
|
|
31
|
+
export { ActivationType } from "./types.js";
|
|
32
|
+
export { createTransformerAPI } from "./transformer.js";
|
|
33
|
+
export type { TokenizerLoadResult, TransformerLoadResult, EncodeResult, DecodeResult, GenerateResult, NextTokenResult, } from "./types.js";
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ensureGoRuntime, resolvePackagedWasmURL, instantiateGoWasm, } from "./loader";
|
|
1
|
+
import { ensureGoRuntime, resolvePackagedWasmURL, instantiateGoWasm, } from "./loader.js";
|
|
2
2
|
// tiny helper that waits until WASM has placed symbols on globalThis
|
|
3
3
|
async function waitForExports(keys, timeoutMs = 5000) {
|
|
4
4
|
const t0 = performance.now();
|
|
@@ -83,4 +83,5 @@ export async function initLoom(opts = {}) {
|
|
|
83
83
|
}
|
|
84
84
|
return api;
|
|
85
85
|
}
|
|
86
|
-
export { ActivationType } from "./types";
|
|
86
|
+
export { ActivationType } from "./types.js";
|
|
87
|
+
export { createTransformerAPI } from "./transformer.js";
|
package/dist/loader.js
CHANGED
package/dist/loom.wasm
CHANGED
|
Binary file
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper to wait for a global function to be available
|
|
3
|
+
*/
|
|
4
|
+
async function waitForGlobal(name, timeoutMs = 5000) {
|
|
5
|
+
const t0 = performance.now();
|
|
6
|
+
for (;;) {
|
|
7
|
+
if (globalThis[name])
|
|
8
|
+
return;
|
|
9
|
+
if (performance.now() - t0 > timeoutMs) {
|
|
10
|
+
throw new Error(`Timeout waiting for ${name}`);
|
|
11
|
+
}
|
|
12
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Create transformer API wrapper around WASM functions
|
|
17
|
+
*/
|
|
18
|
+
export async function createTransformerAPI() {
|
|
19
|
+
// Wait for transformer functions to be available
|
|
20
|
+
await Promise.all([
|
|
21
|
+
waitForGlobal("LoadTokenizerFromBytes"),
|
|
22
|
+
waitForGlobal("LoadTransformerFromBytes"),
|
|
23
|
+
waitForGlobal("EncodeText"),
|
|
24
|
+
waitForGlobal("DecodeTokens"),
|
|
25
|
+
waitForGlobal("GenerateNextToken"),
|
|
26
|
+
waitForGlobal("GenerateText"),
|
|
27
|
+
]);
|
|
28
|
+
const g = globalThis;
|
|
29
|
+
return {
|
|
30
|
+
async loadTokenizer(tokenizerData) {
|
|
31
|
+
return new Promise((resolve, reject) => {
|
|
32
|
+
try {
|
|
33
|
+
const resultStr = g.LoadTokenizerFromBytes(tokenizerData);
|
|
34
|
+
// If it's already an object, return it directly
|
|
35
|
+
if (typeof resultStr === "object") {
|
|
36
|
+
resolve(resultStr);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const result = JSON.parse(resultStr);
|
|
40
|
+
resolve(result);
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
reject(error);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
},
|
|
47
|
+
async loadModel(configData, weightsData) {
|
|
48
|
+
return new Promise((resolve, reject) => {
|
|
49
|
+
try {
|
|
50
|
+
const resultStr = g.LoadTransformerFromBytes(configData, weightsData);
|
|
51
|
+
const result = JSON.parse(resultStr);
|
|
52
|
+
resolve(result);
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
reject(error);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
},
|
|
59
|
+
async encode(text, addSpecialTokens = true) {
|
|
60
|
+
return new Promise((resolve, reject) => {
|
|
61
|
+
try {
|
|
62
|
+
const resultStr = g.EncodeText(text, addSpecialTokens);
|
|
63
|
+
const result = JSON.parse(resultStr);
|
|
64
|
+
resolve(result);
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
reject(error);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
},
|
|
71
|
+
async decode(tokenIds, skipSpecialTokens = true) {
|
|
72
|
+
return new Promise((resolve, reject) => {
|
|
73
|
+
try {
|
|
74
|
+
const resultStr = g.DecodeTokens(tokenIds, skipSpecialTokens);
|
|
75
|
+
const result = JSON.parse(resultStr);
|
|
76
|
+
resolve(result);
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
reject(error);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
},
|
|
83
|
+
async generate(prompt, maxTokens = 50, temperature = 0.7) {
|
|
84
|
+
return new Promise((resolve, reject) => {
|
|
85
|
+
try {
|
|
86
|
+
const resultStr = g.GenerateText(prompt, maxTokens, temperature);
|
|
87
|
+
const result = JSON.parse(resultStr);
|
|
88
|
+
resolve(result);
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
reject(error);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
},
|
|
95
|
+
async *generateStream(prompt, maxTokens = 50, temperature = 0.7) {
|
|
96
|
+
// Encode the prompt
|
|
97
|
+
const encodeResultStr = g.EncodeText(prompt, true);
|
|
98
|
+
const encodeResult = JSON.parse(encodeResultStr);
|
|
99
|
+
if (!encodeResult.success || !encodeResult.ids) {
|
|
100
|
+
throw new Error(encodeResult.error || "Failed to encode prompt");
|
|
101
|
+
}
|
|
102
|
+
const tokens = [...encodeResult.ids];
|
|
103
|
+
// Generate tokens one at a time
|
|
104
|
+
for (let i = 0; i < maxTokens; i++) {
|
|
105
|
+
const resultStr = g.GenerateNextToken(tokens, temperature);
|
|
106
|
+
const result = JSON.parse(resultStr);
|
|
107
|
+
if (!result.success) {
|
|
108
|
+
throw new Error(result.error || "Failed to generate token");
|
|
109
|
+
}
|
|
110
|
+
if (result.token === undefined) {
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
tokens.push(result.token);
|
|
114
|
+
// Decode just this token
|
|
115
|
+
const decodeResultStr = g.DecodeTokens([result.token], true);
|
|
116
|
+
const decodeResult = JSON.parse(decodeResultStr);
|
|
117
|
+
if (decodeResult.success && decodeResult.text) {
|
|
118
|
+
yield decodeResult.text;
|
|
119
|
+
}
|
|
120
|
+
// Check for end of sequence
|
|
121
|
+
if (result.is_eos) {
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -113,3 +113,99 @@ export declare enum ActivationType {
|
|
|
113
113
|
LeakyReLU = 4,
|
|
114
114
|
Linear = 5
|
|
115
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* Result from tokenizer loading
|
|
118
|
+
*/
|
|
119
|
+
export interface TokenizerLoadResult {
|
|
120
|
+
success: boolean;
|
|
121
|
+
vocab_size?: number;
|
|
122
|
+
message?: string;
|
|
123
|
+
error?: string;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Result from transformer model loading
|
|
127
|
+
*/
|
|
128
|
+
export interface TransformerLoadResult {
|
|
129
|
+
success: boolean;
|
|
130
|
+
num_layers?: number;
|
|
131
|
+
hidden_size?: number;
|
|
132
|
+
vocab_size?: number;
|
|
133
|
+
message?: string;
|
|
134
|
+
error?: string;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Result from text encoding
|
|
138
|
+
*/
|
|
139
|
+
export interface EncodeResult {
|
|
140
|
+
success: boolean;
|
|
141
|
+
ids?: number[];
|
|
142
|
+
error?: string;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Result from token decoding
|
|
146
|
+
*/
|
|
147
|
+
export interface DecodeResult {
|
|
148
|
+
success: boolean;
|
|
149
|
+
text?: string;
|
|
150
|
+
error?: string;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Result from text generation
|
|
154
|
+
*/
|
|
155
|
+
export interface GenerateResult {
|
|
156
|
+
success: boolean;
|
|
157
|
+
generated_text?: string;
|
|
158
|
+
error?: string;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Result from next token generation
|
|
162
|
+
*/
|
|
163
|
+
export interface NextTokenResult {
|
|
164
|
+
success: boolean;
|
|
165
|
+
token?: number;
|
|
166
|
+
is_eos?: boolean;
|
|
167
|
+
error?: string;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Transformer API for LLM inference
|
|
171
|
+
*/
|
|
172
|
+
export interface TransformerAPI {
|
|
173
|
+
/**
|
|
174
|
+
* Load tokenizer from JSON bytes
|
|
175
|
+
* @param tokenizerData - Uint8Array of tokenizer.json file
|
|
176
|
+
*/
|
|
177
|
+
loadTokenizer(tokenizerData: Uint8Array): Promise<TokenizerLoadResult>;
|
|
178
|
+
/**
|
|
179
|
+
* Load transformer model from config and weights bytes
|
|
180
|
+
* @param configData - Uint8Array of config.json file
|
|
181
|
+
* @param weightsData - Uint8Array of model.safetensors file
|
|
182
|
+
*/
|
|
183
|
+
loadModel(configData: Uint8Array, weightsData: Uint8Array): Promise<TransformerLoadResult>;
|
|
184
|
+
/**
|
|
185
|
+
* Encode text to token IDs
|
|
186
|
+
* @param text - Input text to encode
|
|
187
|
+
* @param addSpecialTokens - Whether to add special tokens (default: true)
|
|
188
|
+
*/
|
|
189
|
+
encode(text: string, addSpecialTokens?: boolean): Promise<EncodeResult>;
|
|
190
|
+
/**
|
|
191
|
+
* Decode token IDs to text
|
|
192
|
+
* @param tokenIds - Array of token IDs
|
|
193
|
+
* @param skipSpecialTokens - Whether to skip special tokens (default: true)
|
|
194
|
+
*/
|
|
195
|
+
decode(tokenIds: number[], skipSpecialTokens?: boolean): Promise<DecodeResult>;
|
|
196
|
+
/**
|
|
197
|
+
* Generate text from prompt (blocking, all tokens at once)
|
|
198
|
+
* @param prompt - Input prompt
|
|
199
|
+
* @param maxTokens - Maximum tokens to generate (default: 50)
|
|
200
|
+
* @param temperature - Sampling temperature (default: 0.7)
|
|
201
|
+
*/
|
|
202
|
+
generate(prompt: string, maxTokens?: number, temperature?: number): Promise<GenerateResult>;
|
|
203
|
+
/**
|
|
204
|
+
* Generate text token-by-token (streaming)
|
|
205
|
+
* @param prompt - Input prompt
|
|
206
|
+
* @param maxTokens - Maximum tokens to generate (default: 50)
|
|
207
|
+
* @param temperature - Sampling temperature (default: 0.7)
|
|
208
|
+
* @yields Token text strings
|
|
209
|
+
*/
|
|
210
|
+
generateStream(prompt: string, maxTokens?: number, temperature?: number): AsyncGenerator<string, void, unknown>;
|
|
211
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openfluke/welvet",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "TypeScript/JavaScript bindings for LOOM neural network framework with WebAssembly support - GPU-accelerated machine learning in the browser",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|