@tryhamster/gerbil 1.0.0-rc.12 → 1.0.0-rc.14

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 (62) hide show
  1. package/README.md +24 -0
  2. package/dist/browser/index.d.ts +64 -3
  3. package/dist/browser/index.d.ts.map +1 -1
  4. package/dist/browser/index.js +226 -53
  5. package/dist/browser/index.js.map +1 -1
  6. package/dist/cli.mjs +9 -8
  7. package/dist/cli.mjs.map +1 -1
  8. package/dist/frameworks/express.d.mts +1 -1
  9. package/dist/frameworks/express.mjs +2 -1
  10. package/dist/frameworks/express.mjs.map +1 -1
  11. package/dist/frameworks/fastify.d.mts +1 -1
  12. package/dist/frameworks/fastify.mjs +2 -1
  13. package/dist/frameworks/fastify.mjs.map +1 -1
  14. package/dist/frameworks/hono.d.mts +1 -1
  15. package/dist/frameworks/hono.mjs +2 -1
  16. package/dist/frameworks/hono.mjs.map +1 -1
  17. package/dist/frameworks/next.d.mts +2 -2
  18. package/dist/frameworks/next.mjs +2 -1
  19. package/dist/frameworks/next.mjs.map +1 -1
  20. package/dist/frameworks/react.d.mts +1 -1
  21. package/dist/frameworks/trpc.d.mts +1 -1
  22. package/dist/frameworks/trpc.mjs +2 -1
  23. package/dist/frameworks/trpc.mjs.map +1 -1
  24. package/dist/{gerbil-BcWjCGtM.mjs → gerbil-BZklpDhM.mjs} +207 -1
  25. package/dist/gerbil-BZklpDhM.mjs.map +1 -0
  26. package/dist/gerbil-CAMb_nrK.mjs +5 -0
  27. package/dist/{gerbil-E12cYLNi.d.mts → gerbil-DJygY0sJ.d.mts} +71 -2
  28. package/dist/gerbil-DJygY0sJ.d.mts.map +1 -0
  29. package/dist/index.d.mts +3 -3
  30. package/dist/index.d.mts.map +1 -1
  31. package/dist/index.mjs +2 -2
  32. package/dist/index.mjs.map +1 -1
  33. package/dist/integrations/ai-sdk.d.mts +16 -1
  34. package/dist/integrations/ai-sdk.d.mts.map +1 -1
  35. package/dist/integrations/ai-sdk.mjs +19 -2
  36. package/dist/integrations/ai-sdk.mjs.map +1 -1
  37. package/dist/integrations/langchain.d.mts +1 -1
  38. package/dist/integrations/langchain.mjs +2 -1
  39. package/dist/integrations/langchain.mjs.map +1 -1
  40. package/dist/integrations/llamaindex.d.mts +1 -1
  41. package/dist/integrations/llamaindex.mjs +2 -1
  42. package/dist/integrations/llamaindex.mjs.map +1 -1
  43. package/dist/integrations/mcp.d.mts +2 -2
  44. package/dist/integrations/mcp.mjs +5 -4
  45. package/dist/{mcp-DXqxF7ri.mjs → mcp-ZCC5OR7B.mjs} +3 -3
  46. package/dist/{mcp-DXqxF7ri.mjs.map → mcp-ZCC5OR7B.mjs.map} +1 -1
  47. package/dist/{one-liner-UtQX47IT.mjs → one-liner-mH5SKPvT.mjs} +2 -2
  48. package/dist/{one-liner-UtQX47IT.mjs.map → one-liner-mH5SKPvT.mjs.map} +1 -1
  49. package/dist/{repl-FjIaBVFD.mjs → repl-CSM1IBP1.mjs} +3 -3
  50. package/dist/skills/index.d.mts +2 -2
  51. package/dist/skills/index.mjs +4 -3
  52. package/dist/{skills-BmlseBpJ.mjs → skills-CPB_9YfF.mjs} +2 -2
  53. package/dist/{skills-BmlseBpJ.mjs.map → skills-CPB_9YfF.mjs.map} +1 -1
  54. package/dist/{types-Bgb_89Bh.d.mts → types-evP8RShr.d.mts} +8 -2
  55. package/dist/types-evP8RShr.d.mts.map +1 -0
  56. package/docs/ai-sdk.md +18 -0
  57. package/docs/browser.md +34 -0
  58. package/package.json +1 -1
  59. package/dist/gerbil-BcWjCGtM.mjs.map +0 -1
  60. package/dist/gerbil-CBQkuQ9i.mjs +0 -4
  61. package/dist/gerbil-E12cYLNi.d.mts.map +0 -1
  62. package/dist/types-Bgb_89Bh.d.mts.map +0 -1
