@tryhamster/gerbil 1.1.3 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/dist/{architectures-wan0swXu.mjs → architectures-Ol7yUmKf.mjs} +128 -68
  2. package/dist/architectures-Ol7yUmKf.mjs.map +1 -0
  3. package/dist/cli.mjs +8 -8
  4. package/dist/cli.mjs.map +1 -1
  5. package/dist/{defaults-9komdrbY.mjs → defaults-bJcmOaRG.mjs} +2 -2
  6. package/dist/defaults-bJcmOaRG.mjs.map +1 -0
  7. package/dist/frameworks/express.mjs +1 -1
  8. package/dist/frameworks/fastify.mjs +1 -1
  9. package/dist/frameworks/hono.mjs +1 -1
  10. package/dist/frameworks/next.d.mts +2 -2
  11. package/dist/frameworks/next.mjs +1 -1
  12. package/dist/frameworks/trpc.mjs +1 -1
  13. package/dist/gerbil-0M50i8TK.mjs +4 -0
  14. package/dist/{gerbil-CQspp8fS.mjs → gerbil-DW1VioGN.mjs} +2 -2
  15. package/dist/{gerbil-CQspp8fS.mjs.map → gerbil-DW1VioGN.mjs.map} +1 -1
  16. package/dist/{gerbil-DZbWbIm2.d.mts → gerbil-DkilSf1Q.d.mts} +2 -2
  17. package/dist/{gerbil-DZbWbIm2.d.mts.map → gerbil-DkilSf1Q.d.mts.map} +1 -1
  18. package/dist/gpu/hooks.d.mts +24 -7
  19. package/dist/gpu/hooks.d.mts.map +1 -1
  20. package/dist/gpu/hooks.mjs +14 -7
  21. package/dist/gpu/hooks.mjs.map +1 -1
  22. package/dist/gpu/index.d.mts +2 -2
  23. package/dist/gpu/index.mjs +5 -5
  24. package/dist/{gpu-BYCQ5aTI.mjs → gpu-DR6EG0K-.mjs} +93 -24
  25. package/dist/gpu-DR6EG0K-.mjs.map +1 -0
  26. package/dist/index-Dgmb2kE3.d.mts.map +1 -1
  27. package/dist/{index-CKszv3lt.d.mts → index-HVS7yeLx.d.mts} +232 -133
  28. package/dist/index-HVS7yeLx.d.mts.map +1 -0
  29. package/dist/index.d.mts +2 -2
  30. package/dist/index.mjs +6 -6
  31. package/dist/integrations/ai-sdk.mjs +1 -1
  32. package/dist/integrations/langchain.mjs +1 -1
  33. package/dist/integrations/llamaindex.mjs +1 -1
  34. package/dist/integrations/mcp.d.mts +2 -2
  35. package/dist/integrations/mcp.mjs +4 -4
  36. package/dist/{mcp-CszII8GJ.mjs → mcp-8Tn3U-EE.mjs} +3 -3
  37. package/dist/{mcp-CszII8GJ.mjs.map → mcp-8Tn3U-EE.mjs.map} +1 -1
  38. package/dist/moonshine-stt-B3YtKcEE.mjs +4 -0
  39. package/dist/{moonshine-stt-DDUm5WfP.mjs → moonshine-stt-DSz3VW_0.mjs} +56 -6
  40. package/dist/{moonshine-stt-DDUm5WfP.mjs.map → moonshine-stt-DSz3VW_0.mjs.map} +1 -1
  41. package/dist/{one-liner-DVche8Eg.mjs → one-liner-BK9wqRYw.mjs} +2 -2
  42. package/dist/{one-liner-DVche8Eg.mjs.map → one-liner-BK9wqRYw.mjs.map} +1 -1
  43. package/dist/repl-B62rx3DS.mjs +9 -0
  44. package/dist/skills/index.d.mts +2 -2
  45. package/dist/skills/index.mjs +3 -3
  46. package/dist/{skills-BQI-VSn2.mjs → skills-BF3FVv8_.mjs} +2 -2
  47. package/dist/{skills-BQI-VSn2.mjs.map → skills-BF3FVv8_.mjs.map} +1 -1
  48. package/package.json +1 -1
  49. package/dist/architectures-wan0swXu.mjs.map +0 -1
  50. package/dist/defaults-9komdrbY.mjs.map +0 -1
  51. package/dist/gerbil-tHnYb9nZ.mjs +0 -4
  52. package/dist/gpu-BYCQ5aTI.mjs.map +0 -1
  53. package/dist/index-CKszv3lt.d.mts.map +0 -1
  54. package/dist/moonshine-stt-BtR-KiSP.mjs +0 -4
  55. package/dist/repl-BYJA2U7t.mjs +0 -9
