emilstabil commited on
Commit
152ad77
·
verified ·
1 Parent(s): 1c7293d

Deploy Ekko v1 Tiny + PnC browser demo

Browse files
Files changed (2) hide show
  1. app.js +1 -1
  2. pnc-worker.js +21 -10
app.js CHANGED
@@ -92,7 +92,7 @@ const state = {
92
  };
93
 
94
  const worker = new Worker(signedAsset("worker.js?v=20260927-2"));
95
- const pncWorker = new Worker(signedAsset("pnc-worker.js?v=20260927-2"));
96
 
97
  function setStatus(text, detail = "", kind = "loading") {
98
  elements.statusText.textContent = text;
 
92
  };
93
 
94
  const worker = new Worker(signedAsset("worker.js?v=20260927-2"));
95
+ const pncWorker = new Worker(signedAsset("pnc-worker.js?v=20261001-1"));
96
 
97
  function setStatus(text, detail = "", kind = "loading") {
98
  elements.statusText.textContent = text;
pnc-worker.js CHANGED
@@ -21,8 +21,8 @@ let initialization = null;
21
  let session = null;
22
  let vocabulary = null;
23
  let labels = null;
24
- let maximumLength = 256;
25
- const INFERENCE_WINDOW_TOKENS = 192;
26
  let pendingRequest = null;
27
  let processing = false;
28
 
@@ -101,7 +101,7 @@ async function initialize(configUrl) {
101
  vocabulary = tokenizer.model.vocab;
102
  labels = modelConfig.id2label;
103
  // Shorter context restores sentence stops in long, continuous dictation.
104
- maximumLength = Math.min(config.maxLength || 256, INFERENCE_WINDOW_TOKENS);
105
  session = await ort.InferenceSession.create(downloaded.get("pnc.int8.onnx"), {
106
  executionProviders: ["wasm"],
107
  graphOptimizationLevel: "all",
@@ -172,16 +172,26 @@ function encodeWords(words) {
172
  return {identifiers, wordIds};
173
  }
174
 
175
- function encodedLength(words) {
176
- return encodeWords(words).identifiers.length;
 
 
 
 
 
 
 
 
 
177
  }
178
 
179
- function maximumWindowEnd(words, start) {
 
180
  let low = start + 1;
181
  let high = Math.min(words.length, start + maximumLength);
182
  while (low < high) {
183
  const middle = Math.floor((low + high + 1) / 2);
184
- if (encodedLength(words.slice(start, middle)) <= maximumLength) {
185
  low = middle;
186
  } else {
187
  high = middle - 1;
@@ -253,15 +263,16 @@ async function predictWindow(words) {
253
 
254
  async function punctuateWords(words) {
255
  if (!words.length) return [];
 
256
  const output = [];
257
  let nextWord = 0;
258
- const overlapWords = 24;
259
  while (nextWord < words.length) {
260
  let contextStart = Math.max(0, nextWord - overlapWords);
261
- let windowEnd = maximumWindowEnd(words, contextStart);
262
  if (windowEnd <= nextWord) {
263
  contextStart = nextWord;
264
- windowEnd = maximumWindowEnd(words, contextStart);
265
  }
266
  const rendered = await predictWindow(words.slice(contextStart, windowEnd));
267
  const emitEnd = windowEnd === words.length
 
21
  let session = null;
22
  let vocabulary = null;
23
  let labels = null;
24
+ let maximumLength = 128;
25
+ const INFERENCE_WINDOW_TOKENS = 128;
26
  let pendingRequest = null;
27
  let processing = false;
28
 
 
101
  vocabulary = tokenizer.model.vocab;
102
  labels = modelConfig.id2label;
103
  // Shorter context restores sentence stops in long, continuous dictation.
104
+ maximumLength = Math.min(config.maxLength || 128, INFERENCE_WINDOW_TOKENS);
105
  session = await ort.InferenceSession.create(downloaded.get("pnc.int8.onnx"), {
106
  executionProviders: ["wasm"],
107
  graphOptimizationLevel: "all",
 
172
  return {identifiers, wordIds};
173
  }
174
 
175
+ function windowTokenIndex(words) {
176
+ const {wordIds} = encodeWords(words);
177
+ const counts = new Array(words.length).fill(0);
178
+ let specialTokens = 0;
179
+ for (const wordId of wordIds) {
180
+ if (wordId === null) specialTokens += 1;
181
+ else counts[wordId] += 1;
182
+ }
183
+ const prefix = [0];
184
+ for (const count of counts) prefix.push(prefix.at(-1) + count);
185
+ return {prefix, specialTokens};
186
  }
187
 
188
+ function maximumWindowEnd(words, start, prefix, specialTokens) {
189
+ const tokenBudget = prefix[start] + maximumLength - specialTokens;
190
  let low = start + 1;
191
  let high = Math.min(words.length, start + maximumLength);
192
  while (low < high) {
193
  const middle = Math.floor((low + high + 1) / 2);
194
+ if (prefix[middle] <= tokenBudget) {
195
  low = middle;
196
  } else {
197
  high = middle - 1;
 
263
 
264
  async function punctuateWords(words) {
265
  if (!words.length) return [];
266
+ const {prefix, specialTokens} = windowTokenIndex(words);
267
  const output = [];
268
  let nextWord = 0;
269
+ const overlapWords = 12;
270
  while (nextWord < words.length) {
271
  let contextStart = Math.max(0, nextWord - overlapWords);
272
+ let windowEnd = maximumWindowEnd(words, contextStart, prefix, specialTokens);
273
  if (windowEnd <= nextWord) {
274
  contextStart = nextWord;
275
+ windowEnd = maximumWindowEnd(words, contextStart, prefix, specialTokens);
276
  }
277
  const rendered = await predictWindow(words.slice(contextStart, windowEnd));
278
  const emitEnd = windowEnd === words.length