@tryhamster/gerbil 1.3.1 → 1.4.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 (67) hide show
  1. package/dist/architectures-Ol7yUmKf.mjs.map +1 -1
  2. package/dist/browser/index.d.ts +7 -1
  3. package/dist/browser/index.d.ts.map +1 -1
  4. package/dist/cli.mjs +7 -7
  5. package/dist/cli.mjs.map +1 -1
  6. package/dist/{defaults-CudhglS1.mjs → defaults-KnrRSIeJ.mjs} +20 -7
  7. package/dist/defaults-KnrRSIeJ.mjs.map +1 -0
  8. package/dist/frameworks/express.d.mts +2 -2
  9. package/dist/frameworks/express.mjs +1 -1
  10. package/dist/frameworks/fastify.d.mts +2 -2
  11. package/dist/frameworks/fastify.mjs +1 -1
  12. package/dist/frameworks/hono.d.mts +2 -2
  13. package/dist/frameworks/hono.mjs +1 -1
  14. package/dist/frameworks/next.d.mts +4 -4
  15. package/dist/frameworks/next.mjs +1 -1
  16. package/dist/frameworks/react.d.mts +2 -2
  17. package/dist/frameworks/trpc.d.mts +2 -2
  18. package/dist/frameworks/trpc.mjs +1 -1
  19. package/dist/gerbil-CUzVDAU7.mjs +4 -0
  20. package/dist/{gerbil-Du-1M2Wq.mjs → gerbil-DGrCwGtJ.mjs} +26 -3
  21. package/dist/{gerbil-Du-1M2Wq.mjs.map → gerbil-DGrCwGtJ.mjs.map} +1 -1
  22. package/dist/{gerbil-4Xid85_Z.d.mts → gerbil-_68_JSGV.d.mts} +15 -4
  23. package/dist/gerbil-_68_JSGV.d.mts.map +1 -0
  24. package/dist/gpu/hooks.d.mts +21 -16
  25. package/dist/gpu/hooks.d.mts.map +1 -1
  26. package/dist/gpu/hooks.mjs +20 -15
  27. package/dist/gpu/hooks.mjs.map +1 -1
  28. package/dist/gpu/index.d.mts +3 -3
  29. package/dist/gpu/index.mjs +4 -4
  30. package/dist/{gpu-BECDib8p.mjs → gpu-DbB321DN.mjs} +1530 -235
  31. package/dist/gpu-DbB321DN.mjs.map +1 -0
  32. package/dist/{index-C4kJrqs1.d.mts → index-BdbeBDTz.d.mts} +210 -9
  33. package/dist/index-BdbeBDTz.d.mts.map +1 -0
  34. package/dist/index.d.mts +4 -4
  35. package/dist/index.mjs +5 -5
  36. package/dist/integrations/ai-sdk.d.mts +2 -2
  37. package/dist/integrations/ai-sdk.mjs +1 -1
  38. package/dist/integrations/langchain.d.mts +2 -2
  39. package/dist/integrations/langchain.mjs +1 -1
  40. package/dist/integrations/llamaindex.d.mts +2 -2
  41. package/dist/integrations/llamaindex.mjs +1 -1
  42. package/dist/integrations/mcp.d.mts +4 -4
  43. package/dist/integrations/mcp.mjs +4 -4
  44. package/dist/{mcp-4imtBQLX.mjs → mcp-DcE3wn-L.mjs} +3 -3
  45. package/dist/{mcp-4imtBQLX.mjs.map → mcp-DcE3wn-L.mjs.map} +1 -1
  46. package/dist/{moonshine-stt-BO5gZ_D6.mjs → moonshine-stt-BGmctcdO.mjs} +555 -7
  47. package/dist/moonshine-stt-BGmctcdO.mjs.map +1 -0
  48. package/dist/moonshine-stt-QoNJeCzR.mjs +4 -0
  49. package/dist/{one-liner-X5vMbWzs.mjs → one-liner-DTGg6zdm.mjs} +2 -2
  50. package/dist/{one-liner-X5vMbWzs.mjs.map → one-liner-DTGg6zdm.mjs.map} +1 -1
  51. package/dist/{outetts-DmR0NfSG.d.mts → outetts-Cr5oGk4z.d.mts} +9 -6
  52. package/dist/{outetts-DmR0NfSG.d.mts.map → outetts-Cr5oGk4z.d.mts.map} +1 -1
  53. package/dist/{repl-CGadrKcY.mjs → repl-Ci0zXCT_.mjs} +3 -3
  54. package/dist/skills/index.d.mts +6 -6
  55. package/dist/skills/index.mjs +3 -3
  56. package/dist/{skills-BFGAXYkm.mjs → skills-Dsf0op66.mjs} +2 -2
  57. package/dist/{skills-BFGAXYkm.mjs.map → skills-Dsf0op66.mjs.map} +1 -1
  58. package/dist/{types-Cpf-aOxX.d.mts → types-CjG36Vzj.d.mts} +9 -3
  59. package/dist/{types-Cpf-aOxX.d.mts.map → types-CjG36Vzj.d.mts.map} +1 -1
  60. package/package.json +1 -1
  61. package/dist/defaults-CudhglS1.mjs.map +0 -1
  62. package/dist/gerbil-4Xid85_Z.d.mts.map +0 -1
  63. package/dist/gerbil-BikD0xFU.mjs +0 -4
  64. package/dist/gpu-BECDib8p.mjs.map +0 -1
  65. package/dist/index-C4kJrqs1.d.mts.map +0 -1
  66. package/dist/moonshine-stt-BO5gZ_D6.mjs.map +0 -1
  67. package/dist/moonshine-stt-fVw-UB4s.mjs +0 -4
