@missionsquad/browserai 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.
Files changed (146) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +229 -0
  3. package/dist/audio/clip.d.ts +51 -0
  4. package/dist/audio/clip.d.ts.map +1 -0
  5. package/dist/audio/clip.js +71 -0
  6. package/dist/audio/clip.js.map +1 -0
  7. package/dist/audio/decode.d.ts +7 -0
  8. package/dist/audio/decode.d.ts.map +1 -0
  9. package/dist/audio/decode.js +19 -0
  10. package/dist/audio/decode.js.map +1 -0
  11. package/dist/audio/pcm.d.ts +13 -0
  12. package/dist/audio/pcm.d.ts.map +1 -0
  13. package/dist/audio/pcm.js +66 -0
  14. package/dist/audio/pcm.js.map +1 -0
  15. package/dist/audio/recorder.d.ts +40 -0
  16. package/dist/audio/recorder.d.ts.map +1 -0
  17. package/dist/audio/recorder.js +127 -0
  18. package/dist/audio/recorder.js.map +1 -0
  19. package/dist/audio/streaming-player.d.ts +29 -0
  20. package/dist/audio/streaming-player.d.ts.map +1 -0
  21. package/dist/audio/streaming-player.js +82 -0
  22. package/dist/audio/streaming-player.js.map +1 -0
  23. package/dist/client.d.ts +195 -0
  24. package/dist/client.d.ts.map +1 -0
  25. package/dist/client.js +638 -0
  26. package/dist/client.js.map +1 -0
  27. package/dist/config.d.ts +81 -0
  28. package/dist/config.d.ts.map +1 -0
  29. package/dist/config.js +19 -0
  30. package/dist/config.js.map +1 -0
  31. package/dist/errors.d.ts +52 -0
  32. package/dist/errors.d.ts.map +1 -0
  33. package/dist/errors.js +74 -0
  34. package/dist/errors.js.map +1 -0
  35. package/dist/events.d.ts +18 -0
  36. package/dist/events.d.ts.map +1 -0
  37. package/dist/events.js +43 -0
  38. package/dist/events.js.map +1 -0
  39. package/dist/generation.d.ts +12 -0
  40. package/dist/generation.d.ts.map +1 -0
  41. package/dist/generation.js +30 -0
  42. package/dist/generation.js.map +1 -0
  43. package/dist/hardware.d.ts +23 -0
  44. package/dist/hardware.d.ts.map +1 -0
  45. package/dist/hardware.js +150 -0
  46. package/dist/hardware.js.map +1 -0
  47. package/dist/history.d.ts +81 -0
  48. package/dist/history.d.ts.map +1 -0
  49. package/dist/history.js +193 -0
  50. package/dist/history.js.map +1 -0
  51. package/dist/index.d.ts +51 -0
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/index.js +50 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/inference.d.ts +89 -0
  56. package/dist/inference.d.ts.map +1 -0
  57. package/dist/inference.js +411 -0
  58. package/dist/inference.js.map +1 -0
  59. package/dist/json.d.ts +22 -0
  60. package/dist/json.d.ts.map +1 -0
  61. package/dist/json.js +145 -0
  62. package/dist/json.js.map +1 -0
  63. package/dist/metrics.d.ts +18 -0
  64. package/dist/metrics.d.ts.map +1 -0
  65. package/dist/metrics.js +59 -0
  66. package/dist/metrics.js.map +1 -0
  67. package/dist/model-cache.d.ts +49 -0
  68. package/dist/model-cache.d.ts.map +1 -0
  69. package/dist/model-cache.js +511 -0
  70. package/dist/model-cache.js.map +1 -0
  71. package/dist/model-source.d.ts +27 -0
  72. package/dist/model-source.d.ts.map +1 -0
  73. package/dist/model-source.js +110 -0
  74. package/dist/model-source.js.map +1 -0
  75. package/dist/models.d.ts +103 -0
  76. package/dist/models.d.ts.map +1 -0
  77. package/dist/models.js +1052 -0
  78. package/dist/models.js.map +1 -0
  79. package/dist/multimodal.d.ts +261 -0
  80. package/dist/multimodal.d.ts.map +1 -0
  81. package/dist/multimodal.js +506 -0
  82. package/dist/multimodal.js.map +1 -0
  83. package/dist/prompt.d.ts +13 -0
  84. package/dist/prompt.d.ts.map +1 -0
  85. package/dist/prompt.js +32 -0
  86. package/dist/prompt.js.map +1 -0
  87. package/dist/proxy-verify.d.ts +10 -0
  88. package/dist/proxy-verify.d.ts.map +1 -0
  89. package/dist/proxy-verify.js +98 -0
  90. package/dist/proxy-verify.js.map +1 -0
  91. package/dist/schema-validator.d.ts +6 -0
  92. package/dist/schema-validator.d.ts.map +1 -0
  93. package/dist/schema-validator.js +104 -0
  94. package/dist/schema-validator.js.map +1 -0
  95. package/dist/schema.d.ts +98 -0
  96. package/dist/schema.d.ts.map +1 -0
  97. package/dist/schema.js +115 -0
  98. package/dist/schema.js.map +1 -0
  99. package/dist/text-utils.d.ts +8 -0
  100. package/dist/text-utils.d.ts.map +1 -0
  101. package/dist/text-utils.js +14 -0
  102. package/dist/text-utils.js.map +1 -0
  103. package/dist/voice/helpers.d.ts +35 -0
  104. package/dist/voice/helpers.d.ts.map +1 -0
  105. package/dist/voice/helpers.js +49 -0
  106. package/dist/voice/helpers.js.map +1 -0
  107. package/dist/voice/voice-pipeline.d.ts +155 -0
  108. package/dist/voice/voice-pipeline.d.ts.map +1 -0
  109. package/dist/voice/voice-pipeline.js +407 -0
  110. package/dist/voice/voice-pipeline.js.map +1 -0
  111. package/dist/webllm.worker.d.ts +2 -0
  112. package/dist/webllm.worker.d.ts.map +1 -0
  113. package/dist/webllm.worker.js +8 -0
  114. package/dist/webllm.worker.js.map +1 -0
  115. package/package.json +62 -0
  116. package/src/audio/clip.ts +94 -0
  117. package/src/audio/decode.ts +19 -0
  118. package/src/audio/pcm.ts +62 -0
  119. package/src/audio/recorder.ts +146 -0
  120. package/src/audio/streaming-player.ts +99 -0
  121. package/src/client.ts +784 -0
  122. package/src/config.ts +104 -0
  123. package/src/errors.ts +81 -0
  124. package/src/events.ts +53 -0
  125. package/src/generation.ts +39 -0
  126. package/src/hardware.ts +193 -0
  127. package/src/history.ts +257 -0
  128. package/src/index.ts +203 -0
  129. package/src/inference.ts +579 -0
  130. package/src/json.ts +169 -0
  131. package/src/metrics.ts +63 -0
  132. package/src/model-cache.ts +637 -0
  133. package/src/model-source.ts +142 -0
  134. package/src/models.ts +1171 -0
  135. package/src/multimodal.ts +697 -0
  136. package/src/prompt.ts +33 -0
  137. package/src/proxy-verify.ts +113 -0
  138. package/src/schema-validator.ts +117 -0
  139. package/src/schema.ts +118 -0
  140. package/src/text-utils.ts +12 -0
  141. package/src/voice/helpers.ts +59 -0
  142. package/src/voice/voice-pipeline.ts +513 -0
  143. package/src/webllm.worker.ts +9 -0
  144. package/worker-template/README.md +39 -0
  145. package/worker-template/cloudflare-worker.ts +389 -0
  146. package/worker-template/wrangler.jsonc +19 -0