@@ -148,6 +148,66 @@ function createDefaultHFKeyMapper() {
148
148
  };
149
149
  }
150
150
 
151
+ //#endregion
152
+ //#region src/gpu/quantize.ts
153
+ /**
154
+ * On-the-fly INT4 quantization for WebGPU inference.
155
+ *
156
+ * Converts F32 weight matrices to 4-bit unsigned integers with per-group
157
+ * scale/zero-point parameters. Matches the dequantization formula in the
158
+ * MatMulInt4 WGSL kernel:
159
+ *
160
+ * dequant_val = (raw_nibble - zero) * scale
161
+ *
162
+ * Packing: 8 × 4-bit values per u32, little-nibble-first order.
163
+ * Grouping: contiguous elements in row-major (K × N) layout.
164
+ */
165
+ const DEFAULT_GROUP_SIZE = 128;
166
+ /**
167
+ * Quantize a flat F32 weight array to INT4.
168
+ *
169
+ * @param data - Source F32 weight data (row-major, K × N elements)
170
+ * @param groupSize - Number of elements per quantization group (default 128)
171
+ * @returns Packed INT4 data with per-group scales and zeros
172
+ */
173
+ function quantizeInt4(data, groupSize = DEFAULT_GROUP_SIZE) {
174
+ const totalElements = data.length;
175
+ const numGroups = Math.ceil(totalElements / groupSize);
176
+ const packedSize = Math.ceil(totalElements / 8);
177
+ const packed = new Uint32Array(packedSize);
178
+ const scales = new Float32Array(numGroups);
179
+ const zeros = new Float32Array(numGroups);
180
+ for (let g = 0; g < numGroups; g++) {
181
+ const start = g * groupSize;
182
+ const end = Math.min(start + groupSize, totalElements);
183
+ let min = data[start];
184
+ let max = data[start];
185
+ for (let i = start + 1; i < end; i++) {
186
+ const v = data[i];
187
+ if (v < min) min = v;
188
+ if (v > max) max = v;
189
+ }
190
+ const range = max - min;
191
+ const scale = range > 0 ? range / 15 : 1;
192
+ const zero = range > 0 ? -min / scale : 0;
193
+ scales[g] = scale;
194
+ zeros[g] = zero;
195
+ const invRange = range > 0 ? 15 / range : 0;
196
+ for (let i = start; i < end; i++) {
197
+ const q = Math.round((data[i] - min) * invRange);
198
+ const clamped = q < 0 ? 0 : q > 15 ? 15 : q;
199
+ const packedIdx = i >>> 3;
200
+ const nibblePos = i & 7;
201
+ packed[packedIdx] |= clamped << nibblePos * 4;
202
+ }
203
+ }
204
+ return {
205
+ packed,
206
+ scales,
207
+ zeros
208
+ };
209
+ }
210
+
151
211
  //#endregion
152
212
  //#region src/gpu/architectures/kani_tts.ts
153
213
  const KANI_TOKENISER_LENGTH = 64400;