package/README.md CHANGED
@@ -69,6 +69,30 @@ npm install @tryhamster/gerbil
69
69
 
70
70
  After global install, use `gerbil` directly instead of `npx @tryhamster/gerbil`.
71
71
 
72
+ ## Model Preloading
73
+
74
+ Download models ahead of time so users don't wait:
75
+
76
+ ```typescript
77
+ import { Gerbil } from "@tryhamster/gerbil";
78
+
79
+ const g = new Gerbil();
80
+
81
+ // Option 1: Preload for later (download only, free memory)
82
+ await g.preloadModel("qwen3-0.6b", {
83
+ onProgress: (p) => console.log(p.status, p.progress),
84
+ });
85
+ // Later: loads from disk cache (fast, no network)
86
+ await g.loadModel("qwen3-0.6b");
87
+
88
+ // Option 2: Preload and keep in memory (instant use)
89
+ await g.preloadModel("qwen3-0.6b", { keepLoaded: true });
90
+ // Instant - no loading needed
91
+ await g.generate("Hello");
92
+ ```
93
+
94
+ Works for all model types: `preloadTTS()`, `preloadSTT()`, `preloadEmbedding()`.
95
+
72
96
  ## Quick Start
73
97
 
74
98
  ```typescript
@@ -1041,8 +1041,8 @@ type UseEmbeddingReturn = {
1041
1041
  findNearest: (embedding: number[], candidates: string[], topK?: number) => Promise<BrowserSearchResult[]>;
1042
1042
  /** Compute cosine similarity between two vectors */
1043
1043
  cosineSimilarity: (a: number[], b: number[]) => number;
1044
- /** Manually load the model */
1045
- load: () => void;
1044
+ /** Manually load the model - returns Promise that resolves when ready */
1045
+ load: () => Promise<void>;
1046
1046
  /** Whether model is loading */
1047
1047
  isLoading: boolean;
1048
1048
  /** Whether model is ready */
@@ -1082,6 +1082,63 @@ type UseEmbeddingReturn = {
1082
1082
  * ```
1083
1083
  */
1084
1084
  declare function useEmbedding(options?: UseEmbeddingOptions): UseEmbeddingReturn;