@@ -0,0 +1,506 @@
1
+ import { SUPERTONIC_2_MODEL_ID } from "./models.js";
2
+ import { AUDIO_SR } from "./audio/pcm.js";
3
+ /** The kokoro-js CDN bundle loaded by default (kokoro-js ships its own Transformers.js runtime). */
4
+ export const DEFAULT_KOKORO_CDN = "https://cdn.jsdelivr.net/npm/kokoro-js@1.2.1/+esm";
5
+ const MAX_PIXELS = 1_048_576; // ~1.05 MP — larger overflows the q4f16 Qwen-family vision encoder
6
+ /**
7
+ * Speaker-embedding URL for a Supertonic voice id (F1–F5 / M1–M5), resolved against the loaded model's
8
+ * own repo so Supertonic v1 and v2 each fetch their own `voices/*.bin`. Defaults to F1 when unset.
9
+ */
10
+ export function supertonicVoiceUrl(modelId, voiceId) {
11
+ const id = voiceId && /^[FM][1-5]$/.test(voiceId) ? voiceId : "F1";
12
+ return `https://huggingface.co/${modelId}/resolve/main/voices/${id}.bin`;
13
+ }
14
+ /** Count tokens from a TextStreamer token_callback payload (array / typed array / tensor). */
15
+ function countTokenItems(value) {
16
+ if (value == null)
17
+ return 0;
18
+ if (ArrayBuffer.isView(value))
19
+ return value.length ?? 1;
20
+ if (Array.isArray(value))
21
+ return value.length;
22
+ const record = value;
23
+ if (record?.data && typeof record.data.length === "number")
24
+ return record.data.length;
25
+ if (Array.isArray(record?.dims))
26
+ return record.dims.reduce((product, dim) => product * dim, 1);
27
+ if (typeof record?.size === "number")
28
+ return record.size;
29
+ return 1;
30
+ }
31
+ /** A TextStreamer that accumulates text (onDelta) AND counts tokens + records first-token time. */
32
+ function makeCountingStreamer(Streamer, tokenizer, onDelta, sink) {
33
+ return new Streamer(tokenizer, {
34
+ skip_prompt: true,
35
+ skip_special_tokens: true,
36
+ callback_function: (chunk) => {
37
+ if (typeof chunk === "string") {
38
+ if (sink.firstTokenMs === undefined)
39
+ sink.firstTokenMs = performance.now();
40
+ sink.text += chunk;
41
+ onDelta?.(sink.text);
42
+ }
43
+ },
44
+ token_callback_function: (tokens) => {
45
+ sink.completionTokens += countTokenItems(tokens);
46
+ },
47
+ });
48
+ }
49
+ function vlmDtype(preset, runtime) {
50
+ if (runtime === "vlm-vision2seq")
51
+ return { embed_tokens: "fp16", vision_encoder: "q4", decoder_model_merged: "q4" };
52
+ // imagetext family: GLM-OCR ships a single q4f16 dtype; Qwen3-VL uses a per-module mixed map.
53
+ if (preset.transformersDtype)
54
+ return preset.transformersDtype;
55
+ return { embed_tokens: "fp16", vision_encoder: "fp16", decoder_model_merged: "q4f16" };
56
+ }
57
+ /**
58
+ * Load the shared pieces of an audio-text-to-text model (Granite Speech, Voxtral realtime): the
59
+ * AutoProcessor and the AutoModelForAudioTextToText model on WebGPU. All three ONNX modules
60
+ * (audio_encoder, embed_tokens, decoder_model_merged) publish a q4f16 variant, so a flat dtype loads
61
+ * them uniformly; preset.transformersDtype overrides it if a model needs a different mix. The caller
62
+ * tags the returned bundle with the right handle `kind` (audiolm vs audiolm-stream).
63
+ */
64
+ async function loadAudioLmSessions(preset, transformers, progress_callback) {
65
+ const processor = await transformers.AutoProcessor.from_pretrained(preset.id, { progress_callback });
66
+ const dtype = preset.transformersDtype ?? "q4f16";
67
+ const model = await transformers.AutoModelForAudioTextToText.from_pretrained(preset.id, { device: "webgpu", dtype, progress_callback });
68
+ return { processor, model, Streamer: transformers.TextStreamer };
69
+ }
70
+ export async function loadMultimodal(preset, transformers, device, progress_callback, options = {}) {
71
+ const runtime = preset.mmRuntime;
72
+ if (!runtime)
73
+ throw new Error(`Model ${preset.shortName} has no multimodal runtime.`);
74
+ switch (runtime) {
75
+ case "stt": {
76
+ // Whisper/Moonshine load an fp32 encoder + a quantized decoder (encoder quantization hurts
77
+ // accuracy). Some ASR models document a single flat dtype instead — e.g. Cohere's cohere_asr,
78
+ // whose fp32 encoder is multiple GB, ships a q4 WebGPU recipe. Honor preset.transformersDtype
79
+ // when set so those models are not force-loaded with an fp32 encoder.
80
+ const dtype = preset.transformersDtype ??
81
+ (device === "webgpu"
82
+ ? { encoder_model: "fp32", decoder_model_merged: "q4" }
83
+ : { encoder_model: "fp32", decoder_model_merged: "q8" });
84
+ const transcriber = await transformers.pipeline("automatic-speech-recognition", preset.id, { device, dtype, progress_callback });
85
+ return { kind: "stt", transcriber };
86
+ }
87
+ case "tts-pipeline": {
88
+ const synth = await transformers.pipeline("text-to-speech", preset.id, { device, dtype: "fp32", progress_callback });
89
+ return { kind: "tts-pipeline", synth, modelId: preset.id };
90
+ }
91
+ case "tts-kokoro": {
92
+ // kokoro-js bundles its own Transformers.js runtime; by default load it from the CDN.
93
+ const kokoro = await loadKokoroModule(options.kokoro);
94
+ const tts = await kokoro.KokoroTTS.from_pretrained(preset.id, {
95
+ dtype: device === "webgpu" ? "fp32" : "q8",
96
+ device,
97
+ progress_callback,
98
+ });
99
+ return { kind: "tts-kokoro", tts: tts, TextSplitterStream: kokoro.TextSplitterStream };
100
+ }
101
+ case "vlm-vision2seq":
102
+ case "vlm-imagetext": {
103
+ const processor = await transformers.AutoProcessor.from_pretrained(preset.id, { progress_callback });
104
+ const ModelClass = runtime === "vlm-vision2seq" ? transformers.AutoModelForVision2Seq : transformers.AutoModelForImageTextToText;
105
+ const model = await ModelClass.from_pretrained(preset.id, { device: "webgpu", dtype: vlmDtype(preset, runtime), progress_callback });
106
+ return {
107
+ kind: "vlm",
108
+ processor,
109
+ model,
110
+ Streamer: transformers.TextStreamer,
111
+ loadImage: transformers.load_image,
112
+ maxPixels: runtime === "vlm-imagetext" ? MAX_PIXELS : 0,
113
+ imageArray: runtime === "vlm-vision2seq",
114
+ // Generous caps so descriptions/OCR are not truncated mid-output (any OCR model → 2048).
115
+ maxNewTokens: preset.id.toLowerCase().includes("ocr") ? 2048 : 1024,
116
+ };
117
+ }
118
+ case "gemma-mm": {
119
+ const processor = await transformers.AutoProcessor.from_pretrained(preset.id, { progress_callback });
120
+ const model = await transformers.Gemma4ForConditionalGeneration.from_pretrained(preset.id, { device: "webgpu", dtype: "q4f16", progress_callback });
121
+ return { kind: "gemma", processor, model, Streamer: transformers.TextStreamer, loadImage: transformers.load_image };
122
+ }
123
+ case "audio-text-to-text":
124
+ // Granite Speech / Ultravox / non-realtime Voxtral: audio placeholder token in the prompt.
125
+ return { kind: "audiolm", ...(await loadAudioLmSessions(preset, transformers, progress_callback)) };
126
+ case "voxtral-realtime":
127
+ // Voxtral realtime: same load, but the processor is audio-only and generate is self-stopping.
128
+ return { kind: "audiolm-stream", ...(await loadAudioLmSessions(preset, transformers, progress_callback)) };
129
+ default:
130
+ throw new Error(`Unsupported multimodal runtime: ${runtime}`);
131
+ }
132
+ }
133
+ async function loadKokoroModule(options) {
134
+ if (options?.load)
135
+ return options.load();
136
+ const url = options?.url ?? DEFAULT_KOKORO_CDN;
137
+ // Remote dynamic ESM import: browsers support it natively; bundlers must leave the URL external
138
+ // (the indirection through a variable prevents most bundlers from trying to resolve it).
139
+ return (await import(/* @vite-ignore */ /* webpackIgnore: true */ url));
140
+ }
141
+ export async function disposeMultimodal(handle) {
142
+ if (!handle)
143
+ return;
144
+ const model = handle.model;
145
+ try {
146
+ if (typeof model?.dispose === "function")
147
+ await model.dispose();
148
+ }
149
+ catch {
150
+ // Best-effort; the WebGPU context is released when the tab/model is replaced.
151
+ }
152
+ }
153
+ /* ------------------------------------------------------------------ */
154
+ /* Inference */
155
+ /* ------------------------------------------------------------------ */
156
+ /**
157
+ * Gemma's audio feature-extractor only "hears" ~30s per generate() call, so a longer clip must be
158
+ * split into ≤30s windows and transcribed window-by-window. Cap the total work at 12 minutes.
159
+ */
160
+ const GEMMA_AUDIO_CHUNK_SEC = 30;
161
+ const GEMMA_AUDIO_MAX_SEC = 12 * 60; // 720s ceiling on chunked transcription
162
+ const GEMMA_TRANSCRIBE_PROMPT = "Transcribe this audio verbatim.";
163
+ /**
164
+ * Plan the consecutive, non-overlapping ≤30s sample windows a Gemma transcription splits a clip
165
+ * into. The clip is first truncated to the 12-minute ceiling, then walked in
166
+ * {@link GEMMA_AUDIO_CHUNK_SEC} windows (the final window may be shorter). Pure and exported so the
167
+ * boundary math (truncation ceiling, last partial window) is unit-tested independently of a model.
168
+ */
169
+ export function planGemmaAudioWindows(totalSamples) {
170
+ const chunkSamples = GEMMA_AUDIO_CHUNK_SEC * AUDIO_SR;
171
+ const maxSamples = GEMMA_AUDIO_MAX_SEC * AUDIO_SR;
172
+ const usable = Math.min(Math.max(0, Math.floor(totalSamples)), maxSamples);
173
+ const windows = [];
174
+ for (let start = 0; start < usable; start += chunkSamples) {
175
+ windows.push({ start, end: Math.min(start + chunkSamples, usable) });
176
+ }
177
+ return windows;
178
+ }
179
+ /**
180
+ * Transcribe a 16 kHz mono Float32Array. ASR-pipeline models (Whisper/Moonshine — handle kind
181
+ * "stt") additionally accept an audio URL, which the Transformers.js pipeline fetches and decodes;
182
+ * the generative STT recipes (Gemma, Granite Speech, Voxtral) require decoded PCM.
183
+ * @throws {Error} when a URL is passed to a model that cannot fetch audio itself.
184
+ */
185
+ export async function transcribe(handle, audio, onDelta) {
186
+ if (typeof audio === "string" && handle.kind !== "stt") {
187
+ throw new Error("URL audio input is only supported by ASR-pipeline models (Whisper/Moonshine). Decode to 16 kHz mono PCM first (decodeAudioTo16kMono).");
188
+ }
189
+ if (handle.kind === "gemma") {
190
+ // Callers supply decoded 16 kHz samples; chunk anything past Gemma's ~30s window.
191
+ return transcribeGemmaChunked(handle, audio, onDelta);
192
+ }
193
+ if (handle.kind === "audiolm") {
194
+ // Audio-LLM (Granite Speech, etc.): single-pass generate over the whole clip, no segments.
195
+ return transcribeAudioLm(handle, audio, onDelta);
196
+ }
197
+ if (handle.kind === "audiolm-stream") {
198
+ // Voxtral realtime: audio-only, self-stopping generate over the whole clip, no segments.
199
+ return transcribeVoxtralRealtime(handle, audio, onDelta);
200
+ }
201
+ if (handle.kind !== "stt")
202
+ throw new Error("Loaded model cannot transcribe audio.");
203
+ // Whisper supports segment timestamps; Moonshine may not — try, then fall back to a plain pass.
204
+ let out;
205
+ try {
206
+ out = await handle.transcriber(audio, { return_timestamps: true, chunk_length_s: 30, stride_length_s: 5 });
207
+ }
208
+ catch {
209
+ out = await handle.transcriber(audio);
210
+ }
211
+ const text = String(out?.text ?? "").trim();
212
+ const chunks = Array.isArray(out?.chunks) ? out.chunks : [];
213
+ const segments = chunks
214
+ .filter((c) => Array.isArray(c.timestamp))
215
+ .map((c) => ({ start: c.timestamp[0] ?? 0, end: c.timestamp[1] ?? 0, text: String(c.text ?? "").trim() }))
216
+ .filter((s) => s.text.length > 0);
217
+ return { text, segments };
218
+ }
219
+ /**
220
+ * Transcribe with Gemma, splitting audio longer than {@link GEMMA_AUDIO_CHUNK_SEC} into consecutive
221
+ * non-overlapping windows (Gemma's feature-extractor only hears ~30s per pass). Clips beyond
222
+ * {@link GEMMA_AUDIO_MAX_SEC} are truncated to that ceiling. Each window becomes a timestamped segment;
223
+ * partial text streams across windows (already-finished windows are prefixed onto the live one), and
224
+ * the returned telemetry sums token counts across all windows for accurate stats.
225
+ */
226
+ async function transcribeGemmaChunked(handle, audio, onDelta) {
227
+ const windows = planGemmaAudioWindows(audio.length);
228
+ // Fast path: a single ≤30s window (or empty audio) needs no chunk bookkeeping.
229
+ if (windows.length <= 1) {
230
+ const clip = windows[0] ? audio.subarray(windows[0].start, windows[0].end) : audio;
231
+ const result = await runGemma(handle, { audio: clip, prompt: GEMMA_TRANSCRIBE_PROMPT }, onDelta);
232
+ return { text: result.text, segments: [], gen: result };
233
+ }
234
+ const segments = [];
235
+ const parts = [];
236
+ const startedMs = performance.now();
237
+ let completionTokens = 0;
238
+ let firstTokenMs;
239
+ for (const window of windows) {
240
+ const prior = parts.join(" ");
241
+ const result = await runGemma(handle, { audio: audio.subarray(window.start, window.end), prompt: GEMMA_TRANSCRIBE_PROMPT }, (partial) => {
242
+ onDelta?.(prior ? `${prior} ${partial}` : partial);
243
+ });
244
+ const windowText = result.text.trim();
245
+ if (windowText) {
246
+ segments.push({ start: window.start / AUDIO_SR, end: window.end / AUDIO_SR, text: windowText });
247
+ parts.push(windowText);
248
+ onDelta?.(parts.join(" "));
249
+ }
250
+ completionTokens += result.completionTokens;
251
+ if (firstTokenMs === undefined && result.firstTokenMs !== undefined)
252
+ firstTokenMs = result.firstTokenMs;
253
+ }
254
+ return { text: parts.join(" "), segments, gen: { completionTokens, firstTokenMs, startedMs, endedMs: performance.now() } };
255
+ }
256
+ const AUDIO_LM_TRANSCRIBE_PROMPT = "Transcribe this audio verbatim.";
257
+ /**
258
+ * Transcribe with an audio-text-to-text LLM (Granite Speech / Voxtral). These models take a decoded
259
+ * 16 kHz clip plus a text instruction and *generate* the transcript, so — unlike the Whisper pipeline
260
+ * — there are no per-segment timestamps. The whole clip is run in a single pass and returned as plain
261
+ * text plus real token/latency telemetry.
262
+ */
263
+ async function transcribeAudioLm(handle, audio, onDelta) {
264
+ const result = await runAudioLm(handle, audio, AUDIO_LM_TRANSCRIBE_PROMPT, onDelta);
265
+ return { text: result.text, segments: [], gen: result };
266
+ }
267
+ /**
268
+ * Generate text from a 16 kHz mono clip + a text prompt with an audio-text-to-text model. The prompt
269
+ * must carry the model's audio placeholder token: the processor (verified GraniteSpeechProcessor code)
270
+ * requires the token to be present in the text and replaces it with N audio tokens sized to the clip.
271
+ * So the placeholder is embedded in the user turn's (string) content, rendered with
272
+ * `apply_chat_template({ tokenize: false })`, then `processor(text, audio)` produces the model inputs
273
+ * (this is why a list-content chat turn fails — the model's chat template drops the audio marker).
274
+ * Streams partial text via onDelta; returns text + telemetry.
275
+ */
276
+ export async function runAudioLm(handle, audio, prompt, onDelta) {
277
+ const audioToken = handle.processor?.config?.audio_token ?? "<|audio|>";
278
+ const conversation = [{ role: "user", content: `${audioToken}${prompt}` }];
279
+ const text = handle.processor.apply_chat_template(conversation, { add_generation_prompt: true, tokenize: false });
280
+ const inputs = await handle.processor(text, audio);
281
+ const sink = { text: "", completionTokens: 0, firstTokenMs: undefined };
282
+ const startedMs = performance.now();
283
+ const streamer = makeCountingStreamer(handle.Streamer, handle.processor.tokenizer, onDelta, sink);
284
+ await handle.model.generate({ ...inputs, max_new_tokens: 1024, do_sample: false, streamer });
285
+ return { text: sink.text.trim(), completionTokens: sink.completionTokens, firstTokenMs: sink.firstTokenMs, startedMs, endedMs: performance.now() };
286
+ }
287
+ /** Transcribe with Voxtral realtime (single-pass over the whole clip). No timestamped segments. */
288
+ async function transcribeVoxtralRealtime(handle, audio, onDelta) {
289
+ const result = await runVoxtralRealtime(handle, audio, onDelta);
290
+ return { text: result.text, segments: [], gen: result };
291
+ }
292
+ /**
293
+ * Transcribe a 16 kHz mono clip with a Voxtral realtime model. This is a genuine *streaming* model:
294
+ * its `generate` consumes audio as it decodes through a causal streaming encoder, so it is NOT a
295
+ * single-pass `generate({ input_features })` call. Faithful to the verified 4.2.0 recipe (from
296
+ * `tests/models/voxtral_realtime/test_modeling_voxtral_realtime.js`):
297
+ * - Seed `input_ids` from the first streaming chunk (BOS + pad/delay tokens).
298
+ * - Pass `input_features` as an async generator that yields the first chunk's features then hop-based
299
+ * subsequent chunks; the model pulls from it and stops via its internal AudioExhaustedCriteria.
300
+ *
301
+ * The model emits each token ~NUM_DELAY_TOKENS behind the audio it is hearing, so for a fixed file the
302
+ * final words never flush unless more audio follows them. We right-pad the clip with silence by the
303
+ * processor's own offline amount (`num_right_pad_tokens` tokens) — the same flush its non-streaming
304
+ * mode applies — before streaming, so the delayed tail tokens are emitted instead of truncated.
305
+ * Streams partial text via onDelta; returns text + telemetry.
306
+ */
307
+ export async function runVoxtralRealtime(handle, audio, onDelta) {
308
+ const processor = handle.processor;
309
+ const hopLength = processor.feature_extractor.config.hop_length;
310
+ const winHalf = Math.floor(processor.feature_extractor.config.n_fft / 2);
311
+ const firstChunkSamples = processor.num_samples_first_audio_chunk;
312
+ const chunkSamples = processor.num_samples_per_audio_chunk;
313
+ const firstMelFrames = processor.num_mel_frames_first_audio_chunk;
314
+ const audioLenPerTok = processor.audio_length_per_tok;
315
+ const rawPerTok = processor.raw_audio_length_per_tok;
316
+ // Right-pad with silence to flush the transcription delay (see doc comment), matching the amount the
317
+ // processor's own offline/non-streaming path uses. Without this the last word is truncated.
318
+ const flushSamples = processor.num_right_pad_tokens * rawPerTok;
319
+ const clip = new Float32Array(audio.length + flushSamples);
320
+ clip.set(audio);
321
+ // The first streaming chunk supplies the seed input_ids (BOS + NUM_LEFT_PAD + NUM_DELAY pad tokens).
322
+ const firstChunk = await processor(clip.subarray(0, firstChunkSamples), { is_streaming: true, is_first_audio_chunk: true });
323
+ // Async generator of per-chunk mel features that the streaming encoder consumes as generation runs.
324
+ async function* featuresStream() {
325
+ const first = await processor(clip.subarray(0, firstChunkSamples), { is_streaming: true, is_first_audio_chunk: true });
326
+ yield first.input_features;
327
+ let melFrameIdx = firstMelFrames;
328
+ let startIdx = melFrameIdx * hopLength - winHalf;
329
+ while (startIdx + chunkSamples < clip.length) {
330
+ const endIdx = startIdx + chunkSamples;
331
+ const chunk = await processor(clip.slice(startIdx, endIdx), { is_streaming: true, is_first_audio_chunk: false });
332
+ yield chunk.input_features;
333
+ melFrameIdx += audioLenPerTok;
334
+ startIdx = melFrameIdx * hopLength - winHalf;
335
+ }
336
+ }
337
+ // AudioExhaustedCriteria ends generation when the stream drains; this is only a safety backstop
338
+ // sized to the clip (~one text token per raw_audio_length_per_tok samples).
339
+ const maxNewTokens = Math.max(256, Math.ceil(clip.length / rawPerTok) + 128);
340
+ const sink = { text: "", completionTokens: 0, firstTokenMs: undefined };
341
+ const startedMs = performance.now();
342
+ const streamer = makeCountingStreamer(handle.Streamer, processor.tokenizer, onDelta, sink);
343
+ await handle.model.generate({
344
+ input_ids: firstChunk.input_ids,
345
+ input_features: featuresStream(),
346
+ max_new_tokens: maxNewTokens,
347
+ streamer,
348
+ });
349
+ return { text: sink.text.trim(), completionTokens: sink.completionTokens, firstTokenMs: sink.firstTokenMs, startedMs, endedMs: performance.now() };
350
+ }
351
+ /** Synthesize speech. Returns a RawAudio (Float32Array + sampling_rate + toBlob). */
352
+ export async function synthesize(handle, text, opts) {
353
+ if (handle.kind === "tts-kokoro")
354
+ return handle.tts.generate(text, { voice: opts.voice, speed: opts.speed ?? 1 });
355
+ if (handle.kind === "tts-pipeline") {
356
+ const synthOpts = { speaker_embeddings: supertonicVoiceUrl(handle.modelId, opts.voice) };
357
+ let input = text;
358
+ if (handle.modelId === SUPERTONIC_2_MODEL_ID) {
359
+ // Supertonic 2 is multilingual and REQUIRES the text wrapped in a language tag (e.g. <en>…</en>);
360
+ // raw text produces partial words / repeats / gibberish. It also runs a diffusion denoiser, so
361
+ // pass enough inference steps for clean audio. (Speed stays a playback-rate concern, as in v1.)
362
+ input = `<en>${text}</en>`;
363
+ synthOpts.num_inference_steps = 16;
364
+ }
365
+ return handle.synth(input, synthOpts);
366
+ }
367
+ throw new Error("Loaded model cannot synthesize speech.");
368
+ }
369
+ /** Whether a loaded TTS handle can stream sentence-by-sentence audio as text is pushed (Kokoro only). */
370
+ export function supportsStreamingTts(handle) {
371
+ return handle?.kind === "tts-kokoro";
372
+ }
373
+ /**
374
+ * Begin a streaming Kokoro synthesis. Push text into `splitter` as it arrives (e.g. from an LLM token
375
+ * stream) and close() it when done; consume `chunks` to get one RawAudio per completed sentence. The
376
+ * generator is pull-driven — synthesis is serialized per sentence and paced by the consumer loop — and
377
+ * a splitter allows only ONE active iterator, so create a fresh pair per turn via this function.
378
+ * @throws {Error} if the handle is not a Kokoro TTS handle.
379
+ */
380
+ export function synthesizeStream(handle, opts) {
381
+ if (handle.kind !== "tts-kokoro")
382
+ throw new Error("Streaming TTS requires a Kokoro model.");
383
+ const splitter = new handle.TextSplitterStream();
384
+ const stream = handle.tts.stream(splitter, { voice: opts.voice, speed: opts.speed ?? 1 });
385
+ async function* chunks() {
386
+ for await (const part of stream)
387
+ yield part.audio;
388
+ }
389
+ return { splitter, chunks: chunks() };
390
+ }
391
+ /** Answer a question about an image (VLM). Streams partial text via onDelta; returns text + telemetry. */
392
+ export async function describeImage(handle, imageSrc, prompt, onDelta) {
393
+ if (handle.kind === "gemma")
394
+ return runGemma(handle, { imageSrc, prompt }, onDelta);
395
+ if (handle.kind !== "vlm")
396
+ throw new Error("Loaded model cannot analyze images.");
397
+ const messages = [{ role: "user", content: [{ type: "image" }, { type: "text", text: prompt }] }];
398
+ const text = handle.processor.apply_chat_template(messages, { add_generation_prompt: true });
399
+ const src = handle.maxPixels ? await capSrc(imageSrc, handle.maxPixels) : imageSrc;
400
+ const image = await handle.loadImage(src);
401
+ const inputs = handle.imageArray ? await handle.processor(text, [image], {}) : await handle.processor(text, image);
402
+ const sink = { text: "", completionTokens: 0, firstTokenMs: undefined };
403
+ const startedMs = performance.now();
404
+ const streamer = makeCountingStreamer(handle.Streamer, handle.processor.tokenizer, onDelta, sink);
405
+ await handle.model.generate({ ...inputs, max_new_tokens: handle.maxNewTokens, do_sample: false, streamer });
406
+ return { text: sink.text.trim(), completionTokens: sink.completionTokens, firstTokenMs: sink.firstTokenMs, startedMs, endedMs: performance.now() };
407
+ }
408
+ /** Gemma-4 text + image + audio. image/audio placeholders go before the text; audio is a 16 kHz Float32Array. */
409
+ export async function runGemma(handle, input, onDelta) {
410
+ const content = [];
411
+ if (input.imageSrc)
412
+ content.push({ type: "image" });
413
+ if (input.audio)
414
+ content.push({ type: "audio" });
415
+ content.push({ type: "text", text: input.prompt });
416
+ const prompt = handle.processor.apply_chat_template([{ role: "user", content }], { enable_thinking: false, add_generation_prompt: true });
417
+ const image = input.imageSrc ? await handle.loadImage(input.imageSrc) : null;
418
+ const inputs = await handle.processor(prompt, image, input.audio ?? null, { add_special_tokens: false });
419
+ const sink = { text: "", completionTokens: 0, firstTokenMs: undefined };
420
+ const startedMs = performance.now();
421
+ const streamer = makeCountingStreamer(handle.Streamer, handle.processor.tokenizer, onDelta, sink);
422
+ await handle.model.generate({ ...inputs, max_new_tokens: 1024, do_sample: false, streamer });
423
+ return { text: sink.text.trim(), completionTokens: sink.completionTokens, firstTokenMs: sink.firstTokenMs, startedMs, endedMs: performance.now() };
424
+ }
425
+ /**
426
+ * Normalize chat messages into Gemma-friendly turns. Gemma's chat template has no dedicated
427
+ * system role, so any leading system text is folded into the first user turn; each turn's content
428
+ * becomes a `[{type:"text"}]` part (the same content shape the verified image/audio path uses).
429
+ */
430
+ function toGemmaTurns(messages) {
431
+ const turns = [];
432
+ let systemPrefix = "";
433
+ for (const message of messages) {
434
+ if (message.role === "system") {
435
+ systemPrefix += (systemPrefix ? "\n\n" : "") + message.content;
436
+ continue;
437
+ }
438
+ let text = message.content;
439
+ if (message.role === "user" && systemPrefix) {
440
+ text = `${systemPrefix}\n\n${text}`;
441
+ systemPrefix = "";
442
+ }
443
+ turns.push({ role: message.role, content: [{ type: "text", text }] });
444
+ }
445
+ // System-only (no following user turn) still needs to be sent as a user message.
446
+ if (systemPrefix)
447
+ turns.unshift({ role: "user", content: [{ type: "text", text: systemPrefix }] });
448
+ return turns;
449
+ }
450
+ /**
451
+ * Gemma-4 text-only generation from a full chat-message list. Prompt-only (no constrained decoding),
452
+ * matching the Transformers.js text path — a JSON schema is conveyed through the prompt, not a
453
+ * grammar. Streams partial text via onDelta and returns text + real token/latency telemetry.
454
+ */
455
+ export async function generateGemmaText(handle, messages, opts = {}) {
456
+ const prompt = handle.processor.apply_chat_template(toGemmaTurns(messages), { enable_thinking: false, add_generation_prompt: true });
457
+ const inputs = await handle.processor(prompt, null, null, { add_special_tokens: false });
458
+ const sink = { text: "", completionTokens: 0, firstTokenMs: undefined };
459
+ const startedMs = performance.now();
460
+ const streamer = makeCountingStreamer(handle.Streamer, handle.processor.tokenizer, opts.onDelta, sink);
461
+ const doSample = (opts.temperature ?? 0) > 0;
462
+ const genOptions = { ...inputs, max_new_tokens: opts.maxNewTokens ?? 1024, do_sample: doSample, streamer };
463
+ if (doSample && opts.temperature !== undefined)
464
+ genOptions.temperature = opts.temperature;
465
+ if (opts.topP !== undefined)
466
+ genOptions.top_p = opts.topP;
467
+ if (opts.repetitionPenalty !== undefined)
468
+ genOptions.repetition_penalty = opts.repetitionPenalty;
469
+ await handle.model.generate(genOptions);
470
+ return { text: sink.text.trim(), completionTokens: sink.completionTokens, firstTokenMs: sink.firstTokenMs, startedMs, endedMs: performance.now() };
471
+ }
472
+ /* ------------------------------------------------------------------ */
473
+ /* Image helper */
474
+ /* ------------------------------------------------------------------ */
475
+ function loadHTMLImage(src) {
476
+ return new Promise((resolve, reject) => {
477
+ const img = new Image();
478
+ img.crossOrigin = "anonymous";
479
+ img.onload = () => resolve(img);
480
+ img.onerror = () => reject(new Error("image load failed"));
481
+ img.src = src;
482
+ });
483
+ }
484
+ /**
485
+ * Downscale (via a plain canvas) so total pixels ≤ maxPixels, preserving aspect. Returns a PNG
486
+ * data-URL. Guards the Qwen-family vision encoder against an int32 overflow on large images.
487
+ * Browser main-thread only (`Image` + `document.createElement("canvas")` — not available in workers).
488
+ * NOTE: RawImage.resize() is deliberately avoided — its -1 aspect arg produced a malformed image.
489
+ */
490
+ export async function capSrc(src, maxPixels) {
491
+ if (!maxPixels)
492
+ return src;
493
+ const img = await loadHTMLImage(src);
494
+ const px = img.naturalWidth * img.naturalHeight;
495
+ if (px <= maxPixels)
496
+ return src;
497
+ const scale = Math.sqrt(maxPixels / px);
498
+ const w = Math.max(1, Math.round(img.naturalWidth * scale));
499
+ const h = Math.max(1, Math.round(img.naturalHeight * scale));
500
+ const canvas = document.createElement("canvas");
501
+ canvas.width = w;
502
+ canvas.height = h;
503
+ canvas.getContext("2d")?.drawImage(img, 0, 0, w, h);
504
+ return canvas.toDataURL("image/png");
505
+ }
506
+ //# sourceMappingURL=multimodal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multimodal.js","sourceRoot":"","sources":["../src/multimodal.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export declare const DEFAULT_EXTRACTION_INSTRUCTIONS: string;
2
+ /**
3
+ * Build the system + user turns for schema-guided extraction. WebLLM backends additionally enforce
4
+ * the schema with constrained decoding; Transformers.js backends rely on this prompt alone.
5
+ */
6
+ export declare function buildExtractionMessages(inputText: string, schema: unknown, additionalInstructions?: string): ({
7
+ role: "system";
8
+ content: string;
9
+ } | {
10
+ role: "user";
11
+ content: string;
12
+ })[];
13
+ //# sourceMappingURL=prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,+BAA+B,QAOhC,CAAC;AAEb;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,sBAAsB,SAAkC;;;;;;KAmBnI"}
package/dist/prompt.js ADDED
@@ -0,0 +1,32 @@
1
+ export const DEFAULT_EXTRACTION_INSTRUCTIONS = [
2
+ "You are a deterministic information-extraction engine.",
3
+ "Return exactly one JSON object and nothing else.",
4
+ "Never emit Markdown, comments, explanations, hidden reasoning, or a second JSON object.",
5
+ "Stop immediately after the final closing brace of the JSON object.",
6
+ "Use null when a scalar field is unknown. Use [] when a list has no items.",
7
+ "Keep string values concise and do not invent facts not present in the input text.",
8
+ ].join("\n");
9
+ /**
10
+ * Build the system + user turns for schema-guided extraction. WebLLM backends additionally enforce
11
+ * the schema with constrained decoding; Transformers.js backends rely on this prompt alone.
12
+ */
13
+ export function buildExtractionMessages(inputText, schema, additionalInstructions = DEFAULT_EXTRACTION_INSTRUCTIONS) {
14
+ const schemaText = JSON.stringify(schema, null, 2);
15
+ const instructions = additionalInstructions.trim() || DEFAULT_EXTRACTION_INSTRUCTIONS;
16
+ return [
17
+ {
18
+ role: "system",
19
+ content: [
20
+ instructions,
21
+ "",
22
+ "The JSON object must follow this JSON Schema:",
23
+ schemaText,
24
+ ].join("\n"),
25
+ },
26
+ {
27
+ role: "user",
28
+ content: `Extract structured data from the text below. Return one JSON object only.\n\n<text>\n${inputText}\n</text>`,
29
+ },
30
+ ];
31
+ }
32
+ //# sourceMappingURL=prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.js","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,+BAA+B,GAAG;IAC7C,wDAAwD;IACxD,kDAAkD;IAClD,yFAAyF;IACzF,oEAAoE;IACpE,2EAA2E;IAC3E,mFAAmF;CACpF,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAAC,SAAiB,EAAE,MAAe,EAAE,sBAAsB,GAAG,+BAA+B;IAClI,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACnD,MAAM,YAAY,GAAG,sBAAsB,CAAC,IAAI,EAAE,IAAI,+BAA+B,CAAC;IAEtF,OAAO;QACL;YACE,IAAI,EAAE,QAAiB;YACvB,OAAO,EAAE;gBACP,YAAY;gBACZ,EAAE;gBACF,+CAA+C;gBAC/C,UAAU;aACX,CAAC,IAAI,CAAC,IAAI,CAAC;SACb;QACD;YACE,IAAI,EAAE,MAAe;YACrB,OAAO,EAAE,wFAAwF,SAAS,WAAW;SACtH;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { AppConfig } from "@mlc-ai/web-llm";
2
+ /** Verify the proxy Worker is live and can serve the selected WebLLM model's config + wasm library. */
3
+ export declare function verifyWebLLMProxy(proxyOrigin: string, modelId: string, appConfig: AppConfig): Promise<void>;
4
+ /** Verify the proxy Worker can serve a Transformers.js repo's config through /hf-transformers/. */
5
+ export declare function verifyTransformersProxy(proxyOrigin: string, modelId: string): Promise<void>;
6
+ export declare function splitHuggingFaceRepoId(modelId: string): {
7
+ owner: string;
8
+ repo: string;
9
+ };
10
+ //# sourceMappingURL=proxy-verify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy-verify.d.ts","sourceRoot":"","sources":["../src/proxy-verify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAe,MAAM,iBAAiB,CAAC;AAsB9D,uGAAuG;AACvG,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CA+CjH;AAYD,mGAAmG;AACnG,wBAAsB,uBAAuB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAajG;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAIvF"}