@@ -6608,6 +6608,142 @@ const crossAttentionSpec = {
6608
6608
  ]);
6609
6609
  }
6610
6610
  };
6611
+ const t5AttentionSpec = {
6612
+ shaderCode: `\
6613
+ const WG: u32 = 256u;
6614
+ const MAX_S: u32 = 2048u;
6615
+
6616
+ struct Params {
6617
+ S: u32, // sequence length (query == key length)
6618
+ num_heads: u32,
6619
+ head_dim: u32,
6620
+ _pad: u32,
6621
+ }
6622
+
6623
+ @group(0) @binding(0) var<storage, read> Q: array<f32>; // [S, num_heads*head_dim]
6624
+ @group(0) @binding(1) var<storage, read> K: array<f32>; // [S, num_heads*head_dim]
6625
+ @group(0) @binding(2) var<storage, read> V: array<f32>; // [S, num_heads*head_dim]
6626
+ @group(0) @binding(3) var<storage, read> bias: array<f32>; // [num_heads, S, S]
6627
+ @group(0) @binding(4) var<storage, read_write> output: array<f32>; // [S, num_heads*head_dim]
6628
+ @group(0) @binding(5) var<storage, read> params: Params;
6629
+
6630
+ var<workgroup> scores: array<f32, MAX_S>;
6631
+ var<workgroup> red: array<f32, WG>;
6632
+
6633
+ @compute @workgroup_size(256)
6634
+ fn main(
6635
+ @builtin(local_invocation_id) lid: vec3u,
6636
+ @builtin(workgroup_id) wid: vec3u,
6637
+ ) {
6638
+ let q_pos = wid.x;
6639
+ let head = wid.y;
6640
+ if (q_pos >= params.S || head >= params.num_heads) { return; }
6641
+
6642
+ let tid = lid.x;
6643
+ let hd = params.head_dim;
6644
+ let S = params.S;
6645
+ let stride = params.num_heads * hd;
6646
+ let q_base = q_pos * stride + head * hd;
6647
+ let bias_base = (head * S + q_pos) * S;
6648
+
6649
+ // ── Step 1: scores[k] = sum_d Q[q,d]*K[k,d] + bias[head,q,k] (each thread strides over k). ──
6650
+ var k = tid;
6651
+ while (k < S) {
6652
+ let k_base = k * stride + head * hd;
6653
+ var dot: f32 = 0.0;
6654
+ for (var d: u32 = 0u; d < hd; d = d + 1u) {
6655
+ dot = dot + Q[q_base + d] * K[k_base + d];
6656
+ }
6657
+ scores[k] = dot + bias[bias_base + k];
6658
+ k = k + WG;
6659
+ }
6660
+ workgroupBarrier();
6661
+
6662
+ // ── Step 2: row max (parallel reduction over the WG threads' local maxima). ──
6663
+ var local_max: f32 = -1e30;
6664
+ k = tid;
6665
+ while (k < S) {
6666
+ local_max = max(local_max, scores[k]);
6667
+ k = k + WG;
6668
+ }
6669
+ red[tid] = local_max;
6670
+ workgroupBarrier();
6671
+ var stride_r: u32 = WG / 2u;
6672
+ while (stride_r > 0u) {
6673
+ if (tid < stride_r) { red[tid] = max(red[tid], red[tid + stride_r]); }
6674
+ workgroupBarrier();
6675
+ stride_r = stride_r / 2u;
6676
+ }
6677
+ let row_max = red[0];
6678
+ workgroupBarrier();
6679
+
6680
+ // ── Step 3: exponentiate in place, then sum. ──
6681
+ k = tid;
6682
+ while (k < S) {
6683
+ scores[k] = exp(max(scores[k] - row_max, -80.0));
6684
+ k = k + WG;
6685
+ }
6686
+ workgroupBarrier();
6687
+ var local_sum: f32 = 0.0;
6688
+ k = tid;
6689
+ while (k < S) {
6690
+ local_sum = local_sum + scores[k];
6691
+ k = k + WG;
6692
+ }
6693
+ red[tid] = local_sum;
6694
+ workgroupBarrier();
6695
+ stride_r = WG / 2u;
6696
+ while (stride_r > 0u) {
6697
+ if (tid < stride_r) { red[tid] = red[tid] + red[tid + stride_r]; }
6698
+ workgroupBarrier();
6699
+ stride_r = stride_r / 2u;
6700
+ }
6701
+ let inv_sum = 1.0 / max(red[0], 1e-20);
6702
+ workgroupBarrier();
6703
+
6704
+ // ── Step 4: output[q,d] = sum_k softmax(scores)[k] * V[k,d]. Thread tid owns dim
6705
+ // tid (+ WG strides for head_dim > 256). ──
6706
+ var d = tid;
6707
+ while (d < hd) {
6708
+ var acc: f32 = 0.0;
6709
+ for (var kk: u32 = 0u; kk < S; kk = kk + 1u) {
6710
+ acc = acc + scores[kk] * V[kk * stride + head * hd + d];
6711
+ }
6712
+ output[q_base + d] = acc * inv_sum;
6713
+ d = d + WG;
6714
+ }
6715
+ }
6716
+ `,
6717
+ entryPoint: "main",
6718
+ bindings: [
6719
+ { type: "storage-read" },
6720
+ { type: "storage-read" },
6721
+ { type: "storage-read" },
6722
+ { type: "storage-read" },
6723
+ { type: "storage-read-write" },
6724
+ { type: "uniform" }
6725
+ ],
6726
+ getDispatchSize(op, resolvedShapes) {
6727
+ const num_heads = op.attributes.num_heads;
6728
+ const outShape = resolvedShapes[op.outputs[0]];
6729
+ return [
6730
+ outShape ? outShape[0] : op.attributes.S,
6731
+ num_heads,
6732
+ 1
6733
+ ];
6734
+ },
6735
+ buildParams(op, resolvedShapes) {
6736
+ const num_heads = op.attributes.num_heads;
6737
+ const head_dim = op.attributes.head_dim;
6738
+ const outShape = resolvedShapes[op.outputs[0]];
6739
+ return buildUniformBuffer([
6740
+ outShape ? outShape[0] : op.attributes.S,
6741
+ num_heads,
6742
+ head_dim,
6743
+ 0
6744
+ ]);
6745
+ }
6746
+ };
6611
6747
  const KV_CACHE_APPEND_PACKED_F16_SPEC = {
6612
6748
  shaderCode: WGSL_KV_CACHE_APPEND_PACKED_F16,
6613
6749
  entryPoint: "main",
@@ -7918,6 +8054,7 @@ const KERNEL_REGISTRY = {
7918
8054
  RoPE: ropeSpec,
7919
8055
  Attention: attentionSpec,
7920
8056
  CrossAttention: crossAttentionSpec,
8057
+ T5Attention: t5AttentionSpec,
7921
8058
  Softmax: softmaxSpec,
7922
8059
  CausalConv1d: causalConv1dSpec,
7923
8060
  CausalConv1dSiLU: causalConv1dSiluSpec,
@@ -8557,6 +8694,72 @@ var Executor = class Executor {
8557
8694
  return out;
8558
8695
  }
8559
8696
  /**
8697
+ * Autoregressive step for a multi-output decoder graph (e.g. Parler-TTS's 9 codebook
8698
+ * lm_heads). Dispatches the whole graph ONCE at the current seqPos (so the per-layer
8699
+ * KVCacheAppend writes at the right cache row), reads back each named output, then
8700
+ * advances seqPos by `tokens` (default 1, for a prefilled prompt span pass tokens=T).
8701
+ * The caller writes inputs (dec_input_embed + frozen cross-attn K/V) and reset()s
8702
+ * before the first step. Unlike forward(), there is no single "logits" output —
8703
+ * the caller decodes each codebook row itself.
8704
+ */
8705
+ async runGraphStep(outputs, tokens = 1) {
8706
+ const resolvedShapes = this.resolveShapes(tokens);
8707
+ const runtimeContext = { seqPos: this.seqPos };
8708
+ const entries = this.dispatchEntries;
8709
+ const dispatchSizes = new Array(entries.length);
8710
+ for (let i = 0; i < entries.length; i++) {
8711
+ const entry = entries[i];
8712
+ const paramsData = entry.spec.buildParams(entry.node, resolvedShapes, runtimeContext);
8713
+ this.ctx.device.queue.writeBuffer(entry.uniformBuffer, 0, paramsData);
8714
+ dispatchSizes[i] = entry.spec.getDispatchSize(entry.node, resolvedShapes, runtimeContext);
8715
+ }
8716
+ if (this.needsMultiEncoder) {
8717
+ const group = this.webkitGroupSize;
8718
+ for (let start = 0; start < entries.length; start += group) {
8719
+ const enc = this.ctx.device.createCommandEncoder();
8720
+ const end = Math.min(start + group, entries.length);
8721
+ for (let i = start; i < end; i++) {
8722
+ const pass = enc.beginComputePass();
8723
+ pass.setPipeline(entries[i].pipeline);
8724
+ pass.setBindGroup(0, entries[i].bindGroup);
8725
+ pass.dispatchWorkgroups(...dispatchSizes[i]);
8726
+ pass.end();
8727
+ }
8728
+ this.ctx.device.queue.submit([enc.finish()]);
8729
+ await this.ctx.device.queue.onSubmittedWorkDone();
8730
+ }
8731
+ } else {
8732
+ const encoder = this.ctx.device.createCommandEncoder({ label: "runGraphStep" });
8733
+ const pass = encoder.beginComputePass({ label: "step_pass" });
8734
+ for (let i = 0; i < entries.length; i++) {
8735
+ pass.setPipeline(entries[i].pipeline);
8736
+ pass.setBindGroup(0, entries[i].bindGroup);
8737
+ pass.dispatchWorkgroups(...dispatchSizes[i]);
8738
+ }
8739
+ pass.end();
8740
+ this.ctx.device.queue.submit([encoder.finish()]);
8741
+ }
8742
+ const results = [];
8743
+ for (const { name, elemCount } of outputs) {
8744
+ const outBuffer = this.getBuffer(name);
8745
+ if (!outBuffer) throw new Error(`runGraphStep: no GPU buffer for output "${name}".`);
8746
+ const byteLen = Math.min(elemCount * 4, outBuffer.size);
8747
+ const readback = this.ctx.device.createBuffer({
8748
+ size: byteLen,
8749
+ usage: 9
8750
+ });
8751
+ const enc = this.ctx.device.createCommandEncoder();
8752
+ enc.copyBufferToBuffer(outBuffer, 0, readback, 0, byteLen);
8753
+ this.ctx.device.queue.submit([enc.finish()]);
8754
+ await readback.mapAsync(MAP_MODE_READ$1, 0, byteLen);
8755
+ results.push(new Float32Array(readback.getMappedRange(0, byteLen).slice(0)));
8756
+ readback.unmap();
8757
+ readback.destroy();
8758
+ }
8759
+ this.seqPos += tokens;
8760
+ return results;
8761
+ }
8762
+ /**
8560
8763
  * Greedy decode step: forward + GPU argmax. Returns token ID directly.
8561
8764
  * Always uses matvec kernels (M=1). Reads back 4 bytes instead of vocab_size*4.
8562
8765
  */
@@ -10274,6 +10477,8 @@ const UNICODE_TO_BYTE = /* @__PURE__ */ new Map();
10274
10477
  UNICODE_TO_BYTE.set(cs[i], bs[i]);
10275
10478
  }
10276
10479
  }
