@absolutejs/voice 0.0.22-beta.591 → 0.0.22-beta.593

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/dist/index.js CHANGED
@@ -3753,7 +3753,8 @@ var normalizeText2 = (text) => text.trim().replace(/\s+/g, " ");
3753
3753
  var getAudioChunkDurationMs = (chunk) => chunk.byteLength / (DEFAULT_FORMAT.sampleRateHz * DEFAULT_FORMAT.channels * 2) * 1000;
3754
3754
  var getBufferedAudioDurationMs = (chunks) => chunks.reduce((total, chunk) => total + getAudioChunkDurationMs(chunk), 0);
3755
3755
  var STREAM_SENTENCE_BOUNDARY = /[.!?\u2026]['")\]]*\s/;
3756
- var MAX_TTS_CHUNK_CHARS = 220;
3756
+ var STREAM_CLAUSE_BOUNDARY = /[,;:]\s/g;
3757
+ var MAX_TTS_CHUNK_CHARS = 320;
3757
3758
  var nextSpeakableBoundary = (buffer) => {
3758
3759
  const match = STREAM_SENTENCE_BOUNDARY.exec(buffer);
3759
3760
  return match ? match.index + match[0].length : -1;
@@ -3762,6 +3763,12 @@ var softCutBoundary = (buffer) => {
3762
3763
  if (buffer.length < MAX_TTS_CHUNK_CHARS)
3763
3764
  return -1;
3764
3765
  const window2 = buffer.slice(0, MAX_TTS_CHUNK_CHARS);
3766
+ let lastClause = -1;
3767
+ for (const match of window2.matchAll(STREAM_CLAUSE_BOUNDARY)) {
3768
+ lastClause = match.index + match[0].length;
3769
+ }
3770
+ if (lastClause > 0)
3771
+ return lastClause;
3765
3772
  const lastSpace = window2.lastIndexOf(" ");
3766
3773
  return lastSpace > 0 ? lastSpace + 1 : MAX_TTS_CHUNK_CHARS;
3767
3774
  };
@@ -6282,9 +6289,21 @@ var createVoiceSession = (options) => {
6282
6289
  amdFirstAudioAt = Date.now();
6283
6290
  }
6284
6291
  speechDetected = true;
6285
- clearSilenceTimer();
6286
6292
  kickCallSilenceWatchdog();
6287
6293
  backchannelDriver?.noteSpeech();
6294
+ const latest = await readSession();
6295
+ const sttQuietMs = latest.currentTurn.lastTranscriptAt !== undefined ? Date.now() - latest.currentTurn.lastTranscriptAt : Number.POSITIVE_INFINITY;
6296
+ const hasTurnTextDespiteNoise = Boolean(buildTurnText(latest.currentTurn.transcripts, latest.currentTurn.partialText, {
6297
+ partialEndedAtMs: latest.currentTurn.partialEndedAt,
6298
+ partialStartedAtMs: latest.currentTurn.partialStartedAt
6299
+ }));
6300
+ if (hasTurnTextDespiteNoise && sttQuietMs >= turnDetection.silenceMs) {
6301
+ if (!silenceTimer) {
6302
+ scheduleSilenceCommit(0);
6303
+ }
6304
+ } else {
6305
+ clearSilenceTimer();
6306
+ }
6288
6307
  } else if (speechDetected) {
6289
6308
  backchannelDriver?.noteSilence();
6290
6309
  const currentSession = await readSession();
@@ -5980,7 +5980,8 @@ var normalizeText2 = (text) => text.trim().replace(/\s+/g, " ");
5980
5980
  var getAudioChunkDurationMs = (chunk) => chunk.byteLength / (DEFAULT_FORMAT.sampleRateHz * DEFAULT_FORMAT.channels * 2) * 1000;
5981
5981
  var getBufferedAudioDurationMs = (chunks) => chunks.reduce((total, chunk) => total + getAudioChunkDurationMs(chunk), 0);
5982
5982
  var STREAM_SENTENCE_BOUNDARY = /[.!?\u2026]['")\]]*\s/;
5983
- var MAX_TTS_CHUNK_CHARS = 220;
5983
+ var STREAM_CLAUSE_BOUNDARY = /[,;:]\s/g;
5984
+ var MAX_TTS_CHUNK_CHARS = 320;
5984
5985
  var nextSpeakableBoundary = (buffer) => {
5985
5986
  const match = STREAM_SENTENCE_BOUNDARY.exec(buffer);
5986
5987
  return match ? match.index + match[0].length : -1;
@@ -5989,6 +5990,12 @@ var softCutBoundary = (buffer) => {
5989
5990
  if (buffer.length < MAX_TTS_CHUNK_CHARS)
5990
5991
  return -1;
5991
5992
  const window2 = buffer.slice(0, MAX_TTS_CHUNK_CHARS);
5993
+ let lastClause = -1;
5994
+ for (const match of window2.matchAll(STREAM_CLAUSE_BOUNDARY)) {
5995
+ lastClause = match.index + match[0].length;
5996
+ }
5997
+ if (lastClause > 0)
5998
+ return lastClause;
5992
5999
  const lastSpace = window2.lastIndexOf(" ");
5993
6000
  return lastSpace > 0 ? lastSpace + 1 : MAX_TTS_CHUNK_CHARS;
5994
6001
  };
@@ -8509,9 +8516,21 @@ var createVoiceSession = (options) => {
8509
8516
  amdFirstAudioAt = Date.now();
8510
8517
  }
8511
8518
  speechDetected = true;
8512
- clearSilenceTimer();
8513
8519
  kickCallSilenceWatchdog();
8514
8520
  backchannelDriver?.noteSpeech();
8521
+ const latest = await readSession();
8522
+ const sttQuietMs = latest.currentTurn.lastTranscriptAt !== undefined ? Date.now() - latest.currentTurn.lastTranscriptAt : Number.POSITIVE_INFINITY;
8523
+ const hasTurnTextDespiteNoise = Boolean(buildTurnText(latest.currentTurn.transcripts, latest.currentTurn.partialText, {
8524
+ partialEndedAtMs: latest.currentTurn.partialEndedAt,
8525
+ partialStartedAtMs: latest.currentTurn.partialStartedAt
8526
+ }));
8527
+ if (hasTurnTextDespiteNoise && sttQuietMs >= turnDetection.silenceMs) {
8528
+ if (!silenceTimer) {
8529
+ scheduleSilenceCommit(0);
8530
+ }
8531
+ } else {
8532
+ clearSilenceTimer();
8533
+ }
8515
8534
  } else if (speechDetected) {
8516
8535
  backchannelDriver?.noteSilence();
8517
8536
  const currentSession = await readSession();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.591",
3
+ "version": "0.0.22-beta.593",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",