@absolutejs/voice 0.0.22-beta.590 → 0.0.22-beta.592

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
  };
@@ -4574,16 +4581,19 @@ var createVoiceSession = (options) => {
4574
4581
  const DRAIN_TAIL_BUFFER_MS = 300;
4575
4582
  const DRAIN_QUIET_MS = 600;
4576
4583
  const DRAIN_RENDER_START_MS = 4000;
4577
- const DRAIN_MAX_MS = 20000;
4584
+ const DRAIN_STREAMING_MAX_MS = 20000;
4585
+ const DRAIN_HARD_MAX_MS = 120000;
4578
4586
  const drainAssistantSpeech = async (renderPendingSince) => {
4579
4587
  const startedAt = Date.now();
4580
4588
  const sleep3 = (delayMs) => new Promise((resolve) => {
4581
4589
  setTimeout(resolve, delayMs);
4582
4590
  });
4583
- while (Date.now() - startedAt < DRAIN_MAX_MS) {
4591
+ while (Date.now() - startedAt < DRAIN_HARD_MAX_MS) {
4584
4592
  const now = Date.now();
4585
4593
  const renderStarted = lastAssistantAudioAt >= renderPendingSince || now - renderPendingSince >= DRAIN_RENDER_START_MS;
4586
4594
  if (!renderStarted) {
4595
+ if (now - startedAt >= DRAIN_STREAMING_MAX_MS)
4596
+ return;
4587
4597
  await sleep3(DRAIN_POLL_MS);
4588
4598
  continue;
4589
4599
  }
@@ -4591,6 +4601,8 @@ var createVoiceSession = (options) => {
4591
4601
  const playbackDrained = assistantSpeechEndsAt + DRAIN_TAIL_BUFFER_MS <= now;
4592
4602
  if (streamQuiet && playbackDrained)
4593
4603
  return;
4604
+ if (!streamQuiet && now - startedAt >= DRAIN_STREAMING_MAX_MS)
4605
+ return;
4594
4606
  await sleep3(DRAIN_POLL_MS);
4595
4607
  }
4596
4608
  };
@@ -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
  };
@@ -6801,16 +6808,19 @@ var createVoiceSession = (options) => {
6801
6808
  const DRAIN_TAIL_BUFFER_MS = 300;
6802
6809
  const DRAIN_QUIET_MS = 600;
6803
6810
  const DRAIN_RENDER_START_MS = 4000;
6804
- const DRAIN_MAX_MS = 20000;
6811
+ const DRAIN_STREAMING_MAX_MS = 20000;
6812
+ const DRAIN_HARD_MAX_MS = 120000;
6805
6813
  const drainAssistantSpeech = async (renderPendingSince) => {
6806
6814
  const startedAt = Date.now();
6807
6815
  const sleep2 = (delayMs) => new Promise((resolve2) => {
6808
6816
  setTimeout(resolve2, delayMs);
6809
6817
  });
6810
- while (Date.now() - startedAt < DRAIN_MAX_MS) {
6818
+ while (Date.now() - startedAt < DRAIN_HARD_MAX_MS) {
6811
6819
  const now = Date.now();
6812
6820
  const renderStarted = lastAssistantAudioAt >= renderPendingSince || now - renderPendingSince >= DRAIN_RENDER_START_MS;
6813
6821
  if (!renderStarted) {
6822
+ if (now - startedAt >= DRAIN_STREAMING_MAX_MS)
6823
+ return;
6814
6824
  await sleep2(DRAIN_POLL_MS);
6815
6825
  continue;
6816
6826
  }
@@ -6818,6 +6828,8 @@ var createVoiceSession = (options) => {
6818
6828
  const playbackDrained = assistantSpeechEndsAt + DRAIN_TAIL_BUFFER_MS <= now;
6819
6829
  if (streamQuiet && playbackDrained)
6820
6830
  return;
6831
+ if (!streamQuiet && now - startedAt >= DRAIN_STREAMING_MAX_MS)
6832
+ return;
6821
6833
  await sleep2(DRAIN_POLL_MS);
6822
6834
  }
6823
6835
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.590",
3
+ "version": "0.0.22-beta.592",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",