10480
+ /** SentencePiece metaspace marker (U+2581, "▁") used by T5/Unigram tokenizers. */
10481
+ const METASPACE = "▁";
10277
10482
  var Tokenizer = class Tokenizer {
10278
10483
  vocab;
10279
10484
  vocabReverse;
@@ -10287,9 +10492,11 @@ var Tokenizer = class Tokenizer {
10287
10492
  * raw bytes fall back to <0xHH> tokens. When false, GPT-2 byte-level BPE.
10288
10493
  */
10289
10494
  spmMode;
10495
+ /** Unigram (SentencePiece) model, set only when the tokenizer.json is Unigram. */
10496
+ unigram;
10290
10497
  config;
10291
10498
  vocabSize;
10292
- constructor(vocab, vocabReverse, merges, specialTokens, addedTokens, config, vocabSize, spmMode) {
10499
+ constructor(vocab, vocabReverse, merges, specialTokens, addedTokens, config, vocabSize, spmMode, unigram = null) {
10293
10500
  this.vocab = vocab;
10294
10501
  this.vocabReverse = vocabReverse;
10295
10502
  this.merges = merges;
@@ -10297,6 +10504,7 @@ var Tokenizer = class Tokenizer {
10297
10504
  this.addedTokens = addedTokens;
10298
10505
  this.byteFallback = /* @__PURE__ */ new Map();
10299
10506
  this.spmMode = spmMode;
10507
+ this.unigram = unigram;
10300
10508
  this.config = config;
10301
10509
  this.vocabSize = vocabSize;
10302
10510
  for (let b = 0; b < 256; b++) {
@@ -10309,7 +10517,8 @@ var Tokenizer = class Tokenizer {
10309
10517
  */
10310
10518
  static fromJSON(tokenizerJSON, tokenizerConfigJSON) {
10311
10519
  const model = tokenizerJSON.model;
10312
- if (!model || model.type !== "BPE") throw new Error(`Unsupported tokenizer type: ${model?.type ?? "unknown"}. Only BPE is supported.`);
10520
+ if (model?.type === "Unigram") return Tokenizer.fromUnigramJSON(tokenizerJSON, tokenizerConfigJSON);
10521
+ if (!model || model.type !== "BPE") throw new Error(`Unsupported tokenizer type: ${model?.type ?? "unknown"}. Only BPE and Unigram are supported.`);
10313
10522
  const vocab = /* @__PURE__ */ new Map();
10314
10523
  const vocabReverse = /* @__PURE__ */ new Map();
10315
10524
  for (const [token, id] of Object.entries(model.vocab)) {
@@ -10358,6 +10567,60 @@ var Tokenizer = class Tokenizer {
10358
10567
  }, vocab.size, spmMode);
10359
10568
  }
10360
10569
  /**
10570
+ * Build a Unigram (SentencePiece) tokenizer from a `model.type === "Unigram"`
10571
+ * tokenizer.json (e.g. Flan-T5, which fronts Parler-TTS). The Unigram model is a
10572
+ * list of `[piece, log_score]` rows plus an `unk_id`; encoding runs Viterbi
10573
+ * best-segmentation over the lattice (maximize summed log-scores), normalizing
10574
+ * input NFKC-style + collapsing whitespace, replacing spaces with the metaspace
10575
+ * marker (▁), and appending the post-processor's eos (</s>) like HF's T5Tokenizer.
10576
+ */
10577
+ static fromUnigramJSON(tokenizerJSON, tokenizerConfigJSON) {
10578
+ const model = tokenizerJSON.model;
10579
+ const vocab = /* @__PURE__ */ new Map();
10580
+ const vocabReverse = /* @__PURE__ */ new Map();
10581
+ const pieces = /* @__PURE__ */ new Map();
10582
+ const rawVocab = model.vocab;
10583
+ for (let id = 0; id < rawVocab.length; id++) {
10584
+ const [piece, score] = rawVocab[id];
10585
+ vocab.set(piece, id);
10586
+ vocabReverse.set(id, piece);
10587
+ pieces.set(piece, {
10588
+ id,
10589
+ score
10590
+ });
10591
+ }
10592
+ const specialTokens = /* @__PURE__ */ new Map();
10593
+ const addedTokensMap = /* @__PURE__ */ new Map();
10594
+ const addedTokensList = tokenizerJSON.added_tokens;
10595
+ if (addedTokensList) for (const t of addedTokensList) {
10596
+ vocab.set(t.content, t.id);
10597
+ vocabReverse.set(t.id, t.content);
10598
+ addedTokensMap.set(t.content, t.id);
10599
+ if (t.special) specialTokens.set(t.content, t.id);
10600
+ }
10601
+ const preTok = tokenizerJSON.pre_tokenizer;
10602
+ const prependMetaspace = preTok?.type === "Metaspace" ? (preTok.prepend_scheme ?? "always") !== "never" : true;
10603
+ const eosToken = tokenizerConfigJSON?.eos_token ?? "</s>";
10604
+ const eosId = vocab.get(eosToken) ?? null;
10605
+ const unkId = model.unk_id ?? vocab.get("<unk>") ?? 0;
10606
+ const config = {
10607
+ bosToken: null,
10608
+ eosToken,
10609
+ bosTokenId: null,
10610
+ eosTokenId: eosId,
10611
+ chatTemplate: tokenizerConfigJSON?.chat_template ?? null,
10612
+ addBosToken: false,
10613
+ addEosToken: false
10614
+ };
10615
+ const unigram = {
10616
+ pieces,
10617
+ unkId,
10618
+ prependMetaspace,
10619
+ eosId
10620
+ };
10621
+ return new Tokenizer(vocab, vocabReverse, /* @__PURE__ */ new Map(), specialTokens, addedTokensMap, config, vocab.size, false, unigram);
10622
+ }
10623
+ /**
10361
10624
  * Resolve a literal token string (e.g. "<|endoftext|>") to its vocab id,
10362
10625
  * or null if it isn't in the vocabulary.
10363
10626
  */
@@ -10369,6 +10632,7 @@ var Tokenizer = class Tokenizer {
10369
10632
  */
10370
10633
  encode(text) {
10371
10634
  if (!text) return [];
10635
+ if (this.unigram) return this.encodeUnigram(text);
10372
10636
  const ids = [];
10373
10637
  if (this.config.addBosToken && this.config.bosTokenId !== null) ids.push(this.config.bosTokenId);
10374
10638
  const parts = this.splitOnSpecialTokens(text);
@@ -10396,6 +10660,10 @@ var Tokenizer = class Tokenizer {
10396
10660
  if (skipSpecialTokens && this.specialTokens.has(token)) continue;
10397
10661
  pieces.push(token);
10398
10662
  }
10663
+ if (this.unigram) {
10664
+ const joined = pieces.join("").replace(/▁/g, " ");
10665
+ return joined.startsWith(" ") ? joined.slice(1) : joined;
10666
+ }
10399
10667
  if (this.spmMode) {
10400
10668
  let out = "";
10401
10669
  let byteRun = [];
@@ -10588,7 +10856,127 @@ var Tokenizer = class Tokenizer {
10588
10856
  }
10589
10857
  return ids;
10590
10858
  }
10859
+ /**
10860
+ * Encode text with the Unigram model: split on registered added/special tokens,
10861
+ * normalize each plain span (NFKC + whitespace collapse), apply the metaspace
10862
+ * pre-tokenizer (spaces → ▁, leading ▁ prepended), Viterbi-segment each ▁-word,
10863
+ * then append the post-processor eos. Mirrors HF's T5Tokenizer id stream.
10864
+ */
10865
+ encodeUnigram(text) {
10866
+ const uni = this.unigram;
10867
+ const ids = [];
10868
+ for (const part of this.splitOnSpecialTokens(text)) {
10869
+ if (part.special) {
10870
+ const id = this.addedTokens.get(part.text);
10871
+ if (id !== void 0) ids.push(id);
10872
+ continue;
10873
+ }
10874
+ const normalized = normalizeUnigram(part.text);
10875
+ if (!normalized) continue;
10876
+ const encoded = ((uni.prependMetaspace ? " " : "") + normalized).replace(/ /g, METASPACE).replace(/^▁+/, METASPACE);
10877
+ const words = this.splitMetaspaceWords(encoded);
10878
+ for (const word of words) for (const id of this.viterbiEncode(word)) ids.push(id);
10879
+ }
10880
+ if (uni.eosId !== null) ids.push(uni.eosId);
10881
+ return ids;
10882
+ }
10883
+ /** Split a ▁-encoded string into ▁-prefixed words (keep ▁ with the following run). */
10884
+ splitMetaspaceWords(encoded) {
10885
+ const chars = [...encoded];
10886
+ const words = [];
10887
+ let i = 0;
10888
+ while (i < chars.length) {
10889
+ let j = i + 1;
10890
+ while (j < chars.length && chars[j] !== METASPACE) j++;
10891
+ words.push(chars.slice(i, j).join(""));
10892
+ i = j;
10893
+ }
10894
+ return words;
10895
+ }
10896
+ /**
10897
+ * Viterbi best-segmentation of a single piece over the Unigram vocab: find the
10898
+ * segmentation maximizing the sum of piece log-scores. Characters with no covering
10899
+ * vocab piece fall back to the unk id (SentencePiece treats an unknown character
10900
+ * as a single unk token).
10901
+ */
10902
+ viterbiEncode(word) {
10903
+ const uni = this.unigram;
10904
+ const chars = [...word];
10905
+ const n = chars.length;
10906
+ if (n === 0) return [];
10907
+ const NEG = Number.NEGATIVE_INFINITY;
10908
+ const best = new Float64Array(n + 1).fill(NEG);
10909
+ best[0] = 0;
10910
+ const backLen = new Int32Array(n + 1).fill(0);
10911
+ const backId = new Int32Array(n + 1).fill(uni.unkId);
10912
+ const unkScore = this.unigramUnkScore;
10913
+ for (let end = 1; end <= n; end++) {
10914
+ const maxLen = Math.min(end, this.unigramMaxPieceLen);
10915
+ for (let len = 1; len <= maxLen; len++) {
10916
+ const start = end - len;
10917
+ if (best[start] === NEG) continue;
10918
+ const piece = chars.slice(start, end).join("");
10919
+ const entry = uni.pieces.get(piece);
10920
+ if (entry === void 0) continue;
10921
+ const score = best[start] + entry.score;
10922
+ if (score > best[end]) {
10923
+ best[end] = score;
10924
+ backLen[end] = len;
10925
+ backId[end] = entry.id;
10926
+ }
10927
+ }
10928
+ if (best[end - 1] !== NEG) {
10929
+ const score = best[end - 1] + unkScore;
10930
+ if (score > best[end]) {
10931
+ best[end] = score;
10932
+ backLen[end] = 1;
10933
+ backId[end] = uni.unkId;
10934
+ }
10935
+ }
10936
+ }
10937
+ const out = [];
10938
+ let pos = n;
10939
+ while (pos > 0) {
10940
+ const len = backLen[pos] || 1;
10941
+ out.push(backId[pos]);
10942
+ pos -= len;
10943
+ }
10944
+ out.reverse();
10945
+ return out;
10946
+ }
10947
+ /** Lazily-computed longest vocab piece length (in codepoints). */
10948
+ get unigramMaxPieceLen() {
10949
+ if (this._unigramMaxPieceLen === void 0) {
10950
+ let max = 1;
10951
+ for (const piece of this.unigram.pieces.keys()) {
10952
+ const len = [...piece].length;
10953
+ if (len > max) max = len;
10954
+ }
10955
+ this._unigramMaxPieceLen = max;
10956
+ }
10957
+ return this._unigramMaxPieceLen;
10958
+ }
10959
+ _unigramMaxPieceLen;
10960
+ /** Lazily-computed unk emission score (min vocab score − 10, SentencePiece-style). */
10961
+ get unigramUnkScore() {
10962
+ if (this._unigramUnkScore === void 0) {
10963
+ let min = Number.POSITIVE_INFINITY;
10964
+ for (const { score } of this.unigram.pieces.values()) if (score < min) min = score;
10965
+ this._unigramUnkScore = (Number.isFinite(min) ? min : 0) - 10;
10966
+ }
10967
+ return this._unigramUnkScore;
10968
+ }
10969
+ _unigramUnkScore;
10591
10970
  };
10971
+ /**
10972
+ * Normalize text for the SentencePiece Unigram path: NFKC (matches T5's Precompiled
10973
+ * charsmap on the BMP) followed by whitespace normalization — every run of Unicode
10974
+ * whitespace collapses to a single ASCII space, and leading/trailing single spaces
10975
+ * are preserved (SentencePiece's remove_extra_whitespaces behaviour).
10976
+ */
10977
+ function normalizeUnigram(text) {
10978
+ return text.normalize("NFKC").replace(/\s+/g, " ");
10979
+ }
10592
10980
 
10593
10981
  //#endregion
10594
10982
  //#region src/gpu/vocab-prune.ts
@@ -10970,11 +11358,28 @@ async function initFs() {
10970
11358
  function getCachePath(cacheDir, filename) {
10971
11359
  return _path.join(cacheDir, filename.replace(/\//g, "_"));
10972
11360
  }
11361
+ /** Node's writeSync/readSync cap a single call at 2 GiB − 1; chunk above this. */
11362
+ const FS_CHUNK = 1073741824;
10973
11363
  function readCachedFile(cacheDir, filename) {
10974
11364
  if (!_fs || !_path) return null;
10975
11365
  const p = getCachePath(cacheDir, filename);
10976
11366
  try {
10977
- return _fs.readFileSync(p);
11367
+ const size = _fs.statSync(p).size;
11368
+ if (size <= FS_CHUNK) return _fs.readFileSync(p);
11369
+ const buf = Buffer.allocUnsafe(size);
11370
+ const fd = _fs.openSync(p, "r");
11371
+ try {
11372
+ let offset = 0;
11373
+ while (offset < size) {
11374
+ const len = Math.min(FS_CHUNK, size - offset);
11375
+ const read = _fs.readSync(fd, buf, offset, len, offset);
11376
+ if (read <= 0) break;
11377
+ offset += read;
11378
+ }
11379
+ return offset === size ? buf : null;
11380
+ } finally {
11381
+ _fs.closeSync(fd);
11382
+ }
10978
11383
  } catch {
10979
11384
  return null;
10980
11385
  }
@@ -10985,9 +11390,22 @@ function writeCacheFile(cacheDir, filename, data) {
10985
11390
  const p = getCachePath(cacheDir, filename);
10986
11391
  let buf;
10987
11392
  if (Buffer.isBuffer(data)) buf = data;
10988
- else if (data instanceof Uint8Array) buf = Buffer.from(data);
11393
+ else if (data instanceof Uint8Array) buf = Buffer.from(data.buffer, data.byteOffset, data.byteLength);
10989
11394
  else buf = Buffer.from(data);
10990
- _fs.writeFileSync(p, buf);
11395
+ if (buf.byteLength <= FS_CHUNK) {
11396
+ _fs.writeFileSync(p, buf);
11397
+ return;
11398
+ }
11399
+ const fd = _fs.openSync(p, "w");
11400
+ try {
11401
+ let offset = 0;
11402
+ while (offset < buf.byteLength) {
11403
+ const len = Math.min(FS_CHUNK, buf.byteLength - offset);
11404
+ offset += _fs.writeSync(fd, buf, offset, len, offset);
11405
+ }
11406
+ } finally {
11407
+ _fs.closeSync(fd);
11408
+ }
10991
11409
  }
10992
11410
  const BROWSER_CACHE_NAME = "gerbil-models-v4";
10993
11411
  const TENSOR_CACHE_ENABLED = (typeof process === "undefined" || process.env?.GERBIL_TENSOR_CACHE !== "0") && globalThis.GERBIL_TENSOR_CACHE !== false;
@@ -12306,6 +12724,136 @@ async function loadOuteTTS(options) {
12306
12724
  rawConfig
12307
12725
  };
12308
12726
  }
12727
+ const PARLER_DEFAULT_REPO = "parler-tts/parler-tts-mini-v1";
12728
+ /** Fold a weight-norm conv (g [Cout,1,1] or [Cout,1], v [Cout,...]) → plain weight. */
12729
+ function foldDacWeightNorm(g, v, vShape) {
12730
+ const cout = vShape[0];
12731
+ const inner = v.length / cout;
12732
+ const out = new Float32Array(v.length);
12733
+ for (let o = 0; o < cout; o++) {
12734
+ let norm = 0;
12735
+ const base = o * inner;
12736
+ for (let j = 0; j < inner; j++) {
12737
+ const val = v[base + j];
12738
+ norm += val * val;
12739
+ }
12740
+ norm = Math.sqrt(norm);
12741
+ const scale = norm > 0 ? g[o] / norm : 0;
12742
+ for (let j = 0; j < inner; j++) out[base + j] = v[base + j] * scale;
12743
+ }
12744
+ return out;
12745
+ }
12746
+ /**
12747
+ * Fold the parler `audio_encoder.model.*` DAC tensors into the canonical `dac.*`
12748
+ * decoder weight map (the same shape generateDacSpeechDecoderGraph consumes, with
12749
+ * numCodebooks 9 / rates [8,8,4,2]). Decoder-only (synthesis never runs the encoder).
12750
+ */
12751
+ function buildParlerDacWeights(raw, numCodebooks) {
12752
+ const out = /* @__PURE__ */ new Map();
12753
+ const prefix = "audio_encoder.model.";
12754
+ for (const [key, t] of raw) {
12755
+ if (!key.startsWith(`${prefix}decoder.`)) continue;
12756
+ const sub = key.slice(20);
12757
+ if (sub.endsWith(".weight_v")) {
12758
+ const base = sub.slice(0, -9);
12759
+ const g = raw.get(`${prefix}${base}.weight_g`);
12760
+ if (!g) throw new Error(`Parler DAC: missing weight_g for ${base}`);
12761
+ out.set(`dac.${base}.weight`, {
12762
+ data: foldDacWeightNorm(g.data, t.data, t.shape),
12763
+ shape: t.shape
12764
+ });
12765
+ } else if (sub.endsWith(".weight_g")) {} else if (sub.endsWith(".bias")) out.set(`dac.${sub}`, {
12766
+ data: t.data,
12767
+ shape: t.shape
12768
+ });
12769
+ else if (sub.endsWith(".alpha")) out.set(`dac.${sub}`, {
12770
+ data: t.data,
12771
+ shape: [t.shape[1]]
12772
+ });
12773
+ }
12774
+ const D = 8;
12775
+ let latentDim = 1024;
12776
+ const codebooks = [];
12777
+ const outW = [];
12778
+ const outB = [];
12779
+ for (let c = 0; c < numCodebooks; c++) {
12780
+ const qp = `${prefix}quantizer.quantizers.${c}`;
12781
+ const cb = raw.get(`${qp}.codebook.weight`);
12782
+ const owg = raw.get(`${qp}.out_proj.weight_g`);
12783
+ const owv = raw.get(`${qp}.out_proj.weight_v`);
12784
+ const ob = raw.get(`${qp}.out_proj.bias`);
12785
+ if (!(cb && owg && owv && ob)) throw new Error(`Parler DAC: missing quantizer ${c} tensors`);
12786
+ latentDim = owv.shape[0];
12787
+ codebooks.push(cb.data);
12788
+ outW.push(foldDacWeightNorm(owg.data, owv.data, owv.shape));
12789
+ outB.push(ob.data);
12790
+ }
12791
+ const stack = (arrs) => {
12792
+ const total = arrs.reduce((a, x) => a + x.length, 0);
12793
+ const merged = new Float32Array(total);
12794
+ let off = 0;
12795
+ for (const a of arrs) {
12796
+ merged.set(a, off);
12797
+ off += a.length;
12798
+ }
12799
+ return merged;
12800
+ };
12801
+ out.set("dac.quantizer.codebook", {
12802
+ data: stack(codebooks),
12803
+ shape: [
12804
+ numCodebooks,
12805
+ PARLER_CODEBOOK_SIZE_F,
12806
+ D
12807
+ ]
12808
+ });
12809
+ out.set("dac.quantizer.out_proj.weight", {
12810
+ data: stack(outW),
12811
+ shape: [
12812
+ numCodebooks,
12813
+ latentDim,
12814
+ D
12815
+ ]
12816
+ });
12817
+ out.set("dac.quantizer.out_proj.bias", {
12818
+ data: stack(outB),
12819
+ shape: [numCodebooks, latentDim]
12820
+ });
12821
+ return out;
12822
+ }
12823
+ const PARLER_CODEBOOK_SIZE_F = 1024;
12824
+ async function loadParlerTTS(options) {
12825
+ const revision = options.revision ?? "main";
12826
+ const baseURL = await resolveModelBaseURL(options.repo ?? PARLER_DEFAULT_REPO, revision);
12827
+ await initFs();
12828
+ options.onProgress?.(0, 100, "Fetching config + tokenizer…");
12829
+ const [rawConfig, tokenizerJSON] = await Promise.all([fetchJSON(baseURL, "config.json", options.hfToken, options.cacheDir), fetchJSON(baseURL, "tokenizer.json", options.hfToken, options.cacheDir)]);
12830
+ const tokenizerConfig = await fetchJSON(baseURL, "tokenizer_config.json", options.hfToken, options.cacheDir).catch(() => null);
12831
+ const tokenizer = Tokenizer.fromJSON(tokenizerJSON, tokenizerConfig);
12832
+ options.onProgress?.(8, 100, "Downloading Parler weights…");
12833
+ const buf = await fetchBinary(baseURL, "model.safetensors", options.hfToken, (loaded, total) => options.onProgress?.(8 + loaded / (total || 1) * 85, 100, "weights"), options.cacheDir);
12834
+ const file = parseSafetensorsHeader(buf);
12835
+ const modelWeights = /* @__PURE__ */ new Map();
12836
+ const dacRaw = /* @__PURE__ */ new Map();
12837
+ for (const entry of file.entries) {
12838
+ const f32 = toF32(entry, buf, file);
12839
+ if (entry.name.startsWith("audio_encoder.")) dacRaw.set(entry.name, {
12840
+ data: f32,
12841
+ shape: entry.shape
12842
+ });
12843
+ else modelWeights.set(entry.name, {
12844
+ data: f32,
12845
+ shape: entry.shape
12846
+ });
12847
+ }
12848
+ const codecWeights = buildParlerDacWeights(dacRaw, (rawConfig.decoder ?? {}).num_codebooks ?? 9);
12849
+ options.onProgress?.(100, 100, "Parler-TTS loaded.");
12850
+ return {
12851
+ modelWeights,
12852
+ codecWeights,
12853
+ tokenizer,
12854
+ rawConfig
12855
+ };
12856
+ }
12309
12857
 
12310
12858
  //#endregion
12311
12859
  //#region src/gpu/moonshine-executor.ts
@@ -12671,5 +13219,5 @@ function selectGraphWeights(graph, weights) {
12671
13219
  }
12672
13220
 
12673
13221
  //#endregion
12674
- export { destroyBuffers as _, loadMoonshine as a, verifyGPU as b, quantizeKaniBackbone as c, KERNEL_REGISTRY as d, MATMUL_BIAS_F16C_SPEC as f, createUniformBuffer as g, createStorageBuffer as h, loadModel as i, remapPrunedToken as l, createBindGroup as m, MoonshineEncoderExecutor as n, loadOuteTTS as o, clearPipelineCache as p, loadKaniTTS as r, quantizeBackboneInt4 as s, MoonshineSTT as t, Executor as u, getOrCreatePipeline as v, initGPU as y };
12675
- //# sourceMappingURL=moonshine-stt-BO5gZ_D6.mjs.map
13222
+ export { verifyGPU as S, createStorageBuffer as _, loadMoonshine as a, getOrCreatePipeline as b, quantizeBackboneInt4 as c, Tokenizer as d, Executor as f, createBindGroup as g, clearPipelineCache as h, loadModel as i, quantizeKaniBackbone as l, MATMUL_BIAS_F16C_SPEC as m, MoonshineEncoderExecutor as n, loadOuteTTS as o, KERNEL_REGISTRY as p, loadKaniTTS as r, loadParlerTTS as s, MoonshineSTT as t, remapPrunedToken as u, createUniformBuffer as v, initGPU as x, destroyBuffers as y };
13223
+ //# sourceMappingURL=moonshine-stt-BGmctcdO.mjs.map