@absolutejs/voice 0.0.22-beta.664 → 0.0.22-beta.666
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/angular/index.js +21 -0
- package/dist/client/actions.d.ts +37 -0
- package/dist/client/htmxBootstrap.js +21 -0
- package/dist/client/index.js +29 -0
- package/dist/core/types.d.ts +15 -1
- package/dist/embed/index.js +21 -0
- package/dist/embed/voice-widget.js +4 -4
- package/dist/index.js +45 -102
- package/dist/react/index.js +21 -0
- package/dist/react/useVoiceController.d.ts +1 -0
- package/dist/react/useVoiceStream.d.ts +1 -0
- package/dist/svelte/index.js +21 -0
- package/dist/telephony/plivo.d.ts +3 -4
- package/dist/telephony/telnyx.d.ts +3 -4
- package/dist/testing/index.js +69 -24
- package/dist/vue/index.js +21 -0
- package/package.json +1 -1
|
@@ -162,9 +162,8 @@ export type TelnyxVoiceRoutesOptions<TContext = unknown, TSession extends VoiceS
|
|
|
162
162
|
};
|
|
163
163
|
};
|
|
164
164
|
export type VoiceTelnyxWebhookEventStore = {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
set: (eventId: string) => Promise<void> | void;
|
|
165
|
+
/** Atomically accepts an unseen event id and rejects every duplicate. */
|
|
166
|
+
claim: (eventId: string) => Promise<boolean> | boolean;
|
|
168
167
|
};
|
|
169
168
|
export type VoiceTelnyxWebhookEventStoreOptions = {
|
|
170
169
|
ttlSeconds?: number;
|
|
@@ -182,7 +181,7 @@ export type VoicePostgresTelnyxWebhookEventStoreOptions = VoiceTelnyxWebhookEven
|
|
|
182
181
|
tableName?: string;
|
|
183
182
|
tablePrefix?: string;
|
|
184
183
|
};
|
|
185
|
-
export type VoiceRedisTelnyxWebhookEventClient = Pick<RedisClient, "
|
|
184
|
+
export type VoiceRedisTelnyxWebhookEventClient = Pick<RedisClient, "set">;
|
|
186
185
|
export type VoiceRedisTelnyxWebhookEventStoreOptions = VoiceTelnyxWebhookEventStoreOptions & {
|
|
187
186
|
client?: VoiceRedisTelnyxWebhookEventClient;
|
|
188
187
|
keyPrefix?: string;
|
package/dist/testing/index.js
CHANGED
|
@@ -2914,6 +2914,11 @@ var serverMessageToAction = (message) => {
|
|
|
2914
2914
|
transcript: message.transcript,
|
|
2915
2915
|
type: "partial"
|
|
2916
2916
|
};
|
|
2917
|
+
case "playback_rate":
|
|
2918
|
+
return {
|
|
2919
|
+
rate: message.rate,
|
|
2920
|
+
type: "playback_rate"
|
|
2921
|
+
};
|
|
2917
2922
|
case "replay":
|
|
2918
2923
|
return {
|
|
2919
2924
|
assistantTexts: message.assistantTexts,
|
|
@@ -3096,6 +3101,7 @@ var isVoiceServerMessage = (value) => {
|
|
|
3096
3101
|
case "error":
|
|
3097
3102
|
case "final":
|
|
3098
3103
|
case "partial":
|
|
3104
|
+
case "playback_rate":
|
|
3099
3105
|
case "pong":
|
|
3100
3106
|
case "replay":
|
|
3101
3107
|
case "session":
|
|
@@ -3522,6 +3528,7 @@ var createInitialState2 = () => ({
|
|
|
3522
3528
|
isConnected: false,
|
|
3523
3529
|
paused: false,
|
|
3524
3530
|
partial: "",
|
|
3531
|
+
playbackRate: null,
|
|
3525
3532
|
reconnect: createInitialReconnectState(),
|
|
3526
3533
|
scenarioId: null,
|
|
3527
3534
|
sessionId: null,
|
|
@@ -3630,6 +3637,12 @@ var createVoiceStreamStore = () => {
|
|
|
3630
3637
|
partial: joinPartial(turnFinalText, action.transcript.text)
|
|
3631
3638
|
};
|
|
3632
3639
|
break;
|
|
3640
|
+
case "playback_rate":
|
|
3641
|
+
state = {
|
|
3642
|
+
...state,
|
|
3643
|
+
playbackRate: Math.max(0.5, Math.min(2, action.rate))
|
|
3644
|
+
};
|
|
3645
|
+
break;
|
|
3633
3646
|
case "replay":
|
|
3634
3647
|
turnFinalText = action.partial;
|
|
3635
3648
|
state = {
|
|
@@ -3795,6 +3808,9 @@ var createVoiceStream = (path, options = {}) => {
|
|
|
3795
3808
|
get partial() {
|
|
3796
3809
|
return store.getSnapshot().partial;
|
|
3797
3810
|
},
|
|
3811
|
+
get playbackRate() {
|
|
3812
|
+
return store.getSnapshot().playbackRate;
|
|
3813
|
+
},
|
|
3798
3814
|
get paused() {
|
|
3799
3815
|
return store.getSnapshot().paused;
|
|
3800
3816
|
},
|
|
@@ -4167,6 +4183,7 @@ var createInitialState3 = (stream) => ({
|
|
|
4167
4183
|
paused: stream.paused,
|
|
4168
4184
|
pauseExpiresAt: stream.pauseExpiresAt,
|
|
4169
4185
|
partial: stream.partial,
|
|
4186
|
+
playbackRate: stream.playbackRate,
|
|
4170
4187
|
reconnect: stream.reconnect,
|
|
4171
4188
|
recordingError: null,
|
|
4172
4189
|
sessionId: stream.sessionId,
|
|
@@ -4204,6 +4221,7 @@ var createVoiceController = (path, options = {}) => {
|
|
|
4204
4221
|
paused: stream.paused,
|
|
4205
4222
|
pauseExpiresAt: stream.pauseExpiresAt,
|
|
4206
4223
|
partial: stream.partial,
|
|
4224
|
+
playbackRate: stream.playbackRate,
|
|
4207
4225
|
reconnect: stream.reconnect,
|
|
4208
4226
|
sessionId: stream.sessionId,
|
|
4209
4227
|
sessionMetadata: stream.sessionMetadata,
|
|
@@ -4350,6 +4368,9 @@ var createVoiceController = (path, options = {}) => {
|
|
|
4350
4368
|
get partial() {
|
|
4351
4369
|
return state.partial;
|
|
4352
4370
|
},
|
|
4371
|
+
get playbackRate() {
|
|
4372
|
+
return state.playbackRate;
|
|
4373
|
+
},
|
|
4353
4374
|
get paused() {
|
|
4354
4375
|
return state.paused;
|
|
4355
4376
|
},
|
|
@@ -4459,10 +4480,18 @@ var createVoiceDuplexController = (path, options = {}) => {
|
|
|
4459
4480
|
}
|
|
4460
4481
|
});
|
|
4461
4482
|
const audioPlayer = createVoiceAudioPlayer(controller, options.audioPlayer);
|
|
4483
|
+
let appliedPlaybackRate = controller.playbackRate;
|
|
4484
|
+
const unsubscribePlaybackRate = controller.subscribe(() => {
|
|
4485
|
+
if (controller.playbackRate !== null && controller.playbackRate !== appliedPlaybackRate) {
|
|
4486
|
+
appliedPlaybackRate = controller.playbackRate;
|
|
4487
|
+
audioPlayer.setPlaybackRate(controller.playbackRate);
|
|
4488
|
+
}
|
|
4489
|
+
});
|
|
4462
4490
|
bargeInBinding = bindVoiceBargeIn(controller, audioPlayer, options.bargeIn);
|
|
4463
4491
|
const close = () => {
|
|
4464
4492
|
bargeInBinding?.close();
|
|
4465
4493
|
bargeInBinding = null;
|
|
4494
|
+
unsubscribePlaybackRate();
|
|
4466
4495
|
audioPlayer.close();
|
|
4467
4496
|
controller.close();
|
|
4468
4497
|
};
|
|
@@ -7250,6 +7279,11 @@ var createVoiceSession = (options) => {
|
|
|
7250
7279
|
let lastSpeechEnergyAt = 0;
|
|
7251
7280
|
let sttHealthPhaseStart = 0;
|
|
7252
7281
|
let sttDeafConfirmedAt = 0;
|
|
7282
|
+
const resetSttHealthWindow = () => {
|
|
7283
|
+
lastSpeechEnergyAt = 0;
|
|
7284
|
+
sttHealthPhaseStart = 0;
|
|
7285
|
+
sttDeafConfirmedAt = 0;
|
|
7286
|
+
};
|
|
7253
7287
|
let lastSttRecoverySpokenAt = 0;
|
|
7254
7288
|
let activeTTSTurnId;
|
|
7255
7289
|
let assistantSpeechEndsAt = 0;
|
|
@@ -9681,6 +9715,7 @@ var createVoiceSession = (options) => {
|
|
|
9681
9715
|
markTurnCommitted(currentSession, finalText, transcripts);
|
|
9682
9716
|
});
|
|
9683
9717
|
speechDetected = false;
|
|
9718
|
+
resetSttHealthWindow();
|
|
9684
9719
|
rewindFallbackTurnAudio();
|
|
9685
9720
|
logger.info("voice turn committed", {
|
|
9686
9721
|
reason,
|
|
@@ -10008,30 +10043,35 @@ var createVoiceSession = (options) => {
|
|
|
10008
10043
|
clearSilenceTimer();
|
|
10009
10044
|
}
|
|
10010
10045
|
const nowMs = Date.now();
|
|
10011
|
-
if (
|
|
10012
|
-
|
|
10013
|
-
}
|
|
10014
|
-
|
|
10015
|
-
|
|
10016
|
-
|
|
10017
|
-
|
|
10018
|
-
|
|
10019
|
-
|
|
10020
|
-
|
|
10021
|
-
|
|
10022
|
-
|
|
10023
|
-
|
|
10024
|
-
|
|
10025
|
-
|
|
10026
|
-
|
|
10027
|
-
|
|
10028
|
-
|
|
10029
|
-
|
|
10030
|
-
|
|
10031
|
-
|
|
10032
|
-
|
|
10033
|
-
|
|
10034
|
-
|
|
10046
|
+
if (assistantTurnInProgress) {
|
|
10047
|
+
resetSttHealthWindow();
|
|
10048
|
+
} else {
|
|
10049
|
+
if (nowMs - lastSpeechEnergyAt > STT_HEALTH_SPEECH_GAP_MS) {
|
|
10050
|
+
sttHealthPhaseStart = nowMs;
|
|
10051
|
+
}
|
|
10052
|
+
lastSpeechEnergyAt = nowMs;
|
|
10053
|
+
const lastTranscriptAt = latest.currentTurn.lastTranscriptAt ?? 0;
|
|
10054
|
+
if (!options.realtime && sttSession && lastTranscriptAt < sttHealthPhaseStart && nowMs - sttHealthPhaseStart >= STT_HEALTH_STALE_MS) {
|
|
10055
|
+
sttDeafConfirmedAt = nowMs;
|
|
10056
|
+
sttReconnectCount = nowMs - lastSttReconnectAt < STT_RECONNECT_FLAP_WINDOW_MS ? sttReconnectCount + 1 : 1;
|
|
10057
|
+
lastSttReconnectAt = nowMs;
|
|
10058
|
+
sttHealthPhaseStart = nowMs;
|
|
10059
|
+
maybeSpeakSttRecovery(nowMs, latest);
|
|
10060
|
+
if (sttReconnectCount <= MAX_STT_RECONNECTS_IN_FLAP_WINDOW) {
|
|
10061
|
+
await appendTrace({
|
|
10062
|
+
payload: {
|
|
10063
|
+
action: "stt-health-reconnect",
|
|
10064
|
+
attempt: sttReconnectCount,
|
|
10065
|
+
classification: "stt-deaf",
|
|
10066
|
+
recoverable: true,
|
|
10067
|
+
reason: `no transcript for ${STT_HEALTH_STALE_MS}ms of continuous speech`
|
|
10068
|
+
},
|
|
10069
|
+
session: latest,
|
|
10070
|
+
type: "session.error"
|
|
10071
|
+
});
|
|
10072
|
+
await closeAdapter("stt stale; health-reconnect");
|
|
10073
|
+
return;
|
|
10074
|
+
}
|
|
10035
10075
|
}
|
|
10036
10076
|
}
|
|
10037
10077
|
} else if (speechDetected) {
|
|
@@ -10161,6 +10201,11 @@ var createVoiceSession = (options) => {
|
|
|
10161
10201
|
speechThreshold: turnDetection.speechThreshold,
|
|
10162
10202
|
transcriptStabilityMs: turnDetection.transcriptStabilityMs
|
|
10163
10203
|
};
|
|
10204
|
+
}),
|
|
10205
|
+
setPlaybackRate: async (rate) => runSerial("api.setPlaybackRate", async () => {
|
|
10206
|
+
const clamped = Math.max(0.5, Math.min(2, Number(rate) || 1));
|
|
10207
|
+
await send({ rate: clamped, type: "playback_rate" });
|
|
10208
|
+
return clamped;
|
|
10164
10209
|
})
|
|
10165
10210
|
};
|
|
10166
10211
|
return api;
|
package/dist/vue/index.js
CHANGED
|
@@ -10720,6 +10720,11 @@ var serverMessageToAction = (message) => {
|
|
|
10720
10720
|
transcript: message.transcript,
|
|
10721
10721
|
type: "partial"
|
|
10722
10722
|
};
|
|
10723
|
+
case "playback_rate":
|
|
10724
|
+
return {
|
|
10725
|
+
rate: message.rate,
|
|
10726
|
+
type: "playback_rate"
|
|
10727
|
+
};
|
|
10723
10728
|
case "replay":
|
|
10724
10729
|
return {
|
|
10725
10730
|
assistantTexts: message.assistantTexts,
|
|
@@ -10902,6 +10907,7 @@ var isVoiceServerMessage = (value) => {
|
|
|
10902
10907
|
case "error":
|
|
10903
10908
|
case "final":
|
|
10904
10909
|
case "partial":
|
|
10910
|
+
case "playback_rate":
|
|
10905
10911
|
case "pong":
|
|
10906
10912
|
case "replay":
|
|
10907
10913
|
case "session":
|
|
@@ -11328,6 +11334,7 @@ var createInitialState = () => ({
|
|
|
11328
11334
|
isConnected: false,
|
|
11329
11335
|
paused: false,
|
|
11330
11336
|
partial: "",
|
|
11337
|
+
playbackRate: null,
|
|
11331
11338
|
reconnect: createInitialReconnectState(),
|
|
11332
11339
|
scenarioId: null,
|
|
11333
11340
|
sessionId: null,
|
|
@@ -11436,6 +11443,12 @@ var createVoiceStreamStore = () => {
|
|
|
11436
11443
|
partial: joinPartial(turnFinalText, action.transcript.text)
|
|
11437
11444
|
};
|
|
11438
11445
|
break;
|
|
11446
|
+
case "playback_rate":
|
|
11447
|
+
state = {
|
|
11448
|
+
...state,
|
|
11449
|
+
playbackRate: Math.max(0.5, Math.min(2, action.rate))
|
|
11450
|
+
};
|
|
11451
|
+
break;
|
|
11439
11452
|
case "replay":
|
|
11440
11453
|
turnFinalText = action.partial;
|
|
11441
11454
|
state = {
|
|
@@ -11601,6 +11614,9 @@ var createVoiceStream = (path, options = {}) => {
|
|
|
11601
11614
|
get partial() {
|
|
11602
11615
|
return store.getSnapshot().partial;
|
|
11603
11616
|
},
|
|
11617
|
+
get playbackRate() {
|
|
11618
|
+
return store.getSnapshot().playbackRate;
|
|
11619
|
+
},
|
|
11604
11620
|
get paused() {
|
|
11605
11621
|
return store.getSnapshot().paused;
|
|
11606
11622
|
},
|
|
@@ -12226,6 +12242,7 @@ var createInitialState2 = (stream) => ({
|
|
|
12226
12242
|
paused: stream.paused,
|
|
12227
12243
|
pauseExpiresAt: stream.pauseExpiresAt,
|
|
12228
12244
|
partial: stream.partial,
|
|
12245
|
+
playbackRate: stream.playbackRate,
|
|
12229
12246
|
reconnect: stream.reconnect,
|
|
12230
12247
|
recordingError: null,
|
|
12231
12248
|
sessionId: stream.sessionId,
|
|
@@ -12263,6 +12280,7 @@ var createVoiceController = (path, options = {}) => {
|
|
|
12263
12280
|
paused: stream.paused,
|
|
12264
12281
|
pauseExpiresAt: stream.pauseExpiresAt,
|
|
12265
12282
|
partial: stream.partial,
|
|
12283
|
+
playbackRate: stream.playbackRate,
|
|
12266
12284
|
reconnect: stream.reconnect,
|
|
12267
12285
|
sessionId: stream.sessionId,
|
|
12268
12286
|
sessionMetadata: stream.sessionMetadata,
|
|
@@ -12409,6 +12427,9 @@ var createVoiceController = (path, options = {}) => {
|
|
|
12409
12427
|
get partial() {
|
|
12410
12428
|
return state.partial;
|
|
12411
12429
|
},
|
|
12430
|
+
get playbackRate() {
|
|
12431
|
+
return state.playbackRate;
|
|
12432
|
+
},
|
|
12412
12433
|
get paused() {
|
|
12413
12434
|
return state.paused;
|
|
12414
12435
|
},
|