@absolutejs/voice 0.0.22-beta.565 → 0.0.22-beta.567
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 +30 -0
- package/dist/angular/voice-controller.service.d.ts +1 -0
- package/dist/angular/voice-stream.service.d.ts +1 -0
- package/dist/client/actions.d.ts +33 -1
- package/dist/client/htmxBootstrap.js +42 -3
- package/dist/client/index.js +42 -3
- package/dist/core/types.d.ts +17 -1
- package/dist/embed/index.js +24 -0
- package/dist/embed/voice-widget.js +7 -7
- package/dist/index.js +1 -0
- package/dist/react/index.js +24 -0
- package/dist/react/useVoiceController.d.ts +1 -0
- package/dist/react/useVoiceStream.d.ts +1 -0
- package/dist/svelte/index.js +24 -0
- package/dist/testing/index.js +43 -3
- package/dist/vue/index.js +30 -0
- package/dist/vue/useVoiceController.d.ts +1 -0
- package/dist/vue/useVoiceStream.d.ts +1 -0
- package/package.json +1 -1
package/dist/angular/index.js
CHANGED
|
@@ -416,8 +416,15 @@ var serverMessageToAction = (message) => {
|
|
|
416
416
|
case "assistant":
|
|
417
417
|
return {
|
|
418
418
|
text: message.text,
|
|
419
|
+
turnId: message.turnId,
|
|
419
420
|
type: "assistant"
|
|
420
421
|
};
|
|
422
|
+
case "assistant_delta":
|
|
423
|
+
return {
|
|
424
|
+
delta: message.delta,
|
|
425
|
+
turnId: message.turnId,
|
|
426
|
+
type: "assistant_delta"
|
|
427
|
+
};
|
|
421
428
|
case "complete":
|
|
422
429
|
return {
|
|
423
430
|
sessionId: message.sessionId,
|
|
@@ -836,6 +843,7 @@ var createInitialReconnectState = () => ({
|
|
|
836
843
|
});
|
|
837
844
|
var createInitialState = () => ({
|
|
838
845
|
assistantAudio: [],
|
|
846
|
+
assistantStreamingText: "",
|
|
839
847
|
assistantTexts: [],
|
|
840
848
|
call: null,
|
|
841
849
|
error: null,
|
|
@@ -873,9 +881,16 @@ var createVoiceStreamStore = () => {
|
|
|
873
881
|
case "assistant":
|
|
874
882
|
state = {
|
|
875
883
|
...state,
|
|
884
|
+
assistantStreamingText: "",
|
|
876
885
|
assistantTexts: [...state.assistantTexts, action.text]
|
|
877
886
|
};
|
|
878
887
|
break;
|
|
888
|
+
case "assistant_delta":
|
|
889
|
+
state = {
|
|
890
|
+
...state,
|
|
891
|
+
assistantStreamingText: `${state.assistantStreamingText}${action.delta}`
|
|
892
|
+
};
|
|
893
|
+
break;
|
|
879
894
|
case "complete":
|
|
880
895
|
state = {
|
|
881
896
|
...state,
|
|
@@ -943,6 +958,7 @@ var createVoiceStreamStore = () => {
|
|
|
943
958
|
case "replay":
|
|
944
959
|
state = {
|
|
945
960
|
...state,
|
|
961
|
+
assistantStreamingText: "",
|
|
946
962
|
assistantTexts: [...action.assistantTexts],
|
|
947
963
|
call: action.call ?? null,
|
|
948
964
|
error: null,
|
|
@@ -1054,6 +1070,9 @@ var createVoiceStream = (path, options = {}) => {
|
|
|
1054
1070
|
get assistantTexts() {
|
|
1055
1071
|
return store.getSnapshot().assistantTexts;
|
|
1056
1072
|
},
|
|
1073
|
+
get assistantStreamingText() {
|
|
1074
|
+
return store.getSnapshot().assistantStreamingText;
|
|
1075
|
+
},
|
|
1057
1076
|
get call() {
|
|
1058
1077
|
return store.getSnapshot().call;
|
|
1059
1078
|
},
|
|
@@ -1437,6 +1456,7 @@ var resolveVoiceRuntimePreset = (name = "default") => {
|
|
|
1437
1456
|
// src/client/controller.ts
|
|
1438
1457
|
var createInitialState2 = (stream) => ({
|
|
1439
1458
|
assistantAudio: [...stream.assistantAudio],
|
|
1459
|
+
assistantStreamingText: stream.assistantStreamingText,
|
|
1440
1460
|
assistantTexts: [...stream.assistantTexts],
|
|
1441
1461
|
call: stream.call,
|
|
1442
1462
|
error: stream.error,
|
|
@@ -1469,6 +1489,7 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1469
1489
|
state = {
|
|
1470
1490
|
...state,
|
|
1471
1491
|
assistantAudio: [...stream.assistantAudio],
|
|
1492
|
+
assistantStreamingText: stream.assistantStreamingText,
|
|
1472
1493
|
assistantTexts: [...stream.assistantTexts],
|
|
1473
1494
|
call: stream.call,
|
|
1474
1495
|
error: stream.error,
|
|
@@ -1562,6 +1583,9 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1562
1583
|
get assistantTexts() {
|
|
1563
1584
|
return state.assistantTexts;
|
|
1564
1585
|
},
|
|
1586
|
+
get assistantStreamingText() {
|
|
1587
|
+
return state.assistantStreamingText;
|
|
1588
|
+
},
|
|
1565
1589
|
bindHTMX(bindingOptions) {
|
|
1566
1590
|
return bindVoiceHTMX(stream, bindingOptions);
|
|
1567
1591
|
},
|
|
@@ -4201,6 +4225,7 @@ class VoiceStreamService {
|
|
|
4201
4225
|
connect(path, options = {}) {
|
|
4202
4226
|
const stream = createVoiceStream(path, options);
|
|
4203
4227
|
const assistantAudioSignal = signal20([]);
|
|
4228
|
+
const assistantStreamingTextSignal = signal20("");
|
|
4204
4229
|
const assistantTextsSignal = signal20([]);
|
|
4205
4230
|
const callSignal = signal20(null);
|
|
4206
4231
|
const errorSignal = signal20(null);
|
|
@@ -4213,6 +4238,7 @@ class VoiceStreamService {
|
|
|
4213
4238
|
const turnsSignal = signal20([]);
|
|
4214
4239
|
const sync = () => {
|
|
4215
4240
|
assistantAudioSignal.set([...stream.assistantAudio]);
|
|
4241
|
+
assistantStreamingTextSignal.set(stream.assistantStreamingText);
|
|
4216
4242
|
assistantTextsSignal.set([...stream.assistantTexts]);
|
|
4217
4243
|
callSignal.set(stream.call);
|
|
4218
4244
|
errorSignal.set(stream.error);
|
|
@@ -4228,6 +4254,7 @@ class VoiceStreamService {
|
|
|
4228
4254
|
sync();
|
|
4229
4255
|
return {
|
|
4230
4256
|
assistantAudio: computed20(() => assistantAudioSignal()),
|
|
4257
|
+
assistantStreamingText: computed20(() => assistantStreamingTextSignal()),
|
|
4231
4258
|
assistantTexts: computed20(() => assistantTextsSignal()),
|
|
4232
4259
|
call: computed20(() => callSignal()),
|
|
4233
4260
|
callControl: (message) => stream.callControl(message),
|
|
@@ -4264,6 +4291,7 @@ class VoiceControllerService {
|
|
|
4264
4291
|
connect(path, options = {}) {
|
|
4265
4292
|
const controller = createVoiceController(path, options);
|
|
4266
4293
|
const assistantAudioSignal = signal21([]);
|
|
4294
|
+
const assistantStreamingTextSignal = signal21("");
|
|
4267
4295
|
const assistantTextsSignal = signal21([]);
|
|
4268
4296
|
const errorSignal = signal21(null);
|
|
4269
4297
|
const isConnectedSignal = signal21(false);
|
|
@@ -4276,6 +4304,7 @@ class VoiceControllerService {
|
|
|
4276
4304
|
const turnsSignal = signal21([]);
|
|
4277
4305
|
const sync = () => {
|
|
4278
4306
|
assistantAudioSignal.set([...controller.assistantAudio]);
|
|
4307
|
+
assistantStreamingTextSignal.set(controller.assistantStreamingText);
|
|
4279
4308
|
assistantTextsSignal.set([...controller.assistantTexts]);
|
|
4280
4309
|
errorSignal.set(controller.error);
|
|
4281
4310
|
isConnectedSignal.set(controller.isConnected);
|
|
@@ -4291,6 +4320,7 @@ class VoiceControllerService {
|
|
|
4291
4320
|
sync();
|
|
4292
4321
|
return {
|
|
4293
4322
|
assistantAudio: computed21(() => assistantAudioSignal()),
|
|
4323
|
+
assistantStreamingText: computed21(() => assistantStreamingTextSignal()),
|
|
4294
4324
|
assistantTexts: computed21(() => assistantTextsSignal()),
|
|
4295
4325
|
bindHTMX: controller.bindHTMX,
|
|
4296
4326
|
close: () => {
|
|
@@ -7,6 +7,7 @@ export declare class VoiceControllerService {
|
|
|
7
7
|
receivedAt: number;
|
|
8
8
|
turnId?: string;
|
|
9
9
|
}[]>;
|
|
10
|
+
assistantStreamingText: import("@angular/core").Signal<string>;
|
|
10
11
|
assistantTexts: import("@angular/core").Signal<string[]>;
|
|
11
12
|
bindHTMX: (options: import("..").VoiceHTMXBindingOptions) => () => void;
|
|
12
13
|
close: () => void;
|
|
@@ -7,6 +7,7 @@ export declare class VoiceStreamService {
|
|
|
7
7
|
receivedAt: number;
|
|
8
8
|
turnId?: string;
|
|
9
9
|
}[]>;
|
|
10
|
+
assistantStreamingText: import("@angular/core").Signal<string>;
|
|
10
11
|
assistantTexts: import("@angular/core").Signal<string[]>;
|
|
11
12
|
call: import("@angular/core").Signal<import("..").VoiceCallLifecycleState | null>;
|
|
12
13
|
callControl: (message: Parameters<(message: Omit<import("..").VoiceClientCallControlMessage, "type">) => void>[0]) => void;
|
package/dist/client/actions.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
|
|
|
6
6
|
turnId: string | undefined;
|
|
7
7
|
type: "audio";
|
|
8
8
|
text?: undefined;
|
|
9
|
+
delta?: undefined;
|
|
9
10
|
sessionId?: undefined;
|
|
10
11
|
reconnect?: undefined;
|
|
11
12
|
event?: undefined;
|
|
@@ -21,11 +22,33 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
|
|
|
21
22
|
turn?: undefined;
|
|
22
23
|
} | {
|
|
23
24
|
text: string;
|
|
25
|
+
turnId: string | undefined;
|
|
24
26
|
type: "assistant";
|
|
25
27
|
chunk?: undefined;
|
|
26
28
|
format?: undefined;
|
|
27
29
|
receivedAt?: undefined;
|
|
28
|
-
|
|
30
|
+
delta?: undefined;
|
|
31
|
+
sessionId?: undefined;
|
|
32
|
+
reconnect?: undefined;
|
|
33
|
+
event?: undefined;
|
|
34
|
+
message?: undefined;
|
|
35
|
+
transcript?: undefined;
|
|
36
|
+
assistantTexts?: undefined;
|
|
37
|
+
call?: undefined;
|
|
38
|
+
partial?: undefined;
|
|
39
|
+
scenarioId?: undefined;
|
|
40
|
+
sessionMetadata?: undefined;
|
|
41
|
+
status?: undefined;
|
|
42
|
+
turns?: undefined;
|
|
43
|
+
turn?: undefined;
|
|
44
|
+
} | {
|
|
45
|
+
delta: string;
|
|
46
|
+
turnId: string | undefined;
|
|
47
|
+
type: "assistant_delta";
|
|
48
|
+
chunk?: undefined;
|
|
49
|
+
format?: undefined;
|
|
50
|
+
receivedAt?: undefined;
|
|
51
|
+
text?: undefined;
|
|
29
52
|
sessionId?: undefined;
|
|
30
53
|
reconnect?: undefined;
|
|
31
54
|
event?: undefined;
|
|
@@ -47,6 +70,7 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
|
|
|
47
70
|
receivedAt?: undefined;
|
|
48
71
|
turnId?: undefined;
|
|
49
72
|
text?: undefined;
|
|
73
|
+
delta?: undefined;
|
|
50
74
|
reconnect?: undefined;
|
|
51
75
|
event?: undefined;
|
|
52
76
|
message?: undefined;
|
|
@@ -67,6 +91,7 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
|
|
|
67
91
|
receivedAt?: undefined;
|
|
68
92
|
turnId?: undefined;
|
|
69
93
|
text?: undefined;
|
|
94
|
+
delta?: undefined;
|
|
70
95
|
sessionId?: undefined;
|
|
71
96
|
event?: undefined;
|
|
72
97
|
message?: undefined;
|
|
@@ -88,6 +113,7 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
|
|
|
88
113
|
receivedAt?: undefined;
|
|
89
114
|
turnId?: undefined;
|
|
90
115
|
text?: undefined;
|
|
116
|
+
delta?: undefined;
|
|
91
117
|
reconnect?: undefined;
|
|
92
118
|
message?: undefined;
|
|
93
119
|
transcript?: undefined;
|
|
@@ -107,6 +133,7 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
|
|
|
107
133
|
receivedAt?: undefined;
|
|
108
134
|
turnId?: undefined;
|
|
109
135
|
text?: undefined;
|
|
136
|
+
delta?: undefined;
|
|
110
137
|
sessionId?: undefined;
|
|
111
138
|
reconnect?: undefined;
|
|
112
139
|
event?: undefined;
|
|
@@ -127,6 +154,7 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
|
|
|
127
154
|
receivedAt?: undefined;
|
|
128
155
|
turnId?: undefined;
|
|
129
156
|
text?: undefined;
|
|
157
|
+
delta?: undefined;
|
|
130
158
|
sessionId?: undefined;
|
|
131
159
|
reconnect?: undefined;
|
|
132
160
|
event?: undefined;
|
|
@@ -147,6 +175,7 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
|
|
|
147
175
|
receivedAt?: undefined;
|
|
148
176
|
turnId?: undefined;
|
|
149
177
|
text?: undefined;
|
|
178
|
+
delta?: undefined;
|
|
150
179
|
sessionId?: undefined;
|
|
151
180
|
reconnect?: undefined;
|
|
152
181
|
event?: undefined;
|
|
@@ -174,6 +203,7 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
|
|
|
174
203
|
receivedAt?: undefined;
|
|
175
204
|
turnId?: undefined;
|
|
176
205
|
text?: undefined;
|
|
206
|
+
delta?: undefined;
|
|
177
207
|
reconnect?: undefined;
|
|
178
208
|
event?: undefined;
|
|
179
209
|
message?: undefined;
|
|
@@ -190,6 +220,7 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
|
|
|
190
220
|
receivedAt?: undefined;
|
|
191
221
|
turnId?: undefined;
|
|
192
222
|
text?: undefined;
|
|
223
|
+
delta?: undefined;
|
|
193
224
|
reconnect?: undefined;
|
|
194
225
|
event?: undefined;
|
|
195
226
|
message?: undefined;
|
|
@@ -207,6 +238,7 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
|
|
|
207
238
|
receivedAt?: undefined;
|
|
208
239
|
turnId?: undefined;
|
|
209
240
|
text?: undefined;
|
|
241
|
+
delta?: undefined;
|
|
210
242
|
sessionId?: undefined;
|
|
211
243
|
reconnect?: undefined;
|
|
212
244
|
event?: undefined;
|
|
@@ -184,8 +184,15 @@ var serverMessageToAction = (message) => {
|
|
|
184
184
|
case "assistant":
|
|
185
185
|
return {
|
|
186
186
|
text: message.text,
|
|
187
|
+
turnId: message.turnId,
|
|
187
188
|
type: "assistant"
|
|
188
189
|
};
|
|
190
|
+
case "assistant_delta":
|
|
191
|
+
return {
|
|
192
|
+
delta: message.delta,
|
|
193
|
+
turnId: message.turnId,
|
|
194
|
+
type: "assistant_delta"
|
|
195
|
+
};
|
|
189
196
|
case "complete":
|
|
190
197
|
return {
|
|
191
198
|
sessionId: message.sessionId,
|
|
@@ -753,6 +760,7 @@ var createInitialReconnectState = () => ({
|
|
|
753
760
|
});
|
|
754
761
|
var createInitialState = () => ({
|
|
755
762
|
assistantAudio: [],
|
|
763
|
+
assistantStreamingText: "",
|
|
756
764
|
assistantTexts: [],
|
|
757
765
|
call: null,
|
|
758
766
|
error: null,
|
|
@@ -790,9 +798,16 @@ var createVoiceStreamStore = () => {
|
|
|
790
798
|
case "assistant":
|
|
791
799
|
state = {
|
|
792
800
|
...state,
|
|
801
|
+
assistantStreamingText: "",
|
|
793
802
|
assistantTexts: [...state.assistantTexts, action.text]
|
|
794
803
|
};
|
|
795
804
|
break;
|
|
805
|
+
case "assistant_delta":
|
|
806
|
+
state = {
|
|
807
|
+
...state,
|
|
808
|
+
assistantStreamingText: `${state.assistantStreamingText}${action.delta}`
|
|
809
|
+
};
|
|
810
|
+
break;
|
|
796
811
|
case "complete":
|
|
797
812
|
state = {
|
|
798
813
|
...state,
|
|
@@ -860,6 +875,7 @@ var createVoiceStreamStore = () => {
|
|
|
860
875
|
case "replay":
|
|
861
876
|
state = {
|
|
862
877
|
...state,
|
|
878
|
+
assistantStreamingText: "",
|
|
863
879
|
assistantTexts: [...action.assistantTexts],
|
|
864
880
|
call: action.call ?? null,
|
|
865
881
|
error: null,
|
|
@@ -971,6 +987,9 @@ var createVoiceStream = (path, options = {}) => {
|
|
|
971
987
|
get assistantTexts() {
|
|
972
988
|
return store.getSnapshot().assistantTexts;
|
|
973
989
|
},
|
|
990
|
+
get assistantStreamingText() {
|
|
991
|
+
return store.getSnapshot().assistantStreamingText;
|
|
992
|
+
},
|
|
974
993
|
get call() {
|
|
975
994
|
return store.getSnapshot().call;
|
|
976
995
|
},
|
|
@@ -1317,6 +1336,7 @@ var resolveVoiceRuntimePreset = (name = "default") => {
|
|
|
1317
1336
|
// src/client/controller.ts
|
|
1318
1337
|
var createInitialState2 = (stream) => ({
|
|
1319
1338
|
assistantAudio: [...stream.assistantAudio],
|
|
1339
|
+
assistantStreamingText: stream.assistantStreamingText,
|
|
1320
1340
|
assistantTexts: [...stream.assistantTexts],
|
|
1321
1341
|
call: stream.call,
|
|
1322
1342
|
error: stream.error,
|
|
@@ -1349,6 +1369,7 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1349
1369
|
state = {
|
|
1350
1370
|
...state,
|
|
1351
1371
|
assistantAudio: [...stream.assistantAudio],
|
|
1372
|
+
assistantStreamingText: stream.assistantStreamingText,
|
|
1352
1373
|
assistantTexts: [...stream.assistantTexts],
|
|
1353
1374
|
call: stream.call,
|
|
1354
1375
|
error: stream.error,
|
|
@@ -1442,6 +1463,9 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1442
1463
|
get assistantTexts() {
|
|
1443
1464
|
return state.assistantTexts;
|
|
1444
1465
|
},
|
|
1466
|
+
get assistantStreamingText() {
|
|
1467
|
+
return state.assistantStreamingText;
|
|
1468
|
+
},
|
|
1445
1469
|
bindHTMX(bindingOptions) {
|
|
1446
1470
|
return bindVoiceHTMX(stream, bindingOptions);
|
|
1447
1471
|
},
|
|
@@ -1505,6 +1529,7 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1505
1529
|
|
|
1506
1530
|
// src/client/audioPlayer.ts
|
|
1507
1531
|
var DEFAULT_LOOKAHEAD_MS = 15;
|
|
1532
|
+
var DEFAULT_VOLUME = 1;
|
|
1508
1533
|
var createInitialState3 = () => ({
|
|
1509
1534
|
activeSourceCount: 0,
|
|
1510
1535
|
error: null,
|
|
@@ -1521,6 +1546,12 @@ var getAudioContextCtor = () => {
|
|
|
1521
1546
|
}
|
|
1522
1547
|
return window.AudioContext ?? window.webkitAudioContext;
|
|
1523
1548
|
};
|
|
1549
|
+
var clampVolume = (volume) => {
|
|
1550
|
+
if (typeof volume !== "number" || !Number.isFinite(volume)) {
|
|
1551
|
+
return DEFAULT_VOLUME;
|
|
1552
|
+
}
|
|
1553
|
+
return Math.min(1, Math.max(0, volume));
|
|
1554
|
+
};
|
|
1524
1555
|
var decodePCM16LEChunk = (audioContext, chunk) => {
|
|
1525
1556
|
const { format } = chunk;
|
|
1526
1557
|
if (format.container !== "raw" || format.encoding !== "pcm_s16le") {
|
|
@@ -1553,6 +1584,7 @@ var createVoiceAudioPlayer = (source, options = {}) => {
|
|
|
1553
1584
|
let state = createInitialState3();
|
|
1554
1585
|
let audioContext = null;
|
|
1555
1586
|
let outputNode = null;
|
|
1587
|
+
let volume = clampVolume(options.volume);
|
|
1556
1588
|
let queueEndTime = 0;
|
|
1557
1589
|
let syncPromise = Promise.resolve();
|
|
1558
1590
|
let interruptStartedAt = null;
|
|
@@ -1601,11 +1633,11 @@ var createVoiceAudioPlayer = (source, options = {}) => {
|
|
|
1601
1633
|
}
|
|
1602
1634
|
return Math.max(0, ((context.baseLatency ?? 0) + (context.outputLatency ?? 0)) * 1000);
|
|
1603
1635
|
};
|
|
1604
|
-
const
|
|
1636
|
+
const applyOutputGain = (context) => {
|
|
1605
1637
|
if (!outputNode) {
|
|
1606
1638
|
return;
|
|
1607
1639
|
}
|
|
1608
|
-
const gainValue =
|
|
1640
|
+
const gainValue = volume;
|
|
1609
1641
|
if (outputNode.gain.setValueAtTime) {
|
|
1610
1642
|
outputNode.gain.setValueAtTime(gainValue, context?.currentTime ?? 0);
|
|
1611
1643
|
return;
|
|
@@ -1816,11 +1848,15 @@ var createVoiceAudioPlayer = (source, options = {}) => {
|
|
|
1816
1848
|
get queuedChunkCount() {
|
|
1817
1849
|
return state.queuedChunkCount;
|
|
1818
1850
|
},
|
|
1851
|
+
setVolume: (nextVolume) => {
|
|
1852
|
+
volume = clampVolume(nextVolume);
|
|
1853
|
+
applyOutputGain(audioContext);
|
|
1854
|
+
},
|
|
1819
1855
|
start: async () => {
|
|
1820
1856
|
try {
|
|
1821
1857
|
clearError();
|
|
1822
1858
|
const context = await ensureAudioContext();
|
|
1823
|
-
|
|
1859
|
+
applyOutputGain(context);
|
|
1824
1860
|
if (context.state === "suspended") {
|
|
1825
1861
|
await context.resume();
|
|
1826
1862
|
}
|
|
@@ -1844,6 +1880,9 @@ var createVoiceAudioPlayer = (source, options = {}) => {
|
|
|
1844
1880
|
return () => {
|
|
1845
1881
|
subscribers.delete(subscriber);
|
|
1846
1882
|
};
|
|
1883
|
+
},
|
|
1884
|
+
get volume() {
|
|
1885
|
+
return volume;
|
|
1847
1886
|
}
|
|
1848
1887
|
};
|
|
1849
1888
|
return player;
|
package/dist/client/index.js
CHANGED
|
@@ -372,6 +372,7 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
372
372
|
};
|
|
373
373
|
// src/client/audioPlayer.ts
|
|
374
374
|
var DEFAULT_LOOKAHEAD_MS = 15;
|
|
375
|
+
var DEFAULT_VOLUME = 1;
|
|
375
376
|
var createInitialState = () => ({
|
|
376
377
|
activeSourceCount: 0,
|
|
377
378
|
error: null,
|
|
@@ -388,6 +389,12 @@ var getAudioContextCtor = () => {
|
|
|
388
389
|
}
|
|
389
390
|
return window.AudioContext ?? window.webkitAudioContext;
|
|
390
391
|
};
|
|
392
|
+
var clampVolume = (volume) => {
|
|
393
|
+
if (typeof volume !== "number" || !Number.isFinite(volume)) {
|
|
394
|
+
return DEFAULT_VOLUME;
|
|
395
|
+
}
|
|
396
|
+
return Math.min(1, Math.max(0, volume));
|
|
397
|
+
};
|
|
391
398
|
var decodePCM16LEChunk = (audioContext, chunk) => {
|
|
392
399
|
const { format } = chunk;
|
|
393
400
|
if (format.container !== "raw" || format.encoding !== "pcm_s16le") {
|
|
@@ -420,6 +427,7 @@ var createVoiceAudioPlayer = (source, options = {}) => {
|
|
|
420
427
|
let state = createInitialState();
|
|
421
428
|
let audioContext = null;
|
|
422
429
|
let outputNode = null;
|
|
430
|
+
let volume = clampVolume(options.volume);
|
|
423
431
|
let queueEndTime = 0;
|
|
424
432
|
let syncPromise = Promise.resolve();
|
|
425
433
|
let interruptStartedAt = null;
|
|
@@ -468,11 +476,11 @@ var createVoiceAudioPlayer = (source, options = {}) => {
|
|
|
468
476
|
}
|
|
469
477
|
return Math.max(0, ((context.baseLatency ?? 0) + (context.outputLatency ?? 0)) * 1000);
|
|
470
478
|
};
|
|
471
|
-
const
|
|
479
|
+
const applyOutputGain = (context) => {
|
|
472
480
|
if (!outputNode) {
|
|
473
481
|
return;
|
|
474
482
|
}
|
|
475
|
-
const gainValue =
|
|
483
|
+
const gainValue = volume;
|
|
476
484
|
if (outputNode.gain.setValueAtTime) {
|
|
477
485
|
outputNode.gain.setValueAtTime(gainValue, context?.currentTime ?? 0);
|
|
478
486
|
return;
|
|
@@ -683,11 +691,15 @@ var createVoiceAudioPlayer = (source, options = {}) => {
|
|
|
683
691
|
get queuedChunkCount() {
|
|
684
692
|
return state.queuedChunkCount;
|
|
685
693
|
},
|
|
694
|
+
setVolume: (nextVolume) => {
|
|
695
|
+
volume = clampVolume(nextVolume);
|
|
696
|
+
applyOutputGain(audioContext);
|
|
697
|
+
},
|
|
686
698
|
start: async () => {
|
|
687
699
|
try {
|
|
688
700
|
clearError();
|
|
689
701
|
const context = await ensureAudioContext();
|
|
690
|
-
|
|
702
|
+
applyOutputGain(context);
|
|
691
703
|
if (context.state === "suspended") {
|
|
692
704
|
await context.resume();
|
|
693
705
|
}
|
|
@@ -711,6 +723,9 @@ var createVoiceAudioPlayer = (source, options = {}) => {
|
|
|
711
723
|
return () => {
|
|
712
724
|
subscribers.delete(subscriber);
|
|
713
725
|
};
|
|
726
|
+
},
|
|
727
|
+
get volume() {
|
|
728
|
+
return volume;
|
|
714
729
|
}
|
|
715
730
|
};
|
|
716
731
|
return player;
|
|
@@ -757,8 +772,15 @@ var serverMessageToAction = (message) => {
|
|
|
757
772
|
case "assistant":
|
|
758
773
|
return {
|
|
759
774
|
text: message.text,
|
|
775
|
+
turnId: message.turnId,
|
|
760
776
|
type: "assistant"
|
|
761
777
|
};
|
|
778
|
+
case "assistant_delta":
|
|
779
|
+
return {
|
|
780
|
+
delta: message.delta,
|
|
781
|
+
turnId: message.turnId,
|
|
782
|
+
type: "assistant_delta"
|
|
783
|
+
};
|
|
762
784
|
case "complete":
|
|
763
785
|
return {
|
|
764
786
|
sessionId: message.sessionId,
|
|
@@ -906,6 +928,7 @@ var createInitialReconnectState = () => ({
|
|
|
906
928
|
});
|
|
907
929
|
var createInitialState2 = () => ({
|
|
908
930
|
assistantAudio: [],
|
|
931
|
+
assistantStreamingText: "",
|
|
909
932
|
assistantTexts: [],
|
|
910
933
|
call: null,
|
|
911
934
|
error: null,
|
|
@@ -943,9 +966,16 @@ var createVoiceStreamStore = () => {
|
|
|
943
966
|
case "assistant":
|
|
944
967
|
state = {
|
|
945
968
|
...state,
|
|
969
|
+
assistantStreamingText: "",
|
|
946
970
|
assistantTexts: [...state.assistantTexts, action.text]
|
|
947
971
|
};
|
|
948
972
|
break;
|
|
973
|
+
case "assistant_delta":
|
|
974
|
+
state = {
|
|
975
|
+
...state,
|
|
976
|
+
assistantStreamingText: `${state.assistantStreamingText}${action.delta}`
|
|
977
|
+
};
|
|
978
|
+
break;
|
|
949
979
|
case "complete":
|
|
950
980
|
state = {
|
|
951
981
|
...state,
|
|
@@ -1013,6 +1043,7 @@ var createVoiceStreamStore = () => {
|
|
|
1013
1043
|
case "replay":
|
|
1014
1044
|
state = {
|
|
1015
1045
|
...state,
|
|
1046
|
+
assistantStreamingText: "",
|
|
1016
1047
|
assistantTexts: [...action.assistantTexts],
|
|
1017
1048
|
call: action.call ?? null,
|
|
1018
1049
|
error: null,
|
|
@@ -1124,6 +1155,9 @@ var createVoiceStream = (path, options = {}) => {
|
|
|
1124
1155
|
get assistantTexts() {
|
|
1125
1156
|
return store.getSnapshot().assistantTexts;
|
|
1126
1157
|
},
|
|
1158
|
+
get assistantStreamingText() {
|
|
1159
|
+
return store.getSnapshot().assistantStreamingText;
|
|
1160
|
+
},
|
|
1127
1161
|
get call() {
|
|
1128
1162
|
return store.getSnapshot().call;
|
|
1129
1163
|
},
|
|
@@ -1648,6 +1682,7 @@ var resolveVoiceRuntimePreset = (name = "default") => {
|
|
|
1648
1682
|
// src/client/controller.ts
|
|
1649
1683
|
var createInitialState3 = (stream) => ({
|
|
1650
1684
|
assistantAudio: [...stream.assistantAudio],
|
|
1685
|
+
assistantStreamingText: stream.assistantStreamingText,
|
|
1651
1686
|
assistantTexts: [...stream.assistantTexts],
|
|
1652
1687
|
call: stream.call,
|
|
1653
1688
|
error: stream.error,
|
|
@@ -1680,6 +1715,7 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1680
1715
|
state = {
|
|
1681
1716
|
...state,
|
|
1682
1717
|
assistantAudio: [...stream.assistantAudio],
|
|
1718
|
+
assistantStreamingText: stream.assistantStreamingText,
|
|
1683
1719
|
assistantTexts: [...stream.assistantTexts],
|
|
1684
1720
|
call: stream.call,
|
|
1685
1721
|
error: stream.error,
|
|
@@ -1773,6 +1809,9 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1773
1809
|
get assistantTexts() {
|
|
1774
1810
|
return state.assistantTexts;
|
|
1775
1811
|
},
|
|
1812
|
+
get assistantStreamingText() {
|
|
1813
|
+
return state.assistantStreamingText;
|
|
1814
|
+
},
|
|
1776
1815
|
bindHTMX(bindingOptions) {
|
|
1777
1816
|
return bindVoiceHTMX(stream, bindingOptions);
|
|
1778
1817
|
},
|
package/dist/core/types.d.ts
CHANGED
|
@@ -1059,6 +1059,11 @@ export type VoiceServerAssistantMessage = {
|
|
|
1059
1059
|
text: string;
|
|
1060
1060
|
turnId?: string;
|
|
1061
1061
|
};
|
|
1062
|
+
export type VoiceServerAssistantDeltaMessage = {
|
|
1063
|
+
type: "assistant_delta";
|
|
1064
|
+
delta: string;
|
|
1065
|
+
turnId?: string;
|
|
1066
|
+
};
|
|
1062
1067
|
export type VoiceServerAudioMessage = {
|
|
1063
1068
|
type: "audio";
|
|
1064
1069
|
chunkBase64: string;
|
|
@@ -1087,7 +1092,7 @@ export type VoiceServerConnectionMessage = {
|
|
|
1087
1092
|
type: "connection";
|
|
1088
1093
|
reconnect: VoiceReconnectClientState;
|
|
1089
1094
|
};
|
|
1090
|
-
export type VoiceServerMessage<TResult = unknown> = VoiceServerSessionMessage | VoiceServerReplayMessage<TResult> | VoiceServerPartialMessage | VoiceServerFinalMessage | VoiceServerTurnMessage<TResult> | VoiceServerAssistantMessage | VoiceServerAudioMessage | VoiceServerCallLifecycleMessage | VoiceServerCompleteMessage | VoiceServerErrorMessage | VoiceServerPongMessage | VoiceServerConnectionMessage;
|
|
1095
|
+
export type VoiceServerMessage<TResult = unknown> = VoiceServerSessionMessage | VoiceServerReplayMessage<TResult> | VoiceServerPartialMessage | VoiceServerFinalMessage | VoiceServerTurnMessage<TResult> | VoiceServerAssistantMessage | VoiceServerAssistantDeltaMessage | VoiceServerAudioMessage | VoiceServerCallLifecycleMessage | VoiceServerCompleteMessage | VoiceServerErrorMessage | VoiceServerPongMessage | VoiceServerConnectionMessage;
|
|
1091
1096
|
export type VoiceConnectionOptions = {
|
|
1092
1097
|
browserMedia?: false | VoiceBrowserMediaReporterOptions;
|
|
1093
1098
|
protocols?: string[];
|
|
@@ -1178,6 +1183,7 @@ export type VoiceAudioPlayerOptions = {
|
|
|
1178
1183
|
autoStart?: boolean;
|
|
1179
1184
|
createAudioContext?: () => AudioContext;
|
|
1180
1185
|
lookaheadMs?: number;
|
|
1186
|
+
volume?: number;
|
|
1181
1187
|
};
|
|
1182
1188
|
export type VoiceDuplexControllerOptions = VoiceControllerOptions & {
|
|
1183
1189
|
audioPlayer?: VoiceAudioPlayerOptions;
|
|
@@ -1236,6 +1242,7 @@ export type VoiceStreamState<TResult = unknown> = {
|
|
|
1236
1242
|
partial: string;
|
|
1237
1243
|
turns: VoiceTurnRecord<TResult>[];
|
|
1238
1244
|
assistantTexts: string[];
|
|
1245
|
+
assistantStreamingText: string;
|
|
1239
1246
|
assistantAudio: Array<{
|
|
1240
1247
|
chunk: Uint8Array;
|
|
1241
1248
|
format: AudioFormat;
|
|
@@ -1269,6 +1276,7 @@ export type VoiceStream<TResult = unknown> = {
|
|
|
1269
1276
|
subscribe: (subscriber: () => void) => () => void;
|
|
1270
1277
|
turns: VoiceTurnRecord<TResult>[];
|
|
1271
1278
|
assistantTexts: string[];
|
|
1279
|
+
assistantStreamingText: string;
|
|
1272
1280
|
assistantAudio: Array<{
|
|
1273
1281
|
chunk: Uint8Array;
|
|
1274
1282
|
format: AudioFormat;
|
|
@@ -1307,8 +1315,10 @@ export type VoiceAudioPlayer = {
|
|
|
1307
1315
|
pause: () => Promise<void>;
|
|
1308
1316
|
processedChunkCount: number;
|
|
1309
1317
|
queuedChunkCount: number;
|
|
1318
|
+
setVolume: (volume: number) => void;
|
|
1310
1319
|
start: () => Promise<void>;
|
|
1311
1320
|
subscribe: (subscriber: () => void) => () => void;
|
|
1321
|
+
volume: number;
|
|
1312
1322
|
};
|
|
1313
1323
|
export type VoiceBargeInBinding = {
|
|
1314
1324
|
close: () => void;
|
|
@@ -1345,6 +1355,7 @@ export type VoiceController<TResult = unknown> = {
|
|
|
1345
1355
|
toggleRecording: () => Promise<void>;
|
|
1346
1356
|
turns: VoiceTurnRecord<TResult>[];
|
|
1347
1357
|
assistantTexts: string[];
|
|
1358
|
+
assistantStreamingText: string;
|
|
1348
1359
|
assistantAudio: Array<{
|
|
1349
1360
|
chunk: Uint8Array;
|
|
1350
1361
|
format: AudioFormat;
|
|
@@ -1394,6 +1405,11 @@ export type VoiceStoreAction<TResult = unknown> = {
|
|
|
1394
1405
|
} | {
|
|
1395
1406
|
type: "assistant";
|
|
1396
1407
|
text: string;
|
|
1408
|
+
turnId?: string;
|
|
1409
|
+
} | {
|
|
1410
|
+
type: "assistant_delta";
|
|
1411
|
+
delta: string;
|
|
1412
|
+
turnId?: string;
|
|
1397
1413
|
} | {
|
|
1398
1414
|
type: "audio";
|
|
1399
1415
|
chunk: Uint8Array;
|