1085
+ /** Progress callback for preloading */
1086
+ type PreloadProgress = {
1087
+ status: "downloading" | "loading" | "ready" | "error";
1088
+ file?: string;
1089
+ progress?: number;
1090
+ message?: string;
1091
+ };
1092
+ /** Preload options */
1093
+ type PreloadOptions = {
1094
+ onProgress?: (progress: PreloadProgress) => void;
1095
+ };
1096
+ /**
1097
+ * Preload a chat/LLM model (downloads to IndexedDB cache)
1098
+ *
1099
+ * Call this during app initialization to ensure the model is ready
1100
+ * when users need it.
1101
+ *
1102
+ * @example
1103
+ * ```ts
1104
+ * // In your app's initialization
1105
+ * import { preloadChatModel } from "@tryhamster/gerbil/browser";
1106
+ *
1107
+ * await preloadChatModel("qwen3-0.6b", {
1108
+ * onProgress: (p) => console.log(p.status, p.progress),
1109
+ * });
1110
+ *
1111
+ * // Later, useChat will load instantly from cache
1112
+ * ```
1113
+ */
1114
+ declare function preloadChatModel(modelId: string, options?: PreloadOptions): Promise<void>;
1115
+ /**
1116
+ * Preload an embedding model
1117
+ *
1118
+ * @example
1119
+ * ```ts
1120
+ * await preloadEmbeddingModel("Xenova/all-MiniLM-L6-v2");
1121
+ * ```
1122
+ */
1123
+ declare function preloadEmbeddingModel(modelId?: string, options?: PreloadOptions): Promise<void>;
1124
+ /**
1125
+ * Preload a TTS model
1126
+ *
1127
+ * @example
1128
+ * ```ts
1129
+ * await preloadTTSModel("kokoro-82m");
1130
+ * ```
1131
+ */
1132
+ declare function preloadTTSModel(modelId?: TTSModelId, options?: PreloadOptions): Promise<void>;
1133
+ /**
1134
+ * Preload an STT model
1135
+ *
1136
+ * @example
1137
+ * ```ts
1138
+ * await preloadSTTModel("whisper-tiny.en");
1139
+ * ```
1140
+ */
1141
+ declare function preloadSTTModel(modelId?: string, options?: PreloadOptions): Promise<void>;
1085
1142
  /**
1086
1143
  * Check if WebGPU is supported
1087
1144
  */
@@ -1100,7 +1157,11 @@ declare const _default: {
1100
1157
  createGerbilWorker: typeof createGerbilWorker;
1101
1158
  playAudio: typeof playAudio;
1102
1159
  createAudioPlayer: typeof createAudioPlayer;
1160
+ preloadChatModel: typeof preloadChatModel;
1161
+ preloadEmbeddingModel: typeof preloadEmbeddingModel;
1162
+ preloadTTSModel: typeof preloadTTSModel;
1163
+ preloadSTTModel: typeof preloadSTTModel;
1103
1164
  };
1104
1165
  //#endregion