@@ -195,19 +255,23 @@ const NANOCODEC_BASE_CHANNELS = 864;
195
255
  const NANOCODEC_INPUT_DIM = 16;
196
256
  function parseKaniConfig(rawConfig) {
197
257
  const textVocabSize = rawConfig.text_vocab_size ?? KANI_TOKENISER_LENGTH;
258
+ const useLearnableRope = rawConfig.use_learnable_rope ?? false;
259
+ const archList = rawConfig.architectures ?? [];
260
+ const isKaniTTS2 = useLearnableRope || rawConfig.tokens_per_frame != null || rawConfig.audio_step != null || archList.includes("KaniTTS2ForCausalLM");
198
261
  return {
199
262
  textVocabSize,
200
263
  vocabSize: rawConfig.vocab_size,
201
264
  tokensPerFrame: rawConfig.tokens_per_frame ?? KANI_TOKENS_PER_FRAME,
202
265
  audioStep: rawConfig.audio_step ?? 1,
203
- useLearnableRope: rawConfig.use_learnable_rope ?? false,
266
+ useLearnableRope,
204
267
  alphaMin: rawConfig.alpha_min ?? .1,
205
268
  alphaMax: rawConfig.alpha_max ?? 2,
206
269
  speakerEmbDim: rawConfig.speaker_emb_dim ?? 128,
207
270
  audioTokensStart: textVocabSize + 10,
208
271
  startOfSpeech: textVocabSize + 1,
209
272
  endOfSpeech: textVocabSize + 2,
210
- codebookSize: KANI_CODEBOOK_SIZE
273
+ codebookSize: KANI_CODEBOOK_SIZE,
274
+ frameLevelPositions: isKaniTTS2
211
275
  };
212
276
  }
213
277
  /**
@@ -249,6 +313,10 @@ function kaniAttentionLayerIndices(rawConfig) {
249
313
  */
