@tryhamster/gerbil 1.0.0-rc.8 → 1.0.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.
- package/LICENSE +1 -1
- package/README.md +247 -84
- package/dist/architectures-C1I5V3Dt.mjs +6070 -0
- package/dist/architectures-C1I5V3Dt.mjs.map +1 -0
- package/dist/browser/index.d.ts +264 -588
- package/dist/browser/index.d.ts.map +1 -1
- package/dist/browser/index.js +585 -2334
- package/dist/browser/index.js.map +1 -1
- package/dist/cli.mjs +625 -1098
- package/dist/cli.mjs.map +1 -1
- package/dist/defaults-9komdrbY.mjs +24 -0
- package/dist/defaults-9komdrbY.mjs.map +1 -0
- package/dist/frameworks/express.d.mts +1 -3
- package/dist/frameworks/express.d.mts.map +1 -1
- package/dist/frameworks/express.mjs +7 -7
- package/dist/frameworks/express.mjs.map +1 -1
- package/dist/frameworks/fastify.d.mts +1 -1
- package/dist/frameworks/fastify.d.mts.map +1 -1
- package/dist/frameworks/fastify.mjs +3 -3
- package/dist/frameworks/fastify.mjs.map +1 -1
- package/dist/frameworks/hono.d.mts +1 -1
- package/dist/frameworks/hono.d.mts.map +1 -1
- package/dist/frameworks/hono.mjs +4 -4
- package/dist/frameworks/hono.mjs.map +1 -1
- package/dist/frameworks/next.d.mts +3 -2
- package/dist/frameworks/next.d.mts.map +1 -1
- package/dist/frameworks/next.mjs +4 -4
- package/dist/frameworks/next.mjs.map +1 -1
- package/dist/frameworks/react.d.mts +1 -1
- package/dist/frameworks/trpc.d.mts +1 -1
- package/dist/frameworks/trpc.d.mts.map +1 -1
- package/dist/frameworks/trpc.mjs +4 -4
- package/dist/frameworks/trpc.mjs.map +1 -1
- package/dist/gerbil-BHrJJIa4.mjs +1656 -0
- package/dist/gerbil-BHrJJIa4.mjs.map +1 -0
- package/dist/gerbil-BT9fCydo.d.mts +488 -0
- package/dist/gerbil-BT9fCydo.d.mts.map +1 -0
- package/dist/gerbil-DomNfIr1.mjs +4 -0
- package/dist/gpu/hooks.d.mts +520 -0
- package/dist/gpu/hooks.d.mts.map +1 -0
- package/dist/gpu/hooks.mjs +1188 -0
- package/dist/gpu/hooks.mjs.map +1 -0
- package/dist/gpu/index.d.mts +2 -0
- package/dist/gpu/index.mjs +6 -0
- package/dist/gpu-33qCAtHW.mjs +3615 -0
- package/dist/gpu-33qCAtHW.mjs.map +1 -0
- package/dist/index-Dgmb2kE3.d.mts +245 -0
- package/dist/index-Dgmb2kE3.d.mts.map +1 -0
- package/dist/index-jEAL2s-A.d.mts +2022 -0
- package/dist/index-jEAL2s-A.d.mts.map +1 -0
- package/dist/index.d.mts +22 -487
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +13 -8
- package/dist/index.mjs.map +1 -1
- package/dist/indexeddb-store-BWIMtxxH.mjs +103 -0
- package/dist/indexeddb-store-BWIMtxxH.mjs.map +1 -0
- package/dist/indexeddb-store-ClH12Xnl.mjs +4 -0
- package/dist/integrations/ai-sdk.d.mts +75 -6
- package/dist/integrations/ai-sdk.d.mts.map +1 -1
- package/dist/integrations/ai-sdk.mjs +131 -15
- package/dist/integrations/ai-sdk.mjs.map +1 -1
- package/dist/integrations/langchain.d.mts +1 -1
- package/dist/integrations/langchain.d.mts.map +1 -1
- package/dist/integrations/langchain.mjs +5 -5
- package/dist/integrations/langchain.mjs.map +1 -1
- package/dist/integrations/llamaindex.d.mts +1 -1
- package/dist/integrations/llamaindex.d.mts.map +1 -1
- package/dist/integrations/llamaindex.mjs +5 -5
- package/dist/integrations/llamaindex.mjs.map +1 -1
- package/dist/integrations/mcp-client.mjs +3 -3
- package/dist/integrations/mcp-client.mjs.map +1 -1
- package/dist/integrations/mcp.d.mts +3 -2
- package/dist/integrations/mcp.d.mts.map +1 -1
- package/dist/integrations/mcp.mjs +5 -5
- package/dist/{mcp-BvbriaBy.mjs → mcp-1DaMsaBc.mjs} +4 -4
- package/dist/mcp-1DaMsaBc.mjs.map +1 -0
- package/dist/memory/index.d.mts +3 -0
- package/dist/memory/index.mjs +6 -0
- package/dist/memory-D1P7Tmda.mjs +4 -0
- package/dist/memory-DVN0MnIG.mjs +132 -0
- package/dist/memory-DVN0MnIG.mjs.map +1 -0
- package/dist/memory-Dj0J1v88.mjs +294 -0
- package/dist/memory-Dj0J1v88.mjs.map +1 -0
- package/dist/moonshine-stt-BLyVoRpB.mjs +4 -0
- package/dist/moonshine-stt-v_P_Ci_m.mjs +11936 -0
- package/dist/moonshine-stt-v_P_Ci_m.mjs.map +1 -0
- package/dist/{one-liner-s-lD8rCC.mjs → one-liner-DnQn7HJK.mjs} +14 -16
- package/dist/one-liner-DnQn7HJK.mjs.map +1 -0
- package/dist/repl-jV5gcJFA.mjs +9 -0
- package/dist/skills/index.d.mts +270 -320
- package/dist/skills/index.d.mts.map +1 -1
- package/dist/skills/index.mjs +5 -5
- package/dist/{skills-CD3Orlex.mjs → skills-DX8D59UH.mjs} +187 -32
- package/dist/skills-DX8D59UH.mjs.map +1 -0
- package/dist/{tools-Bi1P7Xoy.mjs → tools-DQ1mPUw5.mjs} +34 -22
- package/dist/tools-DQ1mPUw5.mjs.map +1 -0
- package/dist/{types-CiTc7ez3.d.mts → types-D6FiR_oh.d.mts} +106 -12
- package/dist/types-D6FiR_oh.d.mts.map +1 -0
- package/dist/types-DQBe2lFo.d.mts +165 -0
- package/dist/types-DQBe2lFo.d.mts.map +1 -0
- package/dist/{utils-CZBZ8dgR.mjs → utils-DKO55ZmZ.mjs} +1 -1
- package/dist/{utils-CZBZ8dgR.mjs.map → utils-DKO55ZmZ.mjs.map} +1 -1
- package/dist/vector-B0panuy6.mjs +95 -0
- package/dist/vector-B0panuy6.mjs.map +1 -0
- package/docs/PROJECT-STATE.md +321 -0
- package/docs/adding-a-model-family.md +280 -0
- package/docs/ai-sdk.md +70 -61
- package/docs/architecture/overview.md +17 -7
- package/docs/browser.md +203 -8
- package/docs/embeddings.md +156 -0
- package/docs/gerbil-site-native-migration.md +217 -0
- package/docs/gpu-engine/architectures.md +398 -0
- package/docs/gpu-engine/ir.md +372 -0
- package/docs/gpu-engine/kernels.md +718 -0
- package/docs/gpu-engine/paper.html +1759 -0
- package/docs/gpu-engine/paper.md +2109 -0
- package/docs/gpu-engine/safetensors.md +312 -0
- package/docs/gpu-engine/tokenizer.md +302 -0
- package/docs/memory-rag.md +91 -0
- package/docs/metal-safari-intel.md +190 -0
- package/docs/mobile-failure-diagnosis.md +124 -0
- package/docs/mobile.md +99 -0
- package/docs/observability.md +230 -0
- package/docs/onnx-removal-plan.md +339 -0
- package/docs/research/autoresearch-portable.md +904 -0
- package/docs/research/dispatch-reduction-hivemind.md +84 -0
- package/docs/research/ios-safari-model-caching.md +117 -0
- package/docs/research/mobile-webgpu-speed-fusion.md +135 -0
- package/docs/research/native-stt-model-selection.md +49 -0
- package/docs/research/native-tts-model-selection.md +90 -0
- package/docs/research/native-vs-chromium-decision.md +152 -0
- package/docs/research/nemotron-mamba2-inference.md +910 -0
- package/docs/research/qwen35-multimodal.md +293 -0
- package/docs/research/qwen36-gemma4-targets.md +337 -0
- package/docs/research/sota-embedding-models.md +179 -0
- package/docs/research/sota-mobile-models-2026.md +263 -0
- package/docs/research/sota-modality-models.md +202 -0
- package/docs/research/tps-baselines.md +71 -0
- package/docs/research/webgpu-m4-reference.md +104 -0
- package/docs/site-update-plan.md +155 -0
- package/docs/structured-output.md +123 -0
- package/docs/stt.md +63 -446
- package/docs/tts.md +77 -499
- package/docs/vision.md +100 -338
- package/package.json +22 -7
- package/dist/chrome-backend-CORwaIyC.mjs +0 -1212
- package/dist/chrome-backend-CORwaIyC.mjs.map +0 -1
- package/dist/chrome-backend-DIKYoWj-.mjs +0 -3
- package/dist/gerbil-CJ3ifloF.mjs +0 -4
- package/dist/gerbil-Dw4Qj77e.mjs +0 -1631
- package/dist/gerbil-Dw4Qj77e.mjs.map +0 -1
- package/dist/gerbil-qOTe1nl2.d.mts +0 -431
- package/dist/gerbil-qOTe1nl2.d.mts.map +0 -1
- package/dist/kokoro-BNTb6egA.mjs +0 -20210
- package/dist/kokoro-BNTb6egA.mjs.map +0 -1
- package/dist/kokoro-DFRQ1OeM.js +0 -20212
- package/dist/kokoro-DFRQ1OeM.js.map +0 -1
- package/dist/mcp-BvbriaBy.mjs.map +0 -1
- package/dist/one-liner-s-lD8rCC.mjs.map +0 -1
- package/dist/repl-DveXw36T.mjs +0 -9
- package/dist/skills-CD3Orlex.mjs.map +0 -1
- package/dist/stt-CpLYbGFd.mjs +0 -433
- package/dist/stt-CpLYbGFd.mjs.map +0 -1
- package/dist/stt-DRPLEEHB.mjs +0 -3
- package/dist/stt-Te8Qz-Ay.js +0 -433
- package/dist/stt-Te8Qz-Ay.js.map +0 -1
- package/dist/tools-Bi1P7Xoy.mjs.map +0 -1
- package/dist/transformers.web-DokyH3rP.js +0 -3
- package/dist/transformers.web-M6mCnEYJ.js +0 -30382
- package/dist/transformers.web-M6mCnEYJ.js.map +0 -1
- package/dist/tts-C0xx3CtE.js +0 -724
- package/dist/tts-C0xx3CtE.js.map +0 -1
- package/dist/tts-DXgsKGCe.mjs +0 -3
- package/dist/tts-DeGANMNV.mjs +0 -730
- package/dist/tts-DeGANMNV.mjs.map +0 -1
- package/dist/types-CiTc7ez3.d.mts.map +0 -1
- /package/dist/{auto-update-S9s5-g0C.mjs → auto-update-BVaLXcDE.mjs} +0 -0
- /package/dist/{chunk-CkXuGtQK.mjs → chunk-B9cbKln6.mjs} +0 -0
- /package/dist/{microphone-DaMZFRuR.mjs → microphone-Bqmoz9_K.mjs} +0 -0
package/dist/browser/index.d.ts
CHANGED
|
@@ -92,16 +92,47 @@ type EmbedResult = {
|
|
|
92
92
|
/** Time in ms */
|
|
93
93
|
totalTime: number;
|
|
94
94
|
};
|
|
95
|
+
type SearchResult = {
|
|
96
|
+
/** The matched text */
|
|
97
|
+
text: string;
|
|
98
|
+
/** Similarity score (0-1, higher is more similar) */
|
|
99
|
+
score: number;
|
|
100
|
+
/** Index in the original corpus */
|
|
101
|
+
index: number;
|
|
102
|
+
};
|
|
103
|
+
type SimilarityResult = {
|
|
104
|
+
/** Similarity score (0-1, higher is more similar) */
|
|
105
|
+
score: number;
|
|
106
|
+
/** First text */
|
|
107
|
+
textA: string;
|
|
108
|
+
/** Second text */
|
|
109
|
+
textB: string;
|
|
110
|
+
/** Time in ms */
|
|
111
|
+
totalTime: number;
|
|
112
|
+
};
|
|
95
113
|
type LoadOptions = {
|
|
96
114
|
/** Progress callback */
|
|
97
115
|
onProgress?: (info: ProgressInfo) => void;
|
|
98
|
-
/**
|
|
99
|
-
|
|
100
|
-
|
|
116
|
+
/**
|
|
117
|
+
* Compute device. The only inference backend is the native WebGPU engine
|
|
118
|
+
* (Dawn in Node, WebGPU in the browser); "auto" resolves to "webgpu". There
|
|
119
|
+
* is no CPU/WASM or ONNX path.
|
|
120
|
+
*/
|
|
121
|
+
device?: "auto" | "webgpu";
|
|
122
|
+
/**
|
|
123
|
+
* Weight quantization. The engine quantizes to INT4 ("q4") on load; the other
|
|
124
|
+
* values are accepted for forward-compat but currently map to q4.
|
|
125
|
+
*/
|
|
101
126
|
dtype?: "q4" | "q8" | "fp16" | "fp32";
|
|
102
127
|
/** Override context length */
|
|
103
128
|
contextLength?: number;
|
|
104
129
|
};
|
|
130
|
+
type PreloadOptions = {
|
|
131
|
+
/** Progress callback for download status */
|
|
132
|
+
onProgress?: (info: ProgressInfo) => void;
|
|
133
|
+
/** Keep model loaded in memory after preload (default: false - disposes to free memory) */
|
|
134
|
+
keepLoaded?: boolean;
|
|
135
|
+
};
|
|
105
136
|
type ProgressInfo = {
|
|
106
137
|
status: string;
|
|
107
138
|
progress?: number;
|
|
@@ -112,14 +143,18 @@ type ProgressInfo = {
|
|
|
112
143
|
type GerbilConfig = {
|
|
113
144
|
/** Default model */
|
|
114
145
|
model?: string;
|
|
115
|
-
/** Default device */
|
|
116
|
-
device?: "auto" | "
|
|
117
|
-
/** Default quantization */
|
|
146
|
+
/** Default device (native WebGPU only; "auto" resolves to "webgpu") */
|
|
147
|
+
device?: "auto" | "webgpu";
|
|
148
|
+
/** Default quantization (engine uses INT4 "q4") */
|
|
118
149
|
dtype?: "q4" | "q8" | "fp16" | "fp32";
|
|
119
150
|
/** Cache configuration */
|
|
120
151
|
cache?: CacheConfig;
|
|
121
152
|
/** Fallback configuration */
|
|
122
153
|
fallback?: FallbackConfig;
|
|
154
|
+
/** Telemetry hooks for observability (Sentry, logging, etc.) */
|
|
155
|
+
telemetry?: TelemetryConfig;
|
|
156
|
+
/** Concurrency control for request queuing */
|
|
157
|
+
concurrency?: ConcurrencyConfig;
|
|
123
158
|
};
|
|
124
159
|
type CacheConfig = {
|
|
125
160
|
/** Enable caching (default: true) */
|
|
@@ -183,14 +218,14 @@ type SystemInfo = {
|
|
|
183
218
|
type GerbilModelSettings = {
|
|
184
219
|
/** Enable thinking mode */
|
|
185
220
|
thinking?: boolean;
|
|
186
|
-
/** Device to use */
|
|
187
|
-
device?: "auto" | "
|
|
221
|
+
/** Device to use (native WebGPU only) */
|
|
222
|
+
device?: "auto" | "webgpu";
|
|
188
223
|
/** Quantization level */
|
|
189
224
|
dtype?: "q4" | "q8" | "fp16" | "fp32";
|
|
190
225
|
};
|
|
191
226
|
type GerbilProviderSettings = {
|
|
192
|
-
/** Default device */
|
|
193
|
-
device?: "auto" | "
|
|
227
|
+
/** Default device (native WebGPU only) */
|
|
228
|
+
device?: "auto" | "webgpu";
|
|
194
229
|
/** Default quantization */
|
|
195
230
|
dtype?: "q4" | "q8" | "fp16" | "fp32";
|
|
196
231
|
};
|
|
@@ -348,381 +383,150 @@ type StreamingTranscriptionSession = {
|
|
|
348
383
|
/** Reset session (clear buffer and transcript) */
|
|
349
384
|
reset: () => void;
|
|
350
385
|
};
|
|
351
|
-
//#endregion
|
|
352
|
-
//#region src/core/models.d.ts
|
|
353
|
-
declare const BUILTIN_MODELS: Record<string, ModelConfig>;
|
|
354
|
-
//#endregion
|
|
355
|
-
//#region src/browser/index.d.ts
|
|
356
|
-
|
|
357
|
-
type WorkerProgress = {
|
|
358
|
-
status: "loading" | "downloading" | "ready" | "error";
|
|
359
|
-
message?: string;
|
|
360
|
-
file?: string;
|
|
361
|
-
progress?: number;
|
|
362
|
-
/** Number of files being downloaded (0 = loading from cache) */
|
|
363
|
-
downloadCount?: number;
|
|
364
|
-
/** Total files to process */
|
|
365
|
-
totalFiles?: number;
|
|
366
|
-
error?: string;
|
|
367
|
-
};
|
|
368
|
-
type WorkerToken = {
|
|
369
|
-
status: "token";
|
|
370
|
-
text: string;
|
|
371
|
-
state: "thinking" | "answering";
|
|
372
|
-
numTokens: number;
|
|
373
|
-
tps: number;
|
|
374
|
-
};
|
|
375
|
-
type WorkerComplete = {
|
|
376
|
-
status: "complete";
|
|
377
|
-
text: string;
|
|
378
|
-
numTokens: number;
|
|
379
|
-
totalTime: number;
|
|
380
|
-
tps: number;
|
|
381
|
-
};
|
|
382
|
-
type GerbilWorkerOptions = {
|
|
383
|
-
/** Model ID to load (default: "qwen3-0.6b") */
|
|
384
|
-
modelId?: string;
|
|
385
|
-
/** Called during model loading with progress updates */
|
|
386
|
-
onProgress?: (progress: WorkerProgress) => void;
|
|
387
|
-
/** Called for each token during streaming generation */
|
|
388
|
-
onToken?: (token: WorkerToken) => void;
|
|
389
|
-
/** Called when generation is complete */
|
|
390
|
-
onComplete?: (result: WorkerComplete) => void;
|
|
391
|
-
/** Called on errors */
|
|
392
|
-
onError?: (error: string) => void;
|
|
393
|
-
/** Worker script URL (auto-detected if not provided) */
|
|
394
|
-
workerUrl?: string;
|
|
395
|
-
};
|
|
396
|
-
type GenerateStreamOptions = {
|
|
397
|
-
/** Maximum tokens to generate */
|
|
398
|
-
maxTokens?: number;
|
|
399
|
-
/** Temperature for sampling (0 = deterministic) */
|
|
400
|
-
temperature?: number;
|
|
401
|
-
/** Top-p nucleus sampling */
|
|
402
|
-
topP?: number;
|
|
403
|
-
/** Top-k sampling */
|
|
404
|
-
topK?: number;
|
|
405
|
-
/** Enable thinking mode (Qwen3) */
|
|
406
|
-
thinking?: boolean;
|
|
407
|
-
/** System prompt */
|
|
408
|
-
system?: string;
|
|
409
|
-
/** Image URLs or data URIs (for vision models) */
|
|
410
|
-
images?: string[];
|
|
411
|
-
/** Conversation history for multi-turn (includes all previous messages) */
|
|
412
|
-
history?: Array<{
|
|
413
|
-
role: "user" | "assistant" | "system";
|
|
414
|
-
content: string;
|
|
415
|
-
}>;
|
|
416
|
-
};
|
|
417
|
-
type GerbilWorker = {
|
|
418
|
-
/** Generate text with streaming */
|
|
419
|
-
generate: (prompt: string, options?: GenerateStreamOptions) => Promise<string>;
|
|
420
|
-
/** Interrupt current generation */
|
|
421
|
-
interrupt: () => void;
|
|
422
|
-
/** Reset conversation cache */
|
|
423
|
-
reset: () => void;
|
|
424
|
-
/** Terminate the worker */
|
|
425
|
-
terminate: () => void;
|
|
426
|
-
/** Check if model is loaded */
|
|
427
|
-
isReady: () => boolean;
|
|
428
|
-
};
|
|
429
386
|
/**
|
|
430
|
-
*
|
|
431
|
-
*
|
|
432
|
-
* Uses a Web Worker to keep the UI responsive during model loading
|
|
433
|
-
* and text generation, with real-time token streaming.
|
|
387
|
+
* Telemetry hooks for production observability.
|
|
388
|
+
* Pass your own Sentry instance or custom logging functions.
|
|
434
389
|
*/
|
|
435
|
-
|
|
436
|
-
/**
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
/**
|
|
457
|
-
|
|
458
|
-
/**
|
|
459
|
-
|
|
460
|
-
/**
|
|
461
|
-
|
|
462
|
-
/**
|
|
463
|
-
|
|
464
|
-
/** Max tokens per response */
|
|
465
|
-
maxTokens?: number;
|
|
466
|
-
/** Temperature (0-2) */
|
|
467
|
-
temperature?: number;
|
|
468
|
-
/** Initial messages */
|
|
469
|
-
initialMessages?: Message[];
|
|
470
|
-
/** Auto-load model on mount (default: false - loads on first generate or load()) */
|
|
471
|
-
autoLoad?: boolean;
|
|
472
|
-
/** Called when model is ready */
|
|
473
|
-
onReady?: () => void;
|
|
474
|
-
/** Called on error */
|
|
475
|
-
onError?: (error: string) => void;
|
|
476
|
-
};
|
|
477
|
-
/** Return type for useChat hook */
|
|
478
|
-
type UseChatReturn = {
|
|
479
|
-
/** Chat messages */
|
|
480
|
-
messages: Message[];
|
|
481
|
-
/** Current input value */
|
|
482
|
-
input: string;
|
|
483
|
-
/** Set input value */
|
|
484
|
-
setInput: (value: string) => void;
|
|
485
|
-
/** Submit current input */
|
|
486
|
-
handleSubmit: (e?: {
|
|
487
|
-
preventDefault?: () => void;
|
|
488
|
-
}) => void;
|
|
489
|
-
/** Whether model is loading */
|
|
490
|
-
isLoading: boolean;
|
|
491
|
-
/** Loading progress */
|
|
492
|
-
loadingProgress: LoadingProgress | null;
|
|
493
|
-
/** Whether generating a response */
|
|
494
|
-
isGenerating: boolean;
|
|
495
|
-
/** Current thinking content (streaming) */
|
|
496
|
-
thinking: string;
|
|
497
|
-
/** Stop generation */
|
|
498
|
-
stop: () => void;
|
|
499
|
-
/** Clear all messages */
|
|
500
|
-
clear: () => void;
|
|
501
|
-
/** Current tokens per second */
|
|
502
|
-
tps: number;
|
|
503
|
-
/** Whether model is ready */
|
|
504
|
-
isReady: boolean;
|
|
505
|
-
/** Error message if any */
|
|
506
|
-
error: string | null;
|
|
507
|
-
/** Load the model (only needed if lazy: true) */
|
|
508
|
-
load: () => void;
|
|
509
|
-
/** Currently attached images (for next message) */
|
|
510
|
-
attachedImages: string[];
|
|
511
|
-
/** Attach an image to the next message */
|
|
512
|
-
attachImage: (imageUrl: string) => void;
|
|
513
|
-
/** Remove an attached image */
|
|
514
|
-
removeImage: (index: number) => void;
|
|
515
|
-
/** Clear all attached images */
|
|
516
|
-
clearImages: () => void;
|
|
517
|
-
/** Send message with specific images (convenience method) */
|
|
518
|
-
sendWithImages: (text: string, images: string[]) => void;
|
|
390
|
+
type TelemetryConfig = {
|
|
391
|
+
/**
|
|
392
|
+
* Called after successful generation with full result and timing.
|
|
393
|
+
* Use for logging, metrics, or analytics.
|
|
394
|
+
*/
|
|
395
|
+
onGenerate?: (event: GenerateEvent) => void;
|
|
396
|
+
/**
|
|
397
|
+
* Called when any error occurs during Gerbil operations.
|
|
398
|
+
* Perfect for Sentry.captureException() or similar.
|
|
399
|
+
*/
|
|
400
|
+
onError?: (error: Error, context: ErrorContext) => void;
|
|
401
|
+
/**
|
|
402
|
+
* Called after model loading completes (success or failure).
|
|
403
|
+
*/
|
|
404
|
+
onModelLoad?: (event: ModelLoadEvent) => void;
|
|
405
|
+
/**
|
|
406
|
+
* Called when a request is queued (if concurrency limit reached).
|
|
407
|
+
*/
|
|
408
|
+
onQueueWait?: (waitTimeMs: number) => void;
|
|
409
|
+
};
|
|
410
|
+
type GenerateEvent = {
|
|
411
|
+
/** Model used for generation */
|
|
412
|
+
modelId: string;
|
|
413
|
+
/** Generation result */
|
|
414
|
+
result: GenerateResult;
|
|
415
|
+
/** Whether response came from cache */
|
|
416
|
+
cached: boolean;
|
|
417
|
+
/** Time spent waiting in queue (if any) */
|
|
418
|
+
queueTimeMs?: number;
|
|
519
419
|
};
|
|
520
420
|
/**
|
|
521
|
-
*
|
|
522
|
-
*
|
|
523
|
-
* @example
|
|
524
|
-
* ```tsx
|
|
525
|
-
* import { useChat } from "@tryhamster/gerbil/browser";
|
|
526
|
-
*
|
|
527
|
-
* function Chat() {
|
|
528
|
-
* const { messages, input, setInput, handleSubmit, isLoading, isGenerating } = useChat();
|
|
529
|
-
*
|
|
530
|
-
* if (isLoading) return <div>Loading model...</div>;
|
|
531
|
-
*
|
|
532
|
-
* return (
|
|
533
|
-
* <div>
|
|
534
|
-
* {messages.map(m => (
|
|
535
|
-
* <div key={m.id}>{m.role}: {m.content}</div>
|
|
536
|
-
* ))}
|
|
537
|
-
* <form onSubmit={handleSubmit}>
|
|
538
|
-
* <input value={input} onChange={e => setInput(e.target.value)} />
|
|
539
|
-
* <button disabled={isGenerating}>Send</button>
|
|
540
|
-
* </form>
|
|
541
|
-
* </div>
|
|
542
|
-
* );
|
|
543
|
-
* }
|
|
544
|
-
* ```
|
|
421
|
+
* Context passed to telemetry onError callback.
|
|
422
|
+
* Flexible record to allow any relevant context data.
|
|
545
423
|
*/
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
autoLoad?: boolean;
|
|
561
|
-
/** Called when model is ready */
|
|
562
|
-
onReady?: () => void;
|
|
563
|
-
/** Called on error */
|
|
564
|
-
onError?: (error: string) => void;
|
|
424
|
+
type ErrorContext = Record<string, unknown>;
|
|
425
|
+
type ModelLoadEvent = {
|
|
426
|
+
/** Model that was loaded */
|
|
427
|
+
modelId: string;
|
|
428
|
+
/** Time to load in ms */
|
|
429
|
+
loadTimeMs: number;
|
|
430
|
+
/** Whether loaded from cache */
|
|
431
|
+
fromCache: boolean;
|
|
432
|
+
/** Device used */
|
|
433
|
+
device: "webgpu" | "cpu" | "wasm";
|
|
434
|
+
/** Whether load succeeded */
|
|
435
|
+
success: boolean;
|
|
436
|
+
/** Error message if failed */
|
|
437
|
+
error?: string;
|
|
565
438
|
};
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
/** Return type for useCompletion hook */
|
|
572
|
-
type UseCompletionReturn = {
|
|
573
|
-
/** Generated completion */
|
|
574
|
-
completion: string;
|
|
575
|
-
/** Thinking content (if enabled) */
|
|
576
|
-
thinking: string;
|
|
577
|
-
/** Generate completion (optionally with images for vision models) */
|
|
578
|
-
complete: (prompt: string, options?: CompleteOptions) => Promise<string>;
|
|
579
|
-
/** Whether model is loading */
|
|
580
|
-
isLoading: boolean;
|
|
581
|
-
/** Loading progress */
|
|
582
|
-
loadingProgress: LoadingProgress | null;
|
|
583
|
-
/** Whether generating */
|
|
584
|
-
isGenerating: boolean;
|
|
585
|
-
/** Stop generation */
|
|
586
|
-
stop: () => void;
|
|
587
|
-
/** Current tokens per second */
|
|
588
|
-
tps: number;
|
|
589
|
-
/** Whether model is ready */
|
|
590
|
-
isReady: boolean;
|
|
591
|
-
/** Error message if any */
|
|
592
|
-
error: string | null;
|
|
593
|
-
/** Load the model (only needed if lazy: true) */
|
|
594
|
-
load: () => void;
|
|
439
|
+
type ConcurrencyConfig = {
|
|
440
|
+
/** Maximum concurrent generation requests (default: 1 for LLM) */
|
|
441
|
+
maxConcurrent?: number;
|
|
442
|
+
/** Request timeout in ms (default: 300000 = 5 min) */
|
|
443
|
+
timeout?: number;
|
|
595
444
|
};
|
|
445
|
+
//#endregion
|
|
446
|
+
//#region src/core/models.d.ts
|
|
447
|
+
declare const BUILTIN_MODELS: Record<string, ModelConfig>;
|
|
448
|
+
//#endregion
|
|
449
|
+
//#region src/browser/pwa.d.ts
|
|
596
450
|
/**
|
|
597
|
-
*
|
|
451
|
+
* Mobile / PWA storage helpers.
|
|
598
452
|
*
|
|
599
|
-
*
|
|
600
|
-
*
|
|
601
|
-
*
|
|
453
|
+
* On-device models are large (a 4-bit 0.8B is ~400 MB; vision/larger models are
|
|
454
|
+
* GBs). Mobile browsers — iOS Safari especially — wall a web origin off from the
|
|
455
|
+
* real disk with TWO independent ceilings:
|
|
602
456
|
*
|
|
603
|
-
*
|
|
604
|
-
*
|
|
457
|
+
* 1. **Storage quota** (disk for the model cache). An *uninstalled* Safari tab
|
|
458
|
+
* gets only ~1 GB, best-effort and evictable, regardless of how much free
|
|
459
|
+
* disk the device has. Exceed it and every cache write fails → the model
|
|
460
|
+
* re-downloads on every visit.
|
|
461
|
+
* 2. **Tab memory** (RAM during load/inference) — a separate, smaller ceiling.
|
|
605
462
|
*
|
|
606
|
-
*
|
|
463
|
+
* The unlock for the storage ceiling is **persistent storage**, which iOS Safari
|
|
464
|
+
* grants when the site is **installed to the Home Screen** (a PWA). Installed, the
|
|
465
|
+
* quota jumps to a large fraction of actual disk and is never evicted — so models
|
|
466
|
+
* cache once and stay. These helpers let an app surface that to its users and
|
|
467
|
+
* request it, so on-device AI is actually practical on mobile.
|
|
607
468
|
*
|
|
608
|
-
*
|
|
609
|
-
* <div>
|
|
610
|
-
* <button onClick={() => complete("Write a haiku")}>Generate</button>
|
|
611
|
-
* <p>{completion}</p>
|
|
612
|
-
* </div>
|
|
613
|
-
* );
|
|
614
|
-
* }
|
|
615
|
-
* ```
|
|
469
|
+
* All functions are SSR/Node-safe (guarded; return conservative defaults).
|
|
616
470
|
*/
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
/**
|
|
627
|
-
|
|
628
|
-
/**
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
/**
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
type UseSpeechReturn = {
|
|
657
|
-
/** Speak text aloud */
|
|
658
|
-
speak: (text: string, options?: {
|
|
659
|
-
voice?: string;
|
|
660
|
-
speed?: number;
|
|
661
|
-
}) => Promise<void>;
|
|
662
|
-
/** Stop current speech */
|
|
663
|
-
stop: () => void;
|
|
664
|
-
/** Whether TTS model is loading */
|
|
665
|
-
isLoading: boolean;
|
|
666
|
-
/** Loading progress */
|
|
667
|
-
loadingProgress: TTSProgress | null;
|
|
668
|
-
/** Whether currently speaking */
|
|
669
|
-
isSpeaking: boolean;
|
|
670
|
-
/** Whether TTS model is ready */
|
|
671
|
-
isReady: boolean;
|
|
672
|
-
/** Load the TTS model */
|
|
673
|
-
load: () => void;
|
|
674
|
-
/** Error message if any */
|
|
675
|
-
error: string | null;
|
|
676
|
-
/** List available voices for current model */
|
|
677
|
-
listVoices: () => BrowserVoiceInfo[];
|
|
678
|
-
/** Current voice ID */
|
|
679
|
-
currentVoice: string;
|
|
680
|
-
/** Set current voice */
|
|
681
|
-
setVoice: (voiceId: string) => void;
|
|
682
|
-
/** Current speed */
|
|
683
|
-
currentSpeed: number;
|
|
684
|
-
/** Set speed */
|
|
685
|
-
setSpeed: (speed: number) => void;
|
|
686
|
-
/** Current TTS model ID */
|
|
687
|
-
currentModel: TTSModelId;
|
|
688
|
-
/** Sample rate for current model (24000 for Kokoro, 44100 for Supertonic) */
|
|
689
|
-
sampleRate: number;
|
|
471
|
+
/** True when the page is running as an installed/standalone PWA (Home Screen). */
|
|
472
|
+
declare function isStandalone(): boolean;
|
|
473
|
+
/** True when running on iOS/iPadOS (where install is the quota unlock and the
|
|
474
|
+
* install flow is manual: Share → Add to Home Screen). iPadOS masquerades as
|
|
475
|
+
* macOS, so we also treat touch-capable WebKit-on-Mac as iOS. */
|
|
476
|
+
declare function isIOS(): boolean;
|
|
477
|
+
type StorageStatus = {
|
|
478
|
+
/** Total quota granted to this origin, in MB (best-effort estimate). */
|
|
479
|
+
quotaMB: number;
|
|
480
|
+
/** Bytes currently used by this origin, in MB. */
|
|
481
|
+
usageMB: number;
|
|
482
|
+
/** quota − usage, in MB. */
|
|
483
|
+
availableMB: number;
|
|
484
|
+
/** Storage is persistent (exempt from eviction). On iOS this is effectively
|
|
485
|
+
* only true once the site is installed to the Home Screen. */
|
|
486
|
+
persisted: boolean;
|
|
487
|
+
/** Running as an installed/standalone PWA. */
|
|
488
|
+
installed: boolean;
|
|
489
|
+
/** Platform is iOS/iPadOS (install is the quota unlock here). */
|
|
490
|
+
ios: boolean;
|
|
491
|
+
};
|
|
492
|
+
/** Snapshot of the origin's storage situation — quota, usage, persistence, and
|
|
493
|
+
* whether the app is installed. Use it to decide whether to recommend install
|
|
494
|
+
* before downloading a large model. */
|
|
495
|
+
declare function getStorageStatus(): Promise<StorageStatus>;
|
|
496
|
+
/**
|
|
497
|
+
* Request persistent storage (exempt from eviction). Returns whether the origin
|
|
498
|
+
* is persistent afterwards. Browsers grant this based on engagement/installation;
|
|
499
|
+
* on iOS Safari it is effectively granted only to an installed (Home Screen) PWA,
|
|
500
|
+
* so call this AND guide users to install when it returns false on iOS.
|
|
501
|
+
*/
|
|
502
|
+
declare function requestPersistentStorage(): Promise<boolean>;
|
|
503
|
+
type ModelFit = {
|
|
504
|
+
/** The model likely fits in the currently-available quota. */
|
|
505
|
+
fits: boolean;
|
|
506
|
+
availableMB: number;
|
|
507
|
+
/** Caching durably would benefit from installing to the Home Screen — true when
|
|
508
|
+
* not installed on iOS, or when the model doesn't fit the current quota. */
|
|
509
|
+
recommendInstall: boolean;
|
|
690
510
|
};
|
|
691
511
|
/**
|
|
692
|
-
*
|
|
693
|
-
*
|
|
694
|
-
*
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
*
|
|
699
|
-
*
|
|
700
|
-
*
|
|
701
|
-
*
|
|
702
|
-
* const { speak, stop, isLoading, isSpeaking, listVoices, setVoice } = useSpeech();
|
|
703
|
-
*
|
|
704
|
-
* // Or use Supertonic (44.1kHz, faster)
|
|
705
|
-
* // const { speak, listVoices } = useSpeech({ model: "supertonic-66m" });
|
|
706
|
-
*
|
|
707
|
-
* if (isLoading) return <div>Loading TTS...</div>;
|
|
708
|
-
*
|
|
709
|
-
* return (
|
|
710
|
-
* <div>
|
|
711
|
-
* <select onChange={e => setVoice(e.target.value)}>
|
|
712
|
-
* {listVoices().map(v => (
|
|
713
|
-
* <option key={v.id} value={v.id}>{v.name}</option>
|
|
714
|
-
* ))}
|
|
715
|
-
* </select>
|
|
716
|
-
* <button onClick={() => speak("Hello world!")}>
|
|
717
|
-
* {isSpeaking ? "Speaking..." : "Speak"}
|
|
718
|
-
* </button>
|
|
719
|
-
* {isSpeaking && <button onClick={stop}>Stop</button>}
|
|
720
|
-
* </div>
|
|
721
|
-
* );
|
|
722
|
-
* }
|
|
723
|
-
* ```
|
|
512
|
+
* Estimate whether a model of `sizeMB` will cache in the current quota, and
|
|
513
|
+
* whether you should recommend installing to the Home Screen first. Pair with a
|
|
514
|
+
* one-time "Install for offline use" prompt before a large download on mobile.
|
|
515
|
+
*/
|
|
516
|
+
declare function canCacheModel(sizeMB: number): Promise<ModelFit>;
|
|
517
|
+
/**
|
|
518
|
+
* Platform-appropriate install guidance. iOS Safari has NO programmatic install
|
|
519
|
+
* prompt — installation is manual (Share → Add to Home Screen), so apps should
|
|
520
|
+
* show these instructions. Other platforms (Android/Chrome) fire
|
|
521
|
+
* `beforeinstallprompt`, which apps can capture for a one-tap button.
|
|
724
522
|
*/
|
|
725
|
-
declare function
|
|
523
|
+
declare function getInstallGuidance(): {
|
|
524
|
+
installed: boolean;
|
|
525
|
+
manual: boolean;
|
|
526
|
+
steps: string;
|
|
527
|
+
};
|
|
528
|
+
//#endregion
|
|
529
|
+
//#region src/browser/audio.d.ts
|
|
726
530
|
/**
|
|
727
531
|
* Play audio from Float32Array using Web Audio API
|
|
728
532
|
*
|
|
@@ -763,247 +567,119 @@ declare function createAudioPlayer(sampleRate?: number): {
|
|
|
763
567
|
stop: () => void;
|
|
764
568
|
isPlaying: () => boolean;
|
|
765
569
|
};
|
|
570
|
+
//#endregion
|
|
571
|
+
//#region src/browser/device-guards.d.ts
|
|
766
572
|
/**
|
|
767
|
-
*
|
|
573
|
+
* Approximate on-device (INT4) memory footprint in MB for the models the native
|
|
574
|
+
* engine actually ships. Used for memory-aware selection and messaging.
|
|
768
575
|
*/
|
|
769
|
-
|
|
770
|
-
status: "downloading" | "loading" | "ready" | "error";
|
|
771
|
-
message?: string;
|
|
772
|
-
progress?: number;
|
|
773
|
-
file?: string;
|
|
774
|
-
};
|
|
576
|
+
declare const MODEL_SIZES: Record<string, number>;
|
|
775
577
|
/**
|
|
776
|
-
*
|
|
578
|
+
* Check if a model is safe to load on the current device.
|
|
579
|
+
* Returns guidance specific to iOS memory constraints. Matches on the real
|
|
580
|
+
* native-engine repo ids (MLX 4-bit / upstream Qwen / Liquid).
|
|
777
581
|
*/
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
/** Callback when model is ready */
|
|
784
|
-
onReady?: () => void;
|
|
785
|
-
/** Callback when transcription completes (or for each chunk in streaming mode) */
|
|
786
|
-
onTranscript?: (text: string) => void;
|
|
787
|
-
/** Callback on error */
|
|
788
|
-
onError?: (error: string) => void;
|
|
789
|
-
/** Callback during loading */
|
|
790
|
-
onProgress?: (progress: STTProgress) => void;
|
|
791
|
-
/** Enable streaming transcription - transcribes audio in chunks as you speak */
|
|
792
|
-
streaming?: boolean;
|
|
793
|
-
/** Chunk duration in ms for streaming mode (default: 3000 = 3 seconds) */
|
|
794
|
-
chunkDuration?: number;
|
|
795
|
-
/** Callback for each streaming chunk with partial transcript */
|
|
796
|
-
onChunk?: (text: string, chunkIndex: number) => void;
|
|
582
|
+
declare function isModelSafeForDevice(modelId: string): {
|
|
583
|
+
safe: boolean;
|
|
584
|
+
reason: string;
|
|
585
|
+
recommendation?: string;
|
|
586
|
+
maxSafeModel?: string;
|
|
797
587
|
};
|
|
798
588
|
/**
|
|
799
|
-
*
|
|
589
|
+
* Get recommended models based on device memory and capabilities.
|
|
590
|
+
* Helps prevent OOM crashes on low-memory mobile devices.
|
|
800
591
|
*/
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
transcript: string;
|
|
820
|
-
/** Current streaming chunk being transcribed (streaming mode only) */
|
|
821
|
-
streamingChunk: string;
|
|
822
|
-
/** Number of chunks transcribed so far (streaming mode only) */
|
|
823
|
-
chunkCount: number;
|
|
824
|
-
/** Loading progress */
|
|
825
|
-
loadingProgress: STTProgress | null;
|
|
826
|
-
/** Error message */
|
|
827
|
-
error: string | null;
|
|
828
|
-
/** Manually load the model */
|
|
829
|
-
load: () => void;
|
|
592
|
+
declare function getRecommendedModels(): {
|
|
593
|
+
chat: string;
|
|
594
|
+
tts: string;
|
|
595
|
+
stt: string;
|
|
596
|
+
embedding: string;
|
|
597
|
+
reason: string;
|
|
598
|
+
deviceMemory: number | null;
|
|
599
|
+
isMobile: boolean;
|
|
600
|
+
};
|
|
601
|
+
type DownloadPhase = "idle" | "downloading" | "caching" | "initializing" | "ready" | "error";
|
|
602
|
+
declare const SESSION_STORAGE_KEY = "gerbil_session_phase";
|
|
603
|
+
type SessionState = {
|
|
604
|
+
phase: DownloadPhase;
|
|
605
|
+
modelId: string | null;
|
|
606
|
+
sessionId: string;
|
|
607
|
+
timestamp: number;
|
|
608
|
+
bytesDownloaded?: number;
|
|
609
|
+
totalBytes?: number;
|
|
830
610
|
};
|
|
831
611
|
/**
|
|
832
|
-
*
|
|
833
|
-
*
|
|
834
|
-
* Uses MediaRecorder to capture audio and Whisper for transcription.
|
|
835
|
-
* Supports both one-shot and streaming transcription modes.
|
|
836
|
-
*
|
|
837
|
-
* @example Basic usage (one-shot)
|
|
838
|
-
* ```tsx
|
|
839
|
-
* function VoiceInput() {
|
|
840
|
-
* const { startRecording, stopRecording, isRecording, transcript } = useVoiceInput({
|
|
841
|
-
* onTranscript: (text) => console.log("User said:", text),
|
|
842
|
-
* });
|
|
843
|
-
*
|
|
844
|
-
* return (
|
|
845
|
-
* <button onClick={isRecording ? stopRecording : startRecording}>
|
|
846
|
-
* {isRecording ? "Stop" : "Record"}
|
|
847
|
-
* </button>
|
|
848
|
-
* );
|
|
849
|
-
* }
|
|
850
|
-
* ```
|
|
851
|
-
*
|
|
852
|
-
* @example Streaming transcription (real-time)
|
|
853
|
-
* ```tsx
|
|
854
|
-
* function LiveTranscription() {
|
|
855
|
-
* const { startRecording, stopRecording, isRecording, transcript, streamingChunk } = useVoiceInput({
|
|
856
|
-
* streaming: true, // Enable streaming mode
|
|
857
|
-
* chunkDuration: 1500, // Transcribe every 1.5 seconds (default)
|
|
858
|
-
* onChunk: (text, idx) => console.log(`Chunk ${idx}: ${text}`),
|
|
859
|
-
* });
|
|
860
|
-
*
|
|
861
|
-
* return (
|
|
862
|
-
* <div>
|
|
863
|
-
* <button onClick={isRecording ? stopRecording : startRecording}>
|
|
864
|
-
* {isRecording ? "Stop" : "Start Live Transcription"}
|
|
865
|
-
* </button>
|
|
866
|
-
* <p>Current chunk: {streamingChunk}</p>
|
|
867
|
-
* <p>Full transcript: {transcript}</p>
|
|
868
|
-
* </div>
|
|
869
|
-
* );
|
|
870
|
-
* }
|
|
871
|
-
* ```
|
|
612
|
+
* Set the current download/initialization phase.
|
|
613
|
+
* Used to detect if a reload happened during a critical operation.
|
|
872
614
|
*/
|
|
873
|
-
declare function
|
|
615
|
+
declare function setDownloadPhase(phase: DownloadPhase, modelId?: string, progress?: {
|
|
616
|
+
bytesDownloaded: number;
|
|
617
|
+
totalBytes: number;
|
|
618
|
+
}): void;
|
|
874
619
|
/**
|
|
875
|
-
*
|
|
620
|
+
* Get the last known download phase from storage.
|
|
876
621
|
*/
|
|
877
|
-
|
|
878
|
-
/** LLM model ID (default: qwen3-0.6b) */
|
|
879
|
-
llmModel?: string;
|
|
880
|
-
/** STT model ID (default: whisper-tiny.en) */
|
|
881
|
-
sttModel?: string;
|
|
882
|
-
/** TTS model ID (default: kokoro-82m, also supports supertonic-66m) */
|
|
883
|
-
ttsModel?: TTSModelId;
|
|
884
|
-
/** System prompt for LLM */
|
|
885
|
-
system?: string;
|
|
886
|
-
/** Enable thinking mode (default: false) */
|
|
887
|
-
thinking?: boolean;
|
|
888
|
-
/** TTS voice ID (default: model's default voice) */
|
|
889
|
-
voice?: string;
|
|
890
|
-
/** TTS speech speed (default: 1.0) */
|
|
891
|
-
speed?: number;
|
|
892
|
-
/** Auto-load all models on mount (default: false) */
|
|
893
|
-
autoLoad?: boolean;
|
|
894
|
-
/** Callback when user speaks */
|
|
895
|
-
onUserSpeak?: (text: string) => void;
|
|
896
|
-
/** Callback when assistant responds */
|
|
897
|
-
onAssistantSpeak?: (text: string) => void;
|
|
898
|
-
/** Callback on error */
|
|
899
|
-
onError?: (error: string) => void;
|
|
900
|
-
};
|
|
622
|
+
declare function getDownloadPhase(): SessionState | null;
|
|
901
623
|
/**
|
|
902
|
-
*
|
|
624
|
+
* Detect if the page reloaded during a model download/initialization.
|
|
625
|
+
* This typically indicates an iOS memory crash.
|
|
626
|
+
*
|
|
627
|
+
* @returns Detection result with recommended action
|
|
903
628
|
*/
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
629
|
+
declare function detectMemoryCrash(): {
|
|
630
|
+
crashed: boolean;
|
|
631
|
+
phase?: DownloadPhase;
|
|
632
|
+
modelId?: string;
|
|
633
|
+
timeSinceCrash?: number;
|
|
634
|
+
recommendation?: string;
|
|
910
635
|
};
|
|
911
636
|
/**
|
|
912
|
-
*
|
|
637
|
+
* Clear session phase (call when model loads successfully).
|
|
913
638
|
*/
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
/** Cancel current operation */
|
|
922
|
-
cancel: () => void;
|
|
923
|
-
/** Clear conversation history */
|
|
924
|
-
clear: () => void;
|
|
925
|
-
/** Whether recording user speech */
|
|
926
|
-
isListening: boolean;
|
|
927
|
-
/** Whether processing (STT/LLM/TTS) */
|
|
928
|
-
isProcessing: boolean;
|
|
929
|
-
/** Whether assistant is speaking */
|
|
930
|
-
isSpeaking: boolean;
|
|
931
|
-
/** Current stage: idle, listening, transcribing, thinking, speaking */
|
|
932
|
-
stage: "idle" | "listening" | "transcribing" | "thinking" | "speaking";
|
|
933
|
-
/** Whether all models are loaded */
|
|
934
|
-
isReady: boolean;
|
|
935
|
-
/** Whether loading models */
|
|
936
|
-
isLoading: boolean;
|
|
937
|
-
/** Loading progress message */
|
|
938
|
-
loadingMessage: string;
|
|
939
|
-
/** Error message */
|
|
940
|
-
error: string | null;
|
|
941
|
-
/** Manually load all models */
|
|
942
|
-
load: () => void;
|
|
943
|
-
};
|
|
639
|
+
declare function clearDownloadPhase(): void;
|
|
640
|
+
//#endregion
|
|
641
|
+
//#region src/browser/download.d.ts
|
|
642
|
+
/** Chunk size for downloads: 1.5MB (safe for iOS IndexedDB transactions) */
|
|
643
|
+
declare const CHUNK_SIZE_BYTES: number;
|
|
644
|
+
/** IndexedDB database name for chunked downloads */
|
|
645
|
+
declare const DOWNLOAD_DB_NAME = "gerbil-model-chunks";
|
|
944
646
|
/**
|
|
945
|
-
*
|
|
946
|
-
*
|
|
947
|
-
* Complete voice-to-voice conversation loop:
|
|
948
|
-
* 1. User presses button to speak
|
|
949
|
-
* 2. Speech is transcribed (Whisper)
|
|
950
|
-
* 3. LLM generates response
|
|
951
|
-
* 4. Response is spoken aloud (Kokoro or Supertonic TTS)
|
|
952
|
-
*
|
|
953
|
-
* @example
|
|
954
|
-
* ```tsx
|
|
955
|
-
* function VoiceChat() {
|
|
956
|
-
* const {
|
|
957
|
-
* messages,
|
|
958
|
-
* startListening,
|
|
959
|
-
* stopListening,
|
|
960
|
-
* isListening,
|
|
961
|
-
* isSpeaking,
|
|
962
|
-
* stage,
|
|
963
|
-
* } = useVoiceChat({
|
|
964
|
-
* system: "You are a helpful voice assistant.",
|
|
965
|
-
* voice: "af_bella",
|
|
966
|
-
* // Or use Supertonic for faster synthesis:
|
|
967
|
-
* // ttsModel: "supertonic-66m",
|
|
968
|
-
* // voice: "F1",
|
|
969
|
-
* });
|
|
970
|
-
*
|
|
971
|
-
* return (
|
|
972
|
-
* <div>
|
|
973
|
-
* {messages.map(m => (
|
|
974
|
-
* <div key={m.id}>{m.role}: {m.content}</div>
|
|
975
|
-
* ))}
|
|
976
|
-
* <button
|
|
977
|
-
* onMouseDown={startListening}
|
|
978
|
-
* onMouseUp={stopListening}
|
|
979
|
-
* >
|
|
980
|
-
* {stage === "idle" ? "🎤 Hold to Speak" : stage}
|
|
981
|
-
* </button>
|
|
982
|
-
* </div>
|
|
983
|
-
* );
|
|
984
|
-
* }
|
|
985
|
-
* ```
|
|
647
|
+
* Chunked resumable downloader for large model files.
|
|
648
|
+
* Downloads in 1.5MB chunks to avoid iOS memory pressure.
|
|
986
649
|
*/
|
|
987
|
-
declare function
|
|
650
|
+
declare function downloadModelChunked(url: string, modelId: string, options?: {
|
|
651
|
+
onProgress?: (info: {
|
|
652
|
+
phase: string;
|
|
653
|
+
bytesDownloaded: number;
|
|
654
|
+
totalBytes: number;
|
|
655
|
+
percent: number;
|
|
656
|
+
}) => void;
|
|
657
|
+
signal?: AbortSignal;
|
|
658
|
+
}): Promise<ArrayBuffer>;
|
|
988
659
|
/**
|
|
989
|
-
* Check if
|
|
660
|
+
* Check if a model has an incomplete download.
|
|
990
661
|
*/
|
|
991
|
-
declare function
|
|
662
|
+
declare function hasIncompleteDownload(modelId: string): Promise<{
|
|
663
|
+
incomplete: boolean;
|
|
664
|
+
bytesDownloaded?: number;
|
|
665
|
+
totalBytes?: number;
|
|
666
|
+
percent?: number;
|
|
667
|
+
}>;
|
|
992
668
|
/**
|
|
993
|
-
*
|
|
669
|
+
* Clear incomplete download data for a model.
|
|
994
670
|
*/
|
|
995
|
-
declare function
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
declare
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
}
|
|
671
|
+
declare function clearIncompleteDownload(modelId: string): Promise<void>;
|
|
672
|
+
/**
|
|
673
|
+
* Check if there's enough storage quota for a model download.
|
|
674
|
+
* Returns estimated available space and whether download should proceed.
|
|
675
|
+
*/
|
|
676
|
+
declare function checkStorageQuota(requiredMB?: number): Promise<{
|
|
677
|
+
ok: boolean;
|
|
678
|
+
availableMB: number;
|
|
679
|
+
usedMB: number;
|
|
680
|
+
quotaMB: number;
|
|
681
|
+
message?: string;
|
|
682
|
+
}>;
|
|
1007
683
|
//#endregion
|
|
1008
|
-
export { AudioChunk, BUILTIN_MODELS,
|
|
684
|
+
export { AudioChunk, BUILTIN_MODELS, CHUNK_SIZE_BYTES, CacheConfig, ConcurrencyConfig, DOWNLOAD_DB_NAME, EmbedOptions, EmbedResult, ErrorContext, FallbackConfig, GenerateEvent, GenerateOptions, GenerateResult, GerbilConfig, GerbilModelSettings, GerbilProviderSettings, ImageInput, JsonOptions, LoadOptions, LoadSTTOptions, LoadTTSOptions, MODEL_SIZES, ModelConfig, type ModelFit, ModelLoadEvent, ModelSource, ModelStats, PreloadOptions, ProgressInfo, SESSION_STORAGE_KEY, STTModelConfig, SearchResult, type SessionState, SessionStats, SimilarityResult, SpeakOptions, SpeakResult, type StorageStatus, StreamingTranscriptionOptions, StreamingTranscriptionSession, SystemInfo, TTSModelConfig, TelemetryConfig, TranscribeOptions, TranscribeResult, TranscribeSegment, VoiceInfo, canCacheModel, checkStorageQuota, clearDownloadPhase, clearIncompleteDownload, createAudioPlayer, detectMemoryCrash, downloadModelChunked, getDownloadPhase, getInstallGuidance, getRecommendedModels, getStorageStatus, hasIncompleteDownload, isIOS, isModelSafeForDevice, isStandalone, playAudio, requestPersistentStorage, setDownloadPhase };
|
|
1009
685
|
//# sourceMappingURL=index.d.ts.map
|