@degreesign/chat 1.2.0 → 1.3.1
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 +150 -123
- package/dist/browser/chat.min.mjs +1 -1
- package/dist/browser/engine-wllama.min.mjs +1 -1
- package/dist/describe.d.ts +2 -2
- package/dist/enums.d.ts +0 -1
- package/dist/index.d.ts +1 -0
- package/dist/models.d.ts +1 -3
- package/dist/node/chat.node.min.js +1 -1
- package/dist/node/chat.node.min.mjs +1 -1
- package/dist/node/engine-wllama.node.min.js +1 -1
- package/dist/node/engine-wllama.node.min.mjs +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,26 +1,27 @@
|
|
|
1
1
|
# @degreesign/chat
|
|
2
2
|
|
|
3
|
-
One-shot on-device AI chat for browsers, workers and Node, using wllama CPU
|
|
4
|
-
engine and LiteRT-LM WebGPU engine.
|
|
5
|
-
|
|
6
|
-
Includes voice transcription to many languages
|
|
7
|
-
and a super accurate image vision function.
|
|
8
|
-
The package manages download of AI models automatically,
|
|
9
|
-
with auto resume for low network connections.
|
|
3
|
+
One-shot on-device AI chat for browsers, workers and Node, using a wllama CPU
|
|
4
|
+
engine and a LiteRT-LM WebGPU engine. It streams text, describes images,
|
|
5
|
+
manages model downloads with automatic resume, and renders no UI.
|
|
10
6
|
|
|
11
|
-
|
|
7
|
+
Voice notes are transcribed on device by `@degreesign/voice`, a companion
|
|
8
|
+
package, then passed to `@degreesign/chat` as text.
|
|
9
|
+
|
|
10
|
+
`@degreesign/chat` is a plug and play engine for any UI.
|
|
12
11
|
|
|
13
12
|
[](https://www.npmjs.com/package/@degreesign/chat)
|
|
14
13
|
[](#licensing)
|
|
15
14
|
[](#faq)
|
|
16
15
|
[](#faq)
|
|
17
16
|
[](https://degreesign.github.io/ds_chat/architecture.html)
|
|
17
|
+
[](https://degreesign.github.io/ds_chat/vs_web_llm.html)
|
|
18
18
|
|
|
19
19
|
## Table of contents
|
|
20
20
|
|
|
21
21
|
- [Why](#why)
|
|
22
22
|
- [Install](#install)
|
|
23
23
|
- [Quick start](#quick-start)
|
|
24
|
+
- [Case study: DoListy](#case-study-dolisty)
|
|
24
25
|
- [Enable WebGPU](#enable-webgpu)
|
|
25
26
|
- [Public API](#public-api)
|
|
26
27
|
- [Tools](#tools)
|
|
@@ -38,6 +39,8 @@ with auto resume for low network connections.
|
|
|
38
39
|
|
|
39
40
|
## Why
|
|
40
41
|
|
|
42
|
+
- Proven: [DoListy](https://dolisty.com/#chat), a no-signup PWA, answers
|
|
43
|
+
with the network off.
|
|
41
44
|
- On device: model weights download once, then every reply is generated locally.
|
|
42
45
|
- Headless: the package returns text through callbacks and renders no UI.
|
|
43
46
|
- Stateless: the host passes the whole message list and keeps its own history.
|
|
@@ -46,7 +49,7 @@ with auto resume for low network connections.
|
|
|
46
49
|
- Images: a user turn can carry image URLs, sent only to a vision model and
|
|
47
50
|
capped by the prompt budgets.
|
|
48
51
|
- Audio: a user turn can carry an audio URL, sent only to a model with audio
|
|
49
|
-
support
|
|
52
|
+
support. No model in the catalog has an audio encoder.
|
|
50
53
|
- Reusable: the loaded model stays in memory for the next call.
|
|
51
54
|
- Typed: written in TypeScript with declarations for every export.
|
|
52
55
|
- Portable: importing and calling works in browsers, workers, React and Node.
|
|
@@ -133,38 +136,84 @@ second, measured from the first token so prompt processing is excluded.
|
|
|
133
136
|
Attach images to a user turn with `images: [dataUrl]`. The package sends them
|
|
134
137
|
only to a model with vision support, fits each image to 128 to 136 vision
|
|
135
138
|
tokens, snaps both sides to multiples of 32 px, crops the remainder, and caps
|
|
136
|
-
the number with `limits.maxImages`.
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
`
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
A model without audio drops the clip when the turn also has text; an audio-only
|
|
146
|
-
turn reports `Model does not accept audio`. On a phone or tablet
|
|
147
|
-
`gemma4_e2b_limited` is text only, so audio follows the same rule as images
|
|
148
|
-
there. The package does not transcode, so the host supplies one of those
|
|
149
|
-
formats.
|
|
139
|
+
the number with `limits.maxImages`. `qwen3_vl_2b` is the vision model in the
|
|
140
|
+
catalog, and it runs on the CPU engine. A turn sent to a model without vision
|
|
141
|
+
drops its images when the turn also has text, and an image-only turn reports
|
|
142
|
+
`Model does not accept images`.
|
|
143
|
+
|
|
144
|
+
Attach a recording with `audio: [dataUrl]`. No model in the catalog has an
|
|
145
|
+
audio encoder, so a text turn drops the clip and an audio-only turn reports
|
|
146
|
+
`Model does not accept audio`. `limits.maxAudio` still caps the clips
|
|
147
|
+
(default 1).
|
|
150
148
|
|
|
151
149
|
The package never writes storage, so the host appends the user message before
|
|
152
150
|
the call and appends the assistant message after the last `onResponse`.
|
|
153
151
|
|
|
152
|
+
## Case study: DoListy
|
|
153
|
+
|
|
154
|
+
[DoListy](https://dolisty.com/#chat) is a DegreeSign project: a private
|
|
155
|
+
to-do list PWA with no sign-up. It ships `@degreesign/chat` for replies
|
|
156
|
+
and image descriptions, and `@degreesign/voice` for voice notes.
|
|
157
|
+
|
|
158
|
+
I wanted an assistant that could read my daily tasks, but I did not want
|
|
159
|
+
to give 100% of my data to big tech. I was also working on a new project
|
|
160
|
+
that had to stay under wraps until its soft launch, so I could not send
|
|
161
|
+
that work to a hosted model. The assistant had to run on the device, and
|
|
162
|
+
it had to be easy for any developer to drop into an app. Most days I have
|
|
163
|
+
that conversation on my phone: a voice note, a transcript, a few tasks,
|
|
164
|
+
all local. DoListy is where that engine got its first real use.
|
|
165
|
+
|
|
166
|
+
![DoListy assistant answering a question on a phone][dolisty-shot]
|
|
167
|
+
|
|
168
|
+
[dolisty-shot]: https://degreesign.github.io/ds_chat/case-study-dolisty.png
|
|
169
|
+
|
|
170
|
+
*A real session on dolisty.com. The green dot is the local model, not a
|
|
171
|
+
server.*
|
|
172
|
+
|
|
173
|
+
### What it does
|
|
174
|
+
|
|
175
|
+
- Describes a photo and tags it without uploading it.
|
|
176
|
+
- Turns a voice note into a task through `@degreesign/voice`.
|
|
177
|
+
- Writes titles, tags and a running summary in 19 languages. The persona
|
|
178
|
+
is the app's; the package adds no identity text.
|
|
179
|
+
- Answers with the network off, from the model already on disk.
|
|
180
|
+
|
|
181
|
+
### What it costs
|
|
182
|
+
|
|
183
|
+
- No per-reply cost, no API key, no rate limit. The only bill is the
|
|
184
|
+
one-time download: about 1.5 GB for Qwen3-VL, 2.0 GB for Gemma 4.
|
|
185
|
+
- An image waits about 70 seconds for its first token on an 8-thread
|
|
186
|
+
desktop CPU. That is the cost of the CPU vision path, chosen so images
|
|
187
|
+
work on phones without WebGPU; text takes the GPU path when the browser
|
|
188
|
+
has one.
|
|
189
|
+
- A 2 GB download resumes from the last committed part. A reload costs at
|
|
190
|
+
most one part, never the whole file.
|
|
191
|
+
- The gallery describes images in the background while you work.
|
|
192
|
+
|
|
193
|
+
### How it is wired
|
|
194
|
+
|
|
195
|
+
- One `createChat` per send, over a prompt assembled from the app's
|
|
196
|
+
encrypted stores.
|
|
197
|
+
- The reply is committed when `onStatus` reports the end; a newer send
|
|
198
|
+
drops the stale one.
|
|
199
|
+
- `gpuAdapter()` picks Gemma on WebGPU and Qwen everywhere else.
|
|
200
|
+
- One model stays resident, so a switch reloads the engine but never the
|
|
201
|
+
file.
|
|
202
|
+
|
|
203
|
+
**See it work:** open [dolisty.com](https://dolisty.com/#chat) on a phone,
|
|
204
|
+
let the model download once, then turn off the network and ask for a
|
|
205
|
+
summary. Speed numbers are in the
|
|
206
|
+
[web-llm comparison](https://degreesign.github.io/ds_chat/vs_web_llm.html).
|
|
207
|
+
|
|
154
208
|
## Enable WebGPU
|
|
155
209
|
|
|
156
|
-
A request without `model` picks
|
|
157
|
-
and `qwen3_vl_2b` when it does not.
|
|
158
|
-
`
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
or resolved, every status snapshot reports the build that runs in `model`, so a
|
|
164
|
-
host that asks for `gemma4_e2b` on a phone reads `gemma4-e2b-limited` back.
|
|
165
|
-
Hosts that need images on mobile pass `qwen3_vl_2b`; audio is desktop only. The
|
|
166
|
-
GPU engine is far faster on a desktop, so check the browser before blaming the
|
|
167
|
-
package:
|
|
210
|
+
A request without `model` picks `gemma4_e2b_limited` when the browser exposes a
|
|
211
|
+
WebGPU adapter and `qwen3_vl_2b` when it does not. The Gemma build is the 2.0 GB
|
|
212
|
+
text-only `gemma-4-E2B-it-gpu.litertlm`, and it is the only WebGPU model in the
|
|
213
|
+
catalog, so it loads on a desktop and on a phone alike. Every status snapshot
|
|
214
|
+
reports the build that runs in `model`. Hosts that need images pass
|
|
215
|
+
`qwen3_vl_2b`. The GPU engine is far faster on a desktop, so check the browser
|
|
216
|
+
before blaming the package:
|
|
168
217
|
|
|
169
218
|
```js
|
|
170
219
|
// Run in the console of the page that loads the package
|
|
@@ -217,19 +266,14 @@ CPU, not the GPU. Remove it when measuring speed. Headless Chromium hides
|
|
|
217
266
|
`--enable-features=Vulkan,WebGPU` and `--use-angle=vulkan`; check the adapter
|
|
218
267
|
there too, because a missing adapter silently selects the CPU model.
|
|
219
268
|
|
|
220
|
-
### GPU memory
|
|
269
|
+
### GPU memory
|
|
221
270
|
|
|
222
|
-
The WebGPU engine keeps the model
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
the crop is resized to 384 x 384 rather than the full 768 x 768. If the error
|
|
229
|
-
still appears, close other GPU tabs, unload the model, or switch to the CPU
|
|
230
|
-
model. A lost device needs a page or model reload; later calls cannot reuse it.
|
|
231
|
-
A phone or tablet resolves Gemma to the text-only browser build, so it never
|
|
232
|
-
starts the vision or audio encoder.
|
|
271
|
+
The WebGPU engine keeps the model and its KV cache in GPU memory. The Gemma
|
|
272
|
+
build carries no vision or audio encoder, so it never starts one and never
|
|
273
|
+
resizes an image. A card that is already busy can lose the device
|
|
274
|
+
(`VK_ERROR_DEVICE_LOST`) during a long generation. If the error appears, close
|
|
275
|
+
other GPU tabs, unload the model, or switch to the CPU model. A lost device
|
|
276
|
+
needs a page or model reload; later calls cannot reuse it.
|
|
233
277
|
|
|
234
278
|
While a reply streams, the GPU engine rests after every token readback, so the
|
|
235
279
|
card stays near 70% of wall time instead of pegging at 100% and starving the
|
|
@@ -247,16 +291,16 @@ describeImages(input: DescribeImagesInput): Promise<ImageDescription[]>
|
|
|
247
291
|
describeTranslated(input: DescribeTranslatedInput): Promise<string[]>
|
|
248
292
|
describeModelId: ChatModelId
|
|
249
293
|
imageReplyTokens: number
|
|
294
|
+
gpuAdapter(): Promise<boolean>
|
|
250
295
|
clearModelCache(): Promise<void>
|
|
251
296
|
```
|
|
252
297
|
|
|
253
298
|
Call it once per response. A new call aborts the previous stream. When the
|
|
254
|
-
requested model is already loaded, no download or load happens.
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
file from this device.
|
|
299
|
+
requested model is already loaded, no download or load happens. One model stays
|
|
300
|
+
resident on every device, so a new model replaces the old one, including a move
|
|
301
|
+
between the CPU describer and the GPU translator. Files stay on disk, and
|
|
302
|
+
`clearModelCache` releases the loaded model and deletes every cached model file
|
|
303
|
+
from this device.
|
|
260
304
|
|
|
261
305
|
`ChatInput`:
|
|
262
306
|
|
|
@@ -273,10 +317,11 @@ file from this device.
|
|
|
273
317
|
| `onStatus?` | Receives a `ChatStatusSnapshot` on every state change. |
|
|
274
318
|
|
|
275
319
|
Without `model` the package picks the GPU build when the browser provides a
|
|
276
|
-
WebGPU adapter and the CPU build when it does not.
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
320
|
+
WebGPU adapter and the CPU build when it does not. `gpuAdapter` runs the same
|
|
321
|
+
probe, so a host can check the device before it names a model. The budget
|
|
322
|
+
defaults are 250 reply tokens, 128 CPU thinking tokens, 1200 GPU reasoning
|
|
323
|
+
tokens (320 on the CPU), 2 images, 1 audio clip, 1000 characters per message,
|
|
324
|
+
10000 prompt characters and 32 CPU threads.
|
|
280
325
|
|
|
281
326
|
`CancelChat` is `() => void`. Its meaning depends on the current state:
|
|
282
327
|
|
|
@@ -286,10 +331,9 @@ characters and 32 CPU threads.
|
|
|
286
331
|
| Ready | Aborts the reply and unloads the model that answered. |
|
|
287
332
|
| An older call | Nothing, because a newer call owns the runtime. |
|
|
288
333
|
|
|
289
|
-
The model stays loaded between calls until a cancel frees it, and a newer
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
download.
|
|
334
|
+
The model stays loaded between calls until a cancel frees it, and a newer model
|
|
335
|
+
replaces it. One model download serves every caller: a chat that joins a preload
|
|
336
|
+
shares its progress and never starts a second download.
|
|
293
337
|
|
|
294
338
|
### Preload
|
|
295
339
|
|
|
@@ -304,9 +348,8 @@ runtime, and either call joins a load already in flight. A preload owns no cance
|
|
|
304
348
|
function, so a chat that joins its download and is cancelled leaves the download
|
|
305
349
|
running.
|
|
306
350
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
its own model, and a load on the same backend still replaces the one in flight.
|
|
351
|
+
A preload of another model replaces the resident one, because one model stays
|
|
352
|
+
in memory at a time. A load of the same model still joins the one in flight.
|
|
310
353
|
|
|
311
354
|
`ChatPreloadInput` is the subset of `ChatInput` that a preload needs:
|
|
312
355
|
|
|
@@ -327,7 +370,7 @@ on failure. A preload owns no cancel function; a new load replaces it.
|
|
|
327
370
|
describeImages(input: DescribeImagesInput): Promise<ImageDescription[]>
|
|
328
371
|
```
|
|
329
372
|
|
|
330
|
-
Describe every image in English with `
|
|
373
|
+
Describe every image in English with `qwen3_vl_2b_instruct`, the Q4_K_M
|
|
331
374
|
build of Unsloth Qwen3-VL 2B Instruct, one image at a time. When a WebGPU
|
|
332
375
|
adapter exists and `targetLanguage` is not English, the English descriptions
|
|
333
376
|
are then translated one by one with `gemma4_e2b_limited`. Without a GPU, when
|
|
@@ -438,7 +481,7 @@ search and currency tools fetch over the network; `calculate` does not.
|
|
|
438
481
|
|
|
439
482
|
| Field | Description |
|
|
440
483
|
| ----- | ----------- |
|
|
441
|
-
| `model?` | The
|
|
484
|
+
| `model?` | The model that runs, or the requested build before it resolves. |
|
|
442
485
|
| `availability` | `ChatStatus.online`, `.away` or `.offline`, derived from `status`. |
|
|
443
486
|
| `status` | `LlmStatus`: `idle`, `downloading`, `ready`, `error` or `unsupported`. |
|
|
444
487
|
| `backend` | `LlmBackend.cpu`, `.gpu` or `.none`. |
|
|
@@ -453,7 +496,7 @@ search and currency tools fetch over the network; `calculate` does not.
|
|
|
453
496
|
|
|
454
497
|
The first snapshot fires synchronously inside `createChat`. A final snapshot
|
|
455
498
|
with `requesting: false` marks the end of the call. `describeImages` reports the
|
|
456
|
-
same snapshot for each model it loads: `
|
|
499
|
+
same snapshot for each model it loads: `qwen3_vl_2b_instruct` while it
|
|
457
500
|
describes, then `gemma4_e2b_limited` while it translates.
|
|
458
501
|
|
|
459
502
|
A stream that never produces its first chunk ends with an error after 5
|
|
@@ -478,43 +521,34 @@ without it goes quiet again.
|
|
|
478
521
|
| `qwen3_vl_2b` | Qwen3-VL 2B | Yes | Yes | No | Yes | No |
|
|
479
522
|
| `qwen3_vl_2b_instruct` | Qwen3-VL 2B Instruct | No | Yes | No | Yes | No |
|
|
480
523
|
| `qwen3_vl_2b_instruct_q3` | Qwen3-VL 2B Instruct Q3 | No | Yes | No | Yes | No |
|
|
481
|
-
| `gemma4_e2b` | Gemma 4 E2B | Yes | Yes | Yes | No | Yes |
|
|
482
524
|
| `gemma4_e2b_limited` | Gemma 4 E2B limited | Yes | No | No | No | Yes |
|
|
483
525
|
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
`gemma4_e2b_limited` loads that same file on a desktop. The build that actually
|
|
487
|
-
runs is always the one in `ChatStatusSnapshot.model`. The limited build has no
|
|
526
|
+
`gemma4_e2b_limited` loads `gemma-4-E2B-it-gpu.litertlm` on every device. The
|
|
527
|
+
build that runs is always the one in `ChatStatusSnapshot.model`. It has no
|
|
488
528
|
vision or audio encoder, so `supportsImages` and `supportsAudio` report `false`
|
|
489
|
-
there. Use `qwen3_vl_2b` for images
|
|
529
|
+
there. Use `qwen3_vl_2b` for images.
|
|
490
530
|
|
|
491
531
|
The first call downloads the model before its engine loads it. Later calls
|
|
492
|
-
reuse the loaded runtime.
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
next attempt, including after a reload.
|
|
532
|
+
reuse the loaded runtime. One model stays resident, and a new model replaces it.
|
|
533
|
+
An interrupted download keeps every part it committed and resumes from the last
|
|
534
|
+
one on the next attempt, including after a reload.
|
|
496
535
|
|
|
497
536
|
Qwen3-VL 2B downloads a vision projector of about 445 MB with the model, so its
|
|
498
537
|
total download is about 1.5 GB. It runs on the CPU engine, with a 4096 token
|
|
499
538
|
context on a phone and 8192 on a desktop. Its projector uses the same CPU thread
|
|
500
|
-
budget as the text pass, so image turns
|
|
501
|
-
Use the GPU model when images need to be fast.
|
|
539
|
+
budget as the text pass, so image turns wait behind the CPU queue.
|
|
502
540
|
|
|
503
|
-
`
|
|
504
|
-
`describeImages` loads for the English pass, its
|
|
541
|
+
`qwen3_vl_2b_instruct` is the Unsloth Qwen3-VL 2B Instruct build that
|
|
542
|
+
`describeImages` loads for the English pass, its Q4_K_M file. Both instruct
|
|
505
543
|
builds use Qwen's Q8_0 projector, about 445 MB, so the describer totals about
|
|
506
|
-
1.
|
|
507
|
-
prompt directly. `
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
Gemma 4 E2B downloads `gemma-4-E2B-it.litertlm`,
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
instead downloads the 2.0 GB `gemma-4-E2B-it-gpu.litertlm`, the precompiled
|
|
515
|
-
GPU_ARTISAN build Google ships for browsers. The smaller file is what keeps a
|
|
516
|
-
mobile tab alive at the end of the model load, and a desktop can ask for it
|
|
517
|
-
too, trading vision and audio for 600 MB less download.
|
|
544
|
+
1.5 GB on the CPU engine. It has no reasoning pass, so it answers an image
|
|
545
|
+
prompt directly. `qwen3_vl_2b_instruct_q3` is the same model in Q3_K_M, about
|
|
546
|
+
160 MB smaller, for a host that prefers the smaller file and names it
|
|
547
|
+
explicitly.
|
|
548
|
+
|
|
549
|
+
Gemma 4 E2B downloads the 2.0 GB `gemma-4-E2B-it-gpu.litertlm`, the
|
|
550
|
+
precompiled GPU_ARTISAN build Google ships for browsers. It runs on the WebGPU
|
|
551
|
+
engine, carries no vision or audio encoder, and needs no projector download.
|
|
518
552
|
|
|
519
553
|
The WebGPU engine asks for a 32768 token context on a desktop and 16384 on a
|
|
520
554
|
phone, both multiples of 1024. Its int8 KV cache holds the full desktop window
|
|
@@ -551,11 +585,9 @@ user: {next turn}
|
|
|
551
585
|
(default 2). Older image parts are dropped and their text stays.
|
|
552
586
|
- Every image part keeps its full frame and targets 128 vision tokens, with at
|
|
553
587
|
most 136. Both sides are snapped to multiples of 32 px and the remainder is
|
|
554
|
-
cropped.
|
|
555
|
-
smallest Gemma 4 encoder signature.
|
|
588
|
+
cropped.
|
|
556
589
|
- Audio is collected from the newest turns first and capped by `maxAudio`
|
|
557
|
-
(default 1). Older audio parts are dropped and their text stays.
|
|
558
|
-
FLAC are accepted, and a short 16 kHz mono WAV is the best input.
|
|
590
|
+
(default 1). Older audio parts are dropped and their text stays.
|
|
559
591
|
- Image and audio payloads do not count against `promptCharBudget`.
|
|
560
592
|
- An image-only turn with a text model reports `Model does not accept images`,
|
|
561
593
|
and an audio-only turn reports `Model does not accept audio`.
|
|
@@ -618,11 +650,9 @@ self hosted. Chromium also accepts
|
|
|
618
650
|
changed. A page inside an iframe is isolated only when every ancestor sets the
|
|
619
651
|
same headers.
|
|
620
652
|
|
|
621
|
-
Each engine keeps its own cache.
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
model in total. The previous model's files always stay, so a switch back skips
|
|
625
|
-
the download.
|
|
653
|
+
Each engine keeps its own cache. One model stays loaded, so a switch between
|
|
654
|
+
the CPU and GPU models skips the download but still loads the new engine. The
|
|
655
|
+
previous model's files always stay, so a switch back skips the download.
|
|
626
656
|
`clearModelCache()` deletes them all and frees the storage. Both engines store
|
|
627
657
|
model files in the origin private file system as numbered parts, under
|
|
628
658
|
`wllama-store` for the CPU engine and `litert-store` for the GPU engine. The GPU
|
|
@@ -650,7 +680,7 @@ wasm under `dist/assets/litert`; model weights remain external.
|
|
|
650
680
|
|
|
651
681
|
LiteRT-LM needs WebGPU and the JSPI and relaxed SIMD wasm features, currently
|
|
652
682
|
available in Chromium. It loads a 22.7 MB wasm binary from `dist/assets/litert`
|
|
653
|
-
and the 2.
|
|
683
|
+
and the 2.0 GB model file. The GPU engine reports progress while the file
|
|
654
684
|
downloads and 100% of the load phase while the model compiles.
|
|
655
685
|
|
|
656
686
|
wllama needs the compat worker on the same origin. When the app serves the
|
|
@@ -739,7 +769,7 @@ The public enums are `ChatModelId`, `LlmRole`, `ChatStatus`, `LlmStatus`,
|
|
|
739
769
|
The suites live in `test/` and run against the local checkout.
|
|
740
770
|
|
|
741
771
|
`yarn test:instruct` starts a local llama.cpp server with the Qwen3-VL 2B
|
|
742
|
-
Instruct
|
|
772
|
+
Instruct Q4_K_M build:
|
|
743
773
|
|
|
744
774
|
```bash
|
|
745
775
|
yarn test:instruct
|
|
@@ -769,6 +799,9 @@ An interactive map of the package lives at
|
|
|
769
799
|
the two entries, every source module with line numbers, the helper edges and the
|
|
770
800
|
send flow.
|
|
771
801
|
|
|
802
|
+
A side-by-side comparison with `@mlc-ai/web-llm` for Gemma 4 E2B on WebGPU lives
|
|
803
|
+
at [degreesign.github.io/ds_chat/vs_web_llm.html](https://degreesign.github.io/ds_chat/vs_web_llm.html).
|
|
804
|
+
|
|
772
805
|
## FAQ
|
|
773
806
|
|
|
774
807
|
### What is @degreesign/chat?
|
|
@@ -783,25 +816,19 @@ No. The host passes the full prompt on every call and keeps the reply.
|
|
|
783
816
|
### Does it support images?
|
|
784
817
|
|
|
785
818
|
Yes, on models with vision support. Put image URLs in a user turn's `images`
|
|
786
|
-
array. Qwen3-VL 2B accepts images on the CPU engine and
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
at most 136, with both sides snapped to multiples of 32 px and the remainder
|
|
791
|
-
cropped. The WebGPU engine instead center-crops a 384 x 384 square with the
|
|
792
|
-
smallest Gemma 4 vision budget. A model without vision drops images
|
|
819
|
+
array. Qwen3-VL 2B accepts images on the CPU engine and is the vision model in
|
|
820
|
+
the catalog. Each image keeps its full frame and targets 128 vision tokens, at
|
|
821
|
+
most 136, with both sides snapped to multiples of 32 px and the remainder
|
|
822
|
+
cropped. The WebGPU build is text only, so a model without vision drops images
|
|
793
823
|
when the turn also has text; an image-only turn reports
|
|
794
824
|
`Model does not accept images`.
|
|
795
825
|
|
|
796
826
|
### Does it support audio?
|
|
797
827
|
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
The package does not transcode, so the host supplies one of those formats. A
|
|
803
|
-
model without audio drops the clip when the turn also has text; an audio-only
|
|
804
|
-
turn reports `Model does not accept audio`.
|
|
828
|
+
No model in the catalog has an audio encoder. A user turn can still carry an
|
|
829
|
+
audio URL in `audio`, and `limits.maxAudio` caps the clips (default 1), but a
|
|
830
|
+
model without audio support drops the clip when the turn also has text, and an
|
|
831
|
+
audio-only turn reports `Model does not accept audio`.
|
|
805
832
|
|
|
806
833
|
### Does it need a server?
|
|
807
834
|
|
|
@@ -824,11 +851,11 @@ when an older version stored the file. The package stores no model data itself.
|
|
|
824
851
|
|
|
825
852
|
### Which model should I pick?
|
|
826
853
|
|
|
827
|
-
Qwen3-VL 2B supports reasoning and images on the CPU
|
|
828
|
-
|
|
829
|
-
but a larger download and a slower first compile. Use Qwen for
|
|
830
|
-
support and for
|
|
831
|
-
|
|
854
|
+
Qwen3-VL 2B supports reasoning and images on the CPU, and it runs on any browser
|
|
855
|
+
with WebAssembly. Gemma 4 E2B limited supports reasoning on WebGPU, with faster
|
|
856
|
+
text generation but a larger download and a slower first compile. Use Qwen for
|
|
857
|
+
broad browser support and for images. Use Gemma on a device with a WebGPU
|
|
858
|
+
adapter when text speed matters.
|
|
832
859
|
|
|
833
860
|
## Licensing
|
|
834
861
|
|