250
314
  function computeKaniPositions(tokenIds, cfg = parseKaniConfig({})) {
251
315
  const pos = new Float32Array(tokenIds.length);
316
+ if (!cfg.frameLevelPositions) {
317
+ for (let t = 0; t < tokenIds.length; t++) pos[t] = t;
318
+ return pos;
319
+ }
252
320
  let textCount = 0;
253
321
  let audioTokenCount = 0;
254
322
  for (let t = 0; t < tokenIds.length; t++) {
@@ -652,15 +720,25 @@ function computeKaniFfnDim(rawConfig) {
652
720
  return ff;
653
721
  }
654
722
  /**
655
- * Generate the KaniTTS2 codec-LM backbone graph (LFM2-350M body, full-vocab logits,
723
+ * Generate the KaniTTS codec-LM backbone graph (LFM2-350M body, full-vocab logits,
656
724
  * per-layer learnable MRoPE). Mirrors generateLfm2Graph block-for-block; the only
657
725
  * difference is that each attention layer rotates Q/K with the MRoPE op fed a
658
726
  * per-layer host cos/sin table instead of the position-counter RoPE op.
659
727
  *
660
- * f32 only (the checkpoint is bf16→f32; q4 would need the codec-LM head re-validated).
728
+ * dtype:
729
+ * • undefined / "f32" — full precision (the checkpoint is bf16/f32 → f32).
730
+ * • "q4" — weight-only group-wise INT4 (W4A16) for the LFM2 linear projections
731
+ * (q/k/v/o, gate/up/down, short-conv in/out_proj) via MatMulInt4. The tied
732
+ * embedding + LM head stay at f32 on purpose: decoder-LM heads are the most
733
+ * quantization-sensitive part of a codec-LM and the embed table is the single
734
+ * buffer shared by both, so quantizing it would degrade audio quality for no
735
+ * load-size win that the int4 projections do not already capture. Backbone
736
+ * drops from ~1.5 GB (f32) to ~0.37 GB. The NanoCodec decoder is a separate
737
+ * graph and always runs f32.
661
738
  */
662
- function generateKaniTtsGraph(rawConfig, dtype, _groupSize, kvDtype) {
663
- if (dtype === "q4") throw new Error("Kani-TTS-2 codec-LM backbone supports f32 only (load without dtype: 'q4').");
739
+ function generateKaniTtsGraph(rawConfig, dtype, groupSize, kvDtype) {
740
+ const useQ4 = dtype === "q4";
741
+ const groupSz = groupSize ?? DEFAULT_GROUP_SIZE;
664
742
  const hidden_size = rawConfig.hidden_size;
665
743
  const num_layers = rawConfig.num_hidden_layers;
666
744
  const num_heads = rawConfig.num_attention_heads;
@@ -711,6 +789,48 @@ function generateKaniTtsGraph(rawConfig, dtype, _groupSize, kvDtype) {
711
789
  executionOrder.push(node.id);
712
790
  };
713
791
  const addLinear = (id, activationInput, weightName, weightShape, outputName, K, N) => {
792
+ if (useQ4) {
793
+ const wQ = `${weightName}.q`;
794
+ const wScales = `${weightName}.scales`;
795
+ const wZeros = `${weightName}.zeros`;
796
+ const totalElements = K * N;
797
+ addTensor({
798
+ name: wQ,
799
+ shape: [Math.ceil(totalElements / 8)],
800
+ dtype: "u32",
801
+ storage: "constant"
802
+ });
803
+ addTensor({
804
+ name: wScales,
805
+ shape: [Math.ceil(totalElements / groupSz)],
806
+ dtype: "f32",
807
+ storage: "constant"
808
+ });
809
+ addTensor({
810
+ name: wZeros,
811
+ shape: [Math.ceil(totalElements / groupSz)],
812
+ dtype: "f32",
813
+ storage: "constant"
814
+ });
815
+ addNode({
816
+ id,
817
+ opType: "MatMulInt4",
818
+ inputs: [
819
+ activationInput,
820
+ wQ,
821
+ wScales,
822
+ wZeros
823
+ ],
824
+ outputs: [outputName],
825
+ attributes: {
826
+ M_tensor: activationInput,
827
+ K,
828
+ N,
829
+ group_size: groupSz
830
+ }
831
+ });
832
+ return;
833
+ }
714
834
  addTensor({
715
835
  name: weightName,
716
836
  shape: weightShape,
@@ -1239,66 +1359,6 @@ function generateKaniTtsGraph(rawConfig, dtype, _groupSize, kvDtype) {
1239
1359
  };
1240
1360
  }
1241
1361
 
1242
- //#endregion
1243
- //#region src/gpu/quantize.ts
1244
- /**
1245
- * On-the-fly INT4 quantization for WebGPU inference.
1246
- *
1247
- * Converts F32 weight matrices to 4-bit unsigned integers with per-group
1248
- * scale/zero-point parameters. Matches the dequantization formula in the
1249
- * MatMulInt4 WGSL kernel:
1250
- *
1251
- * dequant_val = (raw_nibble - zero) * scale
1252
- *
1253
- * Packing: 8 × 4-bit values per u32, little-nibble-first order.
1254
- * Grouping: contiguous elements in row-major (K × N) layout.
1255
- */
1256
- const DEFAULT_GROUP_SIZE = 128;
1257
- /**
1258
- * Quantize a flat F32 weight array to INT4.
1259
- *
1260
- * @param data - Source F32 weight data (row-major, K × N elements)
1261
- * @param groupSize - Number of elements per quantization group (default 128)
1262
- * @returns Packed INT4 data with per-group scales and zeros
1263
- */
1264
- function quantizeInt4(data, groupSize = DEFAULT_GROUP_SIZE) {
1265
- const totalElements = data.length;
1266
- const numGroups = Math.ceil(totalElements / groupSize);
1267
- const packedSize = Math.ceil(totalElements / 8);
1268
- const packed = new Uint32Array(packedSize);
1269
- const scales = new Float32Array(numGroups);
1270
- const zeros = new Float32Array(numGroups);
1271
- for (let g = 0; g < numGroups; g++) {
1272
- const start = g * groupSize;
1273
- const end = Math.min(start + groupSize, totalElements);
1274
- let min = data[start];
1275
- let max = data[start];
1276
- for (let i = start + 1; i < end; i++) {
1277
- const v = data[i];
1278
- if (v < min) min = v;
1279
- if (v > max) max = v;
1280
- }
1281
- const range = max - min;
1282
- const scale = range > 0 ? range / 15 : 1;
1283
- const zero = range > 0 ? -min / scale : 0;
1284
- scales[g] = scale;
1285
- zeros[g] = zero;
1286
- const invRange = range > 0 ? 15 / range : 0;
1287
- for (let i = start; i < end; i++) {
1288
- const q = Math.round((data[i] - min) * invRange);
1289
- const clamped = q < 0 ? 0 : q > 15 ? 15 : q;
1290
- const packedIdx = i >>> 3;
1291
- const nibblePos = i & 7;
1292
- packed[packedIdx] |= clamped << nibblePos * 4;
1293
- }
1294
- }
1295
- return {
1296
- packed,
1297
- scales,
1298
- zeros
1299
- };
1300
- }
1301
-
1302
1362
  //#endregion
1303
1363
  //#region src/gpu/architectures/gemma3_encoder.ts
1304
1364
  function generateGemma3EncoderGraph(rawConfig, dtype, groupSizeOverride, _kvDtype, _embedding) {
@@ -6059,5 +6119,5 @@ function isArchitectureSupported(name) {
6059
6119
  }
6060
6120
 
6061
6121
  //#endregion
6062
- export { parseKaniConfig as C, createDefaultHFKeyMapper as D, GEMMA4_VIS_KEYS as E, nanoCodecWeightMap as S, DTYPE_BYTES as T, generateNanoCodecDecoderGraph as _, generateMoonshineEncoderGraph as a, kaniLayerAlpha as b, DEFAULT_GROUP_SIZE as c, KANI_START_OF_HUMAN as d, audioTokensToCodes as f, generateKaniTtsGraph as g, foldNanoCodecWeightNorm as h, generateMoonshineDecoderGraph as i, quantizeInt4 as l, computeKaniPositions as m, isArchitectureSupported as n, moonshineEncoderFrames as o, buildKaniLayerCosSin as p, MOONSHINE_REMAINING_WORK as r, parseMoonshineConfig as s, generateGraph as t, KANI_END_OF_HUMAN as u, kaniAttentionLayerIndices as v, CANONICAL_KEYS as w, kaniSinTensor as x, kaniCosTensor as y };
6063
- //# sourceMappingURL=architectures-wan0swXu.mjs.map
6122
+ export { quantizeInt4 as C, createDefaultHFKeyMapper as D, GEMMA4_VIS_KEYS as E, DEFAULT_GROUP_SIZE as S, DTYPE_BYTES as T, kaniCosTensor as _, generateMoonshineEncoderGraph as a, nanoCodecWeightMap as b, KANI_END_OF_HUMAN as c, buildKaniLayerCosSin as d, computeKaniPositions as f, kaniAttentionLayerIndices as g, generateNanoCodecDecoderGraph as h, generateMoonshineDecoderGraph as i, KANI_START_OF_HUMAN as l, generateKaniTtsGraph as m, isArchitectureSupported as n, moonshineEncoderFrames as o, foldNanoCodecWeightNorm as p, MOONSHINE_REMAINING_WORK as r, parseMoonshineConfig as s, generateGraph as t, audioTokensToCodes as u, kaniLayerAlpha as v, CANONICAL_KEYS as w, parseKaniConfig as x, kaniSinTensor as y };
6123
+ //# sourceMappingURL=architectures-Ol7yUmKf.mjs.map