1105
- export { AudioChunk, BUILTIN_MODELS, BrowserEmbedResult, BrowserSearchResult, BrowserVoiceInfo, CacheConfig, CompleteOptions, EmbedOptions, EmbedResult, FallbackConfig, GenerateOptions, GenerateResult, GenerateStreamOptions, GerbilConfig, GerbilModelSettings, GerbilProviderSettings, GerbilWorker, GerbilWorkerOptions, ImageInput, JsonOptions, LoadOptions, LoadSTTOptions, LoadTTSOptions, LoadingProgress, Message, ModelConfig, ModelSource, ModelStats, ProgressInfo, STTModelConfig, STTProgress, SearchResult, SessionStats, SimilarityResult, SpeakOptions, SpeakResult, StreamingTranscriptionOptions, StreamingTranscriptionSession, SystemInfo, TTSModelConfig, TTSModelId, TTSProgress, TranscribeOptions, TranscribeResult, TranscribeSegment, UseChatOptions, UseChatReturn, UseCompletionOptions, UseCompletionReturn, UseEmbeddingOptions, UseEmbeddingReturn, UseSpeechOptions, UseSpeechReturn, UseVoiceChatOptions, UseVoiceChatReturn, UseVoiceInputOptions, UseVoiceInputReturn, VoiceChatMessage, VoiceInfo, WorkerComplete, WorkerProgress, WorkerToken, createAudioPlayer, createGerbilWorker, _default as default, getWebGPUInfo, isWebGPUSupported, playAudio, useChat, useCompletion, useEmbedding, useSpeech, useVoiceChat, useVoiceInput };
1166
+ export { AudioChunk, BUILTIN_MODELS, BrowserEmbedResult, BrowserSearchResult, BrowserVoiceInfo, CacheConfig, CompleteOptions, EmbedOptions, EmbedResult, FallbackConfig, GenerateOptions, GenerateResult, GenerateStreamOptions, GerbilConfig, GerbilModelSettings, GerbilProviderSettings, GerbilWorker, GerbilWorkerOptions, ImageInput, JsonOptions, LoadOptions, LoadSTTOptions, LoadTTSOptions, LoadingProgress, Message, ModelConfig, ModelSource, ModelStats, PreloadOptions, PreloadProgress, ProgressInfo, STTModelConfig, STTProgress, SearchResult, SessionStats, SimilarityResult, SpeakOptions, SpeakResult, StreamingTranscriptionOptions, StreamingTranscriptionSession, SystemInfo, TTSModelConfig, TTSModelId, TTSProgress, TranscribeOptions, TranscribeResult, TranscribeSegment, UseChatOptions, UseChatReturn, UseCompletionOptions, UseCompletionReturn, UseEmbeddingOptions, UseEmbeddingReturn, UseSpeechOptions, UseSpeechReturn, UseVoiceChatOptions, UseVoiceChatReturn, UseVoiceInputOptions, UseVoiceInputReturn, VoiceChatMessage, VoiceInfo, WorkerComplete, WorkerProgress, WorkerToken, createAudioPlayer, createGerbilWorker, _default as default, getWebGPUInfo, isWebGPUSupported, playAudio, preloadChatModel, preloadEmbeddingModel, preloadSTTModel, preloadTTSModel, useChat, useCompletion, useEmbedding, useSpeech, useVoiceChat, useVoiceInput };
1106
1167
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/core/types.ts","../../src/core/models.ts","../../src/browser/index.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/core/types.ts","../../src/core/models.ts","../../src/browser/index.ts"],"sourcesContent":[],"mappings":"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"}
@@ -1878,7 +1878,7 @@ function useVoiceInput(options = {}) {
1878
1878
  const fullTranscriptRef = useRef("");
1879
1879
  const transcribeResolveRef = useRef(null);
1880
1880
  const transcribeRejectRef = useRef(null);
1881
- const resolveSTTModel = (modelId) => {
1881
+ const resolveSTTModel$1 = (modelId) => {
1882
1882
  return {
1883
1883
  "whisper-tiny": "onnx-community/whisper-tiny",
1884
1884
  "whisper-tiny.en": "onnx-community/whisper-tiny.en",
@@ -1969,7 +1969,7 @@ function useVoiceInput(options = {}) {
1969
1969
  };
1970
1970
  worker.postMessage({
1971
1971
  type: "load",
1972
- payload: { model: resolveSTTModel(model) }
1972
+ payload: { model: resolveSTTModel$1(model) }
1973
1973
  });
1974
1974
  return () => {
1975
1975
  mountedRef.current = false;
@@ -2348,7 +2348,7 @@ function useVoiceChat(options = {}) {
2348
2348
  const isListening = stage === "listening";
2349
2349
  const isProcessing = stage === "transcribing" || stage === "thinking";
2350
2350
  const isSpeaking = stage === "speaking";
2351
- const resolveSTTModel = (modelId) => {
2351
+ const resolveSTTModel$1 = (modelId) => {
2352
2352
  return {
2353
2353
  "whisper-tiny": "onnx-community/whisper-tiny",
2354
2354
  "whisper-tiny.en": "onnx-community/whisper-tiny.en",
@@ -2381,7 +2381,7 @@ function useVoiceChat(options = {}) {
2381
2381
  sttWorker.onerror = (e) => reject(new Error(e.message));
2382
2382
  sttWorker.postMessage({
2383
2383
  type: "load",
2384
- payload: { model: resolveSTTModel(sttModel) }
2384
+ payload: { model: resolveSTTModel$1(sttModel) }
2385
2385
  });
2386
2386
  });
2387
2387
  if (cancelled || !mountedRef.current) {
@@ -2831,7 +2831,8 @@ function useEmbedding(options = {}) {
2831
2831
  const [loadingProgress, setLoadingProgress] = useState(null);
2832
2832
  const workerRef = useRef(null);
2833
2833
  const loadRequestedRef = useRef(false);
2834
- const pendingRequestsRef = useRef(/* @__PURE__ */ new Map());
2834
+ const readyPromiseRef = useRef(null);
2835
+ const readyResolveRef = useRef(null);
2835
2836
  const cosineSimilarity = useCallback((a, b) => {
2836
2837
  if (a.length !== b.length) throw new Error(`Vector dimensions must match: ${a.length} vs ${b.length}`);
2837
2838
  let dotProduct = 0;
@@ -2847,13 +2848,17 @@ function useEmbedding(options = {}) {
2847
2848
  return dotProduct / magnitude;
2848
2849
  }, []);
2849
2850
  const load = useCallback(() => {
2850
- if (loadRequestedRef.current || isReady) return;
2851
+ if (isReady && workerRef.current) return Promise.resolve();
2852
+ if (loadRequestedRef.current && readyPromiseRef.current) return readyPromiseRef.current;
2851
2853
  loadRequestedRef.current = true;
2852
2854
  setIsLoading(true);
2853
2855
  setLoadingProgress({
2854
2856
  status: "loading",
2855
2857
  message: "Loading embedding model..."
2856
2858
  });
2859
+ readyPromiseRef.current = new Promise((resolve) => {
2860
+ readyResolveRef.current = resolve;
2861
+ });
2857
2862
  const worker = createEmbeddingWorker();
2858
2863
  workerRef.current = worker;
2859
2864
  worker.onmessage = (e) => {
@@ -2868,23 +2873,19 @@ function useEmbedding(options = {}) {
2868
2873
  setIsLoading(false);
2869
2874
  setIsReady(true);
2870
2875
  setLoadingProgress({ status: "ready" });
2876
+ readyResolveRef.current?.();
2871
2877
  onReady?.();
2872
2878
  } else if (type === "error") {
2873
2879
  setIsLoading(false);
2874
2880
  setError(payload);
2875
2881
  onError?.(payload);
2876
- } else if (type === "embedding" || type === "embeddings") {
2877
- const pending = pendingRequestsRef.current.get(type);
2878
- if (pending) {
2879
- pending.resolve(payload);
2880
- pendingRequestsRef.current.delete(type);
2881
- }
2882
2882
  }
2883
2883
  };
2884
2884
  worker.postMessage({
2885
2885
  type: "load",
2886
2886
  payload: { model }
2887
2887
  });
2888
+ return readyPromiseRef.current;
2888
2889
  }, [
2889
2890
  model,
2890
2891
  isReady,
@@ -2901,33 +2902,26 @@ function useEmbedding(options = {}) {
2901
2902
  };
2902
2903
  }, [autoLoad, load]);
2903
2904
  const embed = useCallback(async (text) => {
2904
- if (!isReady) {
2905
- load();
2906
- await new Promise((resolve) => {
2907
- const checkReady = setInterval(() => {
2908
- if (workerRef.current) {
2909
- const handler = (e) => {
2910
- if (e.data.type === "ready") {
2911
- clearInterval(checkReady);
2912
- resolve();
2913
- }
2914
- };
2915
- workerRef.current.addEventListener("message", handler, { once: true });
2916
- }
2917
- }, 100);
2918
- });
2919
- }
2905
+ const loadPromise = load();
2906
+ if (readyPromiseRef.current) await readyPromiseRef.current;
2907
+ else await loadPromise;
2920
2908
  return new Promise((resolve, reject) => {
2921
2909
  const worker = workerRef.current;
2922
2910
  if (!worker) {
2923
- reject(/* @__PURE__ */ new Error("Worker not initialized"));
2911
+ reject(/* @__PURE__ */ new Error("Worker not initialized. Call load() first."));
2924
2912
  return;
2925
2913
  }
2914
+ const timeout = setTimeout(() => {
2915
+ worker.removeEventListener("message", handler);
2916
+ reject(/* @__PURE__ */ new Error("Embedding timeout after 30s"));
2917
+ }, 3e4);
2926
2918
  const handler = (e) => {
2927
2919
  if (e.data.type === "embedding") {
2920
+ clearTimeout(timeout);
2928
2921
  worker.removeEventListener("message", handler);
2929
2922
  resolve(e.data.payload.vector);
2930
2923
  } else if (e.data.type === "error") {
2924
+ clearTimeout(timeout);
2931
2925
  worker.removeEventListener("message", handler);
2932
2926
  reject(new Error(e.data.payload));
2933
2927
  }
@@ -2941,34 +2935,28 @@ function useEmbedding(options = {}) {
2941
2935
  }
2942
2936
  });
2943
2937
  });
2944
- }, [
2945
- isReady,
2946
- load,
2947
- normalize
2948
- ]);
2938
+ }, [load, normalize]);
2949
2939
  const embedBatch = useCallback(async (texts) => {
2950
- if (!isReady) {
2951
- load();
2952
- await new Promise((resolve) => {
2953
- const check = setInterval(() => {
2954
- if (isReady) {
2955
- clearInterval(check);
2956
- resolve();
2957
- }
2958
- }, 100);
2959
- });
2960
- }
2940
+ const loadPromise = load();
2941
+ if (readyPromiseRef.current) await readyPromiseRef.current;
2942
+ else await loadPromise;
2961
2943
  return new Promise((resolve, reject) => {
2962
2944
  const worker = workerRef.current;
2963
2945
  if (!worker) {
2964
- reject(/* @__PURE__ */ new Error("Worker not initialized"));
2946
+ reject(/* @__PURE__ */ new Error("Worker not initialized. Call load() first."));
2965
2947
  return;
2966
2948
  }
2949
+ const timeout = setTimeout(() => {
2950
+ worker.removeEventListener("message", handler);
2951
+ reject(/* @__PURE__ */ new Error("Batch embedding timeout after 60s"));
2952
+ }, 6e4);
2967
2953
  const handler = (e) => {
2968
2954
  if (e.data.type === "embeddings") {
2955
+ clearTimeout(timeout);
2969
2956
  worker.removeEventListener("message", handler);
2970
2957
  resolve(e.data.payload);
2971
2958
  } else if (e.data.type === "error") {
2959
+ clearTimeout(timeout);
2972
2960
  worker.removeEventListener("message", handler);
2973
2961
  reject(new Error(e.data.payload));
2974
2962
  }
@@ -2982,11 +2970,7 @@ function useEmbedding(options = {}) {
2982
2970
  }
2983
2971
  });
2984
2972
  });
2985
- }, [
2986
- isReady,
2987
- load,
2988
- normalize
2989
- ]);
2973
+ }, [load, normalize]);
2990
2974
  return {
2991
2975
  embed,
2992
2976
  embedBatch,
@@ -3026,6 +3010,191 @@ function useEmbedding(options = {}) {
3026
3010
  };
3027
3011
  }
3028
3012
  /**
3013
+ * Preload a chat/LLM model (downloads to IndexedDB cache)
3014
+ *
3015
+ * Call this during app initialization to ensure the model is ready
3016
+ * when users need it.
3017
+ *
3018
+ * @example
3019
+ * ```ts
3020
+ * // In your app's initialization
3021
+ * import { preloadChatModel } from "@tryhamster/gerbil/browser";
3022
+ *
3023
+ * await preloadChatModel("qwen3-0.6b", {
3024
+ * onProgress: (p) => console.log(p.status, p.progress),
3025
+ * });
3026
+ *
3027
+ * // Later, useChat will load instantly from cache
3028
+ * ```
3029
+ */
3030
+ async function preloadChatModel(modelId, options = {}) {
3031
+ const { onProgress } = options;
3032
+ const worker = await createGerbilWorker({
3033
+ modelId,
3034
+ onProgress: (p) => {
3035
+ if (p.status === "downloading") onProgress?.({
3036
+ status: "downloading",
3037
+ file: p.file,
3038
+ progress: p.progress
3039
+ });
3040
+ else onProgress?.({
3041
+ status: "loading",
3042
+ message: p.status
3043
+ });
3044
+ }
3045
+ });
3046
+ onProgress?.({ status: "ready" });
3047
+ worker.terminate();
3048
+ }
3049
+ /**
3050
+ * Preload an embedding model
3051
+ *
3052
+ * @example
3053
+ * ```ts
3054
+ * await preloadEmbeddingModel("Xenova/all-MiniLM-L6-v2");
3055
+ * ```
3056
+ */
3057
+ async function preloadEmbeddingModel(modelId = "Xenova/all-MiniLM-L6-v2", options = {}) {
3058
+ const { onProgress } = options;
3059
+ return new Promise((resolve, reject) => {
3060
+ const worker = createEmbeddingWorker();
3061
+ worker.onmessage = (e) => {
3062
+ const { type, payload } = e.data;
3063
+ if (type === "progress") {
3064
+ if (payload.status === "progress" && payload.file) onProgress?.({
3065
+ status: "downloading",
3066
+ file: payload.file,
3067
+ progress: Math.round(payload.loaded / payload.total * 100)
3068
+ });
3069
+ } else if (type === "ready") {
3070
+ onProgress?.({ status: "ready" });
3071
+ worker.terminate();
3072
+ resolve();
3073
+ } else if (type === "error") {
3074
+ onProgress?.({
3075
+ status: "error",
3076
+ message: payload
3077
+ });
3078
+ worker.terminate();
3079
+ reject(new Error(payload));
3080
+ }
3081
+ };
3082
+ onProgress?.({
3083
+ status: "loading",
3084
+ message: `Loading ${modelId}...`
3085
+ });
3086
+ worker.postMessage({
3087
+ type: "load",
3088
+ payload: { model: modelId }
3089
+ });
3090
+ });
3091
+ }
3092
+ /**
3093
+ * Preload a TTS model
3094
+ *
3095
+ * @example
3096
+ * ```ts
3097
+ * await preloadTTSModel("kokoro-82m");
3098
+ * ```
3099
+ */
3100
+ async function preloadTTSModel(modelId = "kokoro-82m", options = {}) {
3101
+ const { onProgress } = options;
3102
+ const modelConfig = TTS_MODELS[modelId];
3103
+ if (!modelConfig) throw new Error(`Unknown TTS model: ${modelId}`);
3104
+ return new Promise((resolve, reject) => {
3105
+ const worker = createTTSWorker();
3106
+ worker.onmessage = (e) => {
3107
+ const { type, payload } = e.data;
3108
+ if (type === "progress") {
3109
+ if (payload.status === "progress" && payload.file) onProgress?.({
3110
+ status: "downloading",
3111
+ file: payload.file,
3112
+ progress: Math.round(payload.loaded / payload.total * 100)
3113
+ });
3114
+ } else if (type === "ready") {
3115
+ onProgress?.({ status: "ready" });
3116
+ worker.terminate();
3117
+ resolve();
3118
+ } else if (type === "error") {
3119
+ onProgress?.({
3120
+ status: "error",
3121
+ message: payload
3122
+ });
3123
+ worker.terminate();
3124
+ reject(new Error(payload));
3125
+ }
3126
+ };
3127
+ onProgress?.({
3128
+ status: "loading",
3129
+ message: `Loading ${modelId}...`
3130
+ });
3131
+ worker.postMessage({
3132
+ type: "load",
3133
+ payload: {
3134
+ modelId,
3135
+ repo: modelConfig.repo,
3136
+ voices: modelConfig.voices
3137
+ }
3138
+ });
3139
+ });
3140
+ }
3141
+ /**
3142
+ * Preload an STT model
3143
+ *
3144
+ * @example
3145
+ * ```ts
3146
+ * await preloadSTTModel("whisper-tiny.en");
3147
+ * ```
3148
+ */
3149
+ async function preloadSTTModel(modelId = "whisper-tiny.en", options = {}) {
3150
+ const { onProgress } = options;
3151
+ const resolved = resolveSTTModel(modelId);
3152
+ return new Promise((resolve, reject) => {
3153
+ const worker = createSTTWorker();
3154
+ worker.onmessage = (e) => {
3155
+ const { type, payload } = e.data;
3156
+ if (type === "progress") {
3157
+ if (payload.status === "progress" && payload.file) onProgress?.({
3158
+ status: "downloading",
3159
+ file: payload.file,
3160
+ progress: Math.round(payload.loaded / payload.total * 100)
3161
+ });
3162
+ } else if (type === "ready") {
3163
+ onProgress?.({ status: "ready" });
3164
+ worker.terminate();
3165
+ resolve();
3166
+ } else if (type === "error") {
3167
+ onProgress?.({
3168
+ status: "error",
3169
+ message: payload
3170
+ });
3171
+ worker.terminate();
3172
+ reject(new Error(payload));
3173
+ }
3174
+ };
3175
+ onProgress?.({
3176
+ status: "loading",
3177
+ message: `Loading ${modelId}...`
3178
+ });
3179
+ worker.postMessage({
3180
+ type: "load",
3181
+ payload: { model: resolved }
3182
+ });
3183
+ });
3184
+ }
3185
+ /** Helper to resolve STT model ID to repo */
3186
+ function resolveSTTModel(modelId) {
3187
+ return {
3188
+ "whisper-tiny": "onnx-community/whisper-tiny",
3189
+ "whisper-tiny.en": "onnx-community/whisper-tiny.en",
3190
+ "whisper-base": "onnx-community/whisper-base",
3191
+ "whisper-base.en": "onnx-community/whisper-base.en",
3192
+ "whisper-small": "onnx-community/whisper-small",
3193
+ "whisper-small.en": "onnx-community/whisper-small.en",
3194
+ "whisper-large-v3-turbo": "onnx-community/whisper-large-v3-turbo"
3195
+ }[modelId] || modelId;
3196
+ }
3197
+ /**
3029
3198
  * Check if WebGPU is supported
3030
3199
  */
3031
3200
  function isWebGPUSupported() {
@@ -3055,9 +3224,13 @@ var browser_default = {
3055
3224
  getWebGPUInfo,
3056
3225
  createGerbilWorker,
3057
3226
  playAudio,
3058
- createAudioPlayer
3227
+ createAudioPlayer,
3228
+ preloadChatModel,
3229
+ preloadEmbeddingModel,
3230
+ preloadTTSModel,
3231
+ preloadSTTModel
3059
3232
  };
3060
3233
 
3061
3234
  //#endregion
3062
- export { BUILTIN_MODELS, createAudioPlayer, createGerbilWorker, browser_default as default, getWebGPUInfo, isWebGPUSupported, playAudio, useChat, useCompletion, useEmbedding, useSpeech, useVoiceChat, useVoiceInput };
3235
+ export { BUILTIN_MODELS, createAudioPlayer, createGerbilWorker, browser_default as default, getWebGPUInfo, isWebGPUSupported, playAudio, preloadChatModel, preloadEmbeddingModel, preloadSTTModel, preloadTTSModel, useChat, useCompletion, useEmbedding, useSpeech, useVoiceChat, useVoiceInput };
3063
3236
  //# sourceMappingURL=index.js.map