@absolutejs/voice 0.0.21 → 0.0.22-beta.0

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.
Files changed (39) hide show
  1. package/README.md +499 -2
  2. package/dist/angular/index.js +90 -0
  3. package/dist/angular/voice-controller.service.d.ts +6 -0
  4. package/dist/angular/voice-stream.service.d.ts +6 -0
  5. package/dist/client/actions.d.ts +41 -0
  6. package/dist/client/audioPlayer.d.ts +40 -0
  7. package/dist/client/duplex.d.ts +3 -0
  8. package/dist/client/htmxBootstrap.js +84 -0
  9. package/dist/client/index.d.ts +2 -0
  10. package/dist/client/index.js +507 -5
  11. package/dist/correction.d.ts +18 -1
  12. package/dist/fileStore.d.ts +27 -0
  13. package/dist/index.d.ts +12 -1
  14. package/dist/index.js +2425 -33
  15. package/dist/ops.d.ts +100 -0
  16. package/dist/react/index.js +86 -0
  17. package/dist/react/useVoiceController.d.ts +6 -0
  18. package/dist/react/useVoiceStream.d.ts +6 -0
  19. package/dist/routing.d.ts +3 -0
  20. package/dist/runtimeOps.d.ts +23 -0
  21. package/dist/svelte/index.js +84 -0
  22. package/dist/telephony/response.d.ts +7 -0
  23. package/dist/telephony/twilio.d.ts +116 -0
  24. package/dist/testing/benchmark.d.ts +59 -4
  25. package/dist/testing/corrected.d.ts +41 -0
  26. package/dist/testing/duplex.d.ts +59 -0
  27. package/dist/testing/fixtures.d.ts +18 -2
  28. package/dist/testing/index.d.ts +5 -0
  29. package/dist/testing/index.js +4940 -307
  30. package/dist/testing/review.d.ts +143 -0
  31. package/dist/testing/sessionBenchmark.d.ts +25 -0
  32. package/dist/testing/stt.d.ts +2 -1
  33. package/dist/testing/telephony.d.ts +70 -0
  34. package/dist/testing/tts.d.ts +73 -0
  35. package/dist/types.d.ts +290 -3
  36. package/dist/vue/index.js +90 -0
  37. package/dist/vue/useVoiceController.d.ts +11 -0
  38. package/dist/vue/useVoiceStream.d.ts +11 -0
  39. package/package.json +115 -1
@@ -102,6 +102,14 @@ var normalizeErrorMessage = (value) => {
102
102
  };
103
103
  var serverMessageToAction = (message) => {
104
104
  switch (message.type) {
105
+ case "audio":
106
+ return {
107
+ chunk: Uint8Array.from(atob(message.chunkBase64), (char) => char.charCodeAt(0)),
108
+ format: message.format,
109
+ receivedAt: message.receivedAt,
110
+ turnId: message.turnId,
111
+ type: "audio"
112
+ };
105
113
  case "assistant":
106
114
  return {
107
115
  text: message.text,
@@ -182,6 +190,7 @@ var isVoiceServerMessage = (value) => {
182
190
  return false;
183
191
  }
184
192
  switch (value.type) {
193
+ case "audio":
185
194
  case "assistant":
186
195
  case "complete":
187
196
  case "error":
@@ -354,6 +363,7 @@ var createVoiceConnection = (path, options = {}) => {
354
363
 
355
364
  // src/client/store.ts
356
365
  var createInitialState = () => ({
366
+ assistantAudio: [],
357
367
  assistantTexts: [],
358
368
  error: null,
359
369
  isConnected: false,
@@ -371,6 +381,20 @@ var createVoiceStreamStore = () => {
371
381
  };
372
382
  const dispatch = (action) => {
373
383
  switch (action.type) {
384
+ case "audio":
385
+ state = {
386
+ ...state,
387
+ assistantAudio: [
388
+ ...state.assistantAudio,
389
+ {
390
+ chunk: action.chunk,
391
+ format: action.format,
392
+ receivedAt: action.receivedAt,
393
+ turnId: action.turnId
394
+ }
395
+ ]
396
+ };
397
+ break;
374
398
  case "assistant":
375
399
  state = {
376
400
  ...state,
@@ -510,6 +534,9 @@ var createVoiceStream = (path, options = {}) => {
510
534
  get assistantTexts() {
511
535
  return store.getSnapshot().assistantTexts;
512
536
  },
537
+ get assistantAudio() {
538
+ return store.getSnapshot().assistantAudio;
539
+ },
513
540
  sendAudio(audio) {
514
541
  connection.sendAudio(audio);
515
542
  },
@@ -531,6 +558,7 @@ var _init = __decoratorStart(undefined);
531
558
  class VoiceStreamService {
532
559
  connect(path, options = {}) {
533
560
  const stream = createVoiceStream(path, options);
561
+ const assistantAudioSignal = signal([]);
534
562
  const assistantTextsSignal = signal([]);
535
563
  const errorSignal = signal(null);
536
564
  const isConnectedSignal = signal(false);
@@ -539,6 +567,7 @@ class VoiceStreamService {
539
567
  const statusSignal = signal(stream.status);
540
568
  const turnsSignal = signal([]);
541
569
  const sync = () => {
570
+ assistantAudioSignal.set([...stream.assistantAudio]);
542
571
  assistantTextsSignal.set([...stream.assistantTexts]);
543
572
  errorSignal.set(stream.error);
544
573
  isConnectedSignal.set(stream.isConnected);
@@ -550,6 +579,7 @@ class VoiceStreamService {
550
579
  const unsubscribe = stream.subscribe(sync);
551
580
  sync();
552
581
  return {
582
+ assistantAudio: computed(() => assistantAudioSignal()),
553
583
  assistantTexts: computed(() => assistantTextsSignal()),
554
584
  close: () => {
555
585
  unsubscribe();
@@ -938,6 +968,58 @@ var PRESET_INPUTS = {
938
968
  transcriptStabilityMs: 1650
939
969
  }
940
970
  },
971
+ "pstn-balanced": {
972
+ audioConditioning: {
973
+ enabled: true,
974
+ maxGain: 2.8,
975
+ noiseGateAttenuation: 0.07,
976
+ noiseGateThreshold: 0.005,
977
+ targetLevel: 0.08
978
+ },
979
+ capture: {
980
+ channelCount: 1,
981
+ sampleRateHz: 16000
982
+ },
983
+ connection: {
984
+ maxReconnectAttempts: 14,
985
+ pingInterval: 45000,
986
+ reconnect: true
987
+ },
988
+ sttLifecycle: "continuous",
989
+ turnDetection: {
990
+ qualityProfile: "noisy-room",
991
+ profile: "long-form",
992
+ silenceMs: 660,
993
+ speechThreshold: 0.012,
994
+ transcriptStabilityMs: 300
995
+ }
996
+ },
997
+ "pstn-fast": {
998
+ audioConditioning: {
999
+ enabled: true,
1000
+ maxGain: 2.75,
1001
+ noiseGateAttenuation: 0.06,
1002
+ noiseGateThreshold: 0.005,
1003
+ targetLevel: 0.08
1004
+ },
1005
+ capture: {
1006
+ channelCount: 1,
1007
+ sampleRateHz: 16000
1008
+ },
1009
+ connection: {
1010
+ maxReconnectAttempts: 14,
1011
+ pingInterval: 45000,
1012
+ reconnect: true
1013
+ },
1014
+ sttLifecycle: "continuous",
1015
+ turnDetection: {
1016
+ qualityProfile: "noisy-room",
1017
+ profile: "long-form",
1018
+ silenceMs: 620,
1019
+ speechThreshold: 0.012,
1020
+ transcriptStabilityMs: 280
1021
+ }
1022
+ },
941
1023
  reliability: {
942
1024
  audioConditioning: {
943
1025
  enabled: true,
@@ -981,6 +1063,7 @@ var resolveVoiceRuntimePreset = (name = "default") => {
981
1063
 
982
1064
  // src/client/controller.ts
983
1065
  var createInitialState2 = (stream) => ({
1066
+ assistantAudio: [...stream.assistantAudio],
984
1067
  assistantTexts: [...stream.assistantTexts],
985
1068
  error: stream.error,
986
1069
  isConnected: stream.isConnected,
@@ -1009,6 +1092,7 @@ var createVoiceController = (path, options = {}) => {
1009
1092
  const sync = () => {
1010
1093
  state = {
1011
1094
  ...state,
1095
+ assistantAudio: [...stream.assistantAudio],
1012
1096
  assistantTexts: [...stream.assistantTexts],
1013
1097
  error: stream.error,
1014
1098
  isConnected: stream.isConnected,
@@ -1136,6 +1220,9 @@ var createVoiceController = (path, options = {}) => {
1136
1220
  },
1137
1221
  get assistantTexts() {
1138
1222
  return state.assistantTexts;
1223
+ },
1224
+ get assistantAudio() {
1225
+ return state.assistantAudio;
1139
1226
  }
1140
1227
  };
1141
1228
  };
@@ -1149,6 +1236,7 @@ var _init = __decoratorStart(undefined);
1149
1236
  class VoiceControllerService {
1150
1237
  connect(path, options = {}) {
1151
1238
  const controller = createVoiceController(path, options);
1239
+ const assistantAudioSignal = signal2([]);
1152
1240
  const assistantTextsSignal = signal2([]);
1153
1241
  const errorSignal = signal2(null);
1154
1242
  const isConnectedSignal = signal2(false);
@@ -1159,6 +1247,7 @@ class VoiceControllerService {
1159
1247
  const statusSignal = signal2(controller.status);
1160
1248
  const turnsSignal = signal2([]);
1161
1249
  const sync = () => {
1250
+ assistantAudioSignal.set([...controller.assistantAudio]);
1162
1251
  assistantTextsSignal.set([...controller.assistantTexts]);
1163
1252
  errorSignal.set(controller.error);
1164
1253
  isConnectedSignal.set(controller.isConnected);
@@ -1172,6 +1261,7 @@ class VoiceControllerService {
1172
1261
  const unsubscribe = controller.subscribe(sync);
1173
1262
  sync();
1174
1263
  return {
1264
+ assistantAudio: computed2(() => assistantAudioSignal()),
1175
1265
  assistantTexts: computed2(() => assistantTextsSignal()),
1176
1266
  bindHTMX: controller.bindHTMX,
1177
1267
  close: () => {
@@ -1,6 +1,12 @@
1
1
  import type { VoiceControllerOptions, VoiceTurnRecord } from '../types';
2
2
  export declare class VoiceControllerService {
3
3
  connect<TResult = unknown>(path: string, options?: VoiceControllerOptions): {
4
+ assistantAudio: import("@angular/core").Signal<{
5
+ chunk: Uint8Array;
6
+ format: import("..").AudioFormat;
7
+ receivedAt: number;
8
+ turnId?: string;
9
+ }[]>;
4
10
  assistantTexts: import("@angular/core").Signal<string[]>;
5
11
  bindHTMX: (options: import("..").VoiceHTMXBindingOptions) => () => void;
6
12
  close: () => void;
@@ -1,6 +1,12 @@
1
1
  import type { VoiceConnectionOptions, VoiceTurnRecord } from '../types';
2
2
  export declare class VoiceStreamService {
3
3
  connect<TResult = unknown>(path: string, options?: VoiceConnectionOptions): {
4
+ assistantAudio: import("@angular/core").Signal<{
5
+ chunk: Uint8Array;
6
+ format: import("..").AudioFormat;
7
+ receivedAt: number;
8
+ turnId?: string;
9
+ }[]>;
4
10
  assistantTexts: import("@angular/core").Signal<string[]>;
5
11
  close: () => void;
6
12
  endTurn: () => void;
@@ -1,7 +1,24 @@
1
1
  import type { VoiceServerMessage } from '../types';
2
2
  export declare const serverMessageToAction: <TResult = unknown>(message: VoiceServerMessage<TResult>) => {
3
+ chunk: Uint8Array<ArrayBuffer>;
4
+ format: import("..").AudioFormat;
5
+ receivedAt: number;
6
+ turnId: string | undefined;
7
+ type: "audio";
8
+ text?: undefined;
9
+ sessionId?: undefined;
10
+ message?: undefined;
11
+ transcript?: undefined;
12
+ scenarioId?: undefined;
13
+ status?: undefined;
14
+ turn?: undefined;
15
+ } | {
3
16
  text: string;
4
17
  type: "assistant";
18
+ chunk?: undefined;
19
+ format?: undefined;
20
+ receivedAt?: undefined;
21
+ turnId?: undefined;
5
22
  sessionId?: undefined;
6
23
  message?: undefined;
7
24
  transcript?: undefined;
@@ -11,6 +28,10 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
11
28
  } | {
12
29
  sessionId: string;
13
30
  type: "complete";
31
+ chunk?: undefined;
32
+ format?: undefined;
33
+ receivedAt?: undefined;
34
+ turnId?: undefined;
14
35
  text?: undefined;
15
36
  message?: undefined;
16
37
  transcript?: undefined;
@@ -20,6 +41,10 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
20
41
  } | {
21
42
  message: string;
22
43
  type: "error";
44
+ chunk?: undefined;
45
+ format?: undefined;
46
+ receivedAt?: undefined;
47
+ turnId?: undefined;
23
48
  text?: undefined;
24
49
  sessionId?: undefined;
25
50
  transcript?: undefined;
@@ -29,6 +54,10 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
29
54
  } | {
30
55
  transcript: import("..").Transcript;
31
56
  type: "final";
57
+ chunk?: undefined;
58
+ format?: undefined;
59
+ receivedAt?: undefined;
60
+ turnId?: undefined;
32
61
  text?: undefined;
33
62
  sessionId?: undefined;
34
63
  message?: undefined;
@@ -38,6 +67,10 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
38
67
  } | {
39
68
  transcript: import("..").Transcript;
40
69
  type: "partial";
70
+ chunk?: undefined;
71
+ format?: undefined;
72
+ receivedAt?: undefined;
73
+ turnId?: undefined;
41
74
  text?: undefined;
42
75
  sessionId?: undefined;
43
76
  message?: undefined;
@@ -49,6 +82,10 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
49
82
  scenarioId: string | undefined;
50
83
  status: import("..").VoiceSessionStatus;
51
84
  type: "session";
85
+ chunk?: undefined;
86
+ format?: undefined;
87
+ receivedAt?: undefined;
88
+ turnId?: undefined;
52
89
  text?: undefined;
53
90
  message?: undefined;
54
91
  transcript?: undefined;
@@ -56,6 +93,10 @@ export declare const serverMessageToAction: <TResult = unknown>(message: VoiceSe
56
93
  } | {
57
94
  turn: import("..").VoiceTurnRecord<TResult>;
58
95
  type: "turn";
96
+ chunk?: undefined;
97
+ format?: undefined;
98
+ receivedAt?: undefined;
99
+ turnId?: undefined;
59
100
  text?: undefined;
60
101
  sessionId?: undefined;
61
102
  message?: undefined;
@@ -0,0 +1,40 @@
1
+ import type { AudioFormat, VoiceAudioPlayer, VoiceAudioPlayerOptions, VoiceAudioPlayerSource } from '../types';
2
+ type MinimalAudioBuffer = {
3
+ duration: number;
4
+ getChannelData: (channel: number) => Float32Array;
5
+ };
6
+ type MinimalAudioBufferSourceNode = {
7
+ buffer: MinimalAudioBuffer | null;
8
+ connect: (destination: unknown) => void;
9
+ disconnect?: () => void;
10
+ onended: (() => void) | null;
11
+ start: (when?: number) => void;
12
+ stop?: () => void;
13
+ };
14
+ type MinimalGainNode = {
15
+ connect?: (destination: unknown) => void;
16
+ disconnect?: () => void;
17
+ gain: {
18
+ setValueAtTime?: (value: number, time: number) => void;
19
+ value: number;
20
+ };
21
+ };
22
+ type MinimalAudioContext = {
23
+ baseLatency?: number;
24
+ close: () => Promise<void>;
25
+ createBuffer: (numberOfChannels: number, length: number, sampleRate: number) => MinimalAudioBuffer;
26
+ createBufferSource: () => MinimalAudioBufferSourceNode;
27
+ createGain?: () => MinimalGainNode;
28
+ currentTime: number;
29
+ destination: unknown;
30
+ outputLatency?: number;
31
+ resume: () => Promise<void>;
32
+ state: 'closed' | 'running' | 'suspended';
33
+ suspend: () => Promise<void>;
34
+ };
35
+ export declare const createVoiceAudioPlayer: (source: VoiceAudioPlayerSource, options?: VoiceAudioPlayerOptions) => VoiceAudioPlayer;
36
+ export declare const decodeVoiceAudioChunk: (audioContext: Pick<MinimalAudioContext, "createBuffer">, chunk: {
37
+ chunk: Uint8Array;
38
+ format: AudioFormat;
39
+ }) => MinimalAudioBuffer;
40
+ export {};
@@ -0,0 +1,3 @@
1
+ import type { VoiceAudioPlayer, VoiceBargeInBinding, VoiceBargeInOptions, VoiceController, VoiceDuplexController, VoiceDuplexControllerOptions } from '../types';
2
+ export declare const bindVoiceBargeIn: <TResult = unknown>(controller: Pick<VoiceController<TResult>, "partial" | "sendAudio" | "subscribe">, player: Pick<VoiceAudioPlayer, "interrupt" | "isPlaying">, options?: VoiceBargeInOptions) => VoiceBargeInBinding;
3
+ export declare const createVoiceDuplexController: <TResult = unknown>(path: string, options?: VoiceDuplexControllerOptions) => VoiceDuplexController<TResult>;
@@ -170,6 +170,14 @@ var normalizeErrorMessage = (value) => {
170
170
  };
171
171
  var serverMessageToAction = (message) => {
172
172
  switch (message.type) {
173
+ case "audio":
174
+ return {
175
+ chunk: Uint8Array.from(atob(message.chunkBase64), (char) => char.charCodeAt(0)),
176
+ format: message.format,
177
+ receivedAt: message.receivedAt,
178
+ turnId: message.turnId,
179
+ type: "audio"
180
+ };
173
181
  case "assistant":
174
182
  return {
175
183
  text: message.text,
@@ -250,6 +258,7 @@ var isVoiceServerMessage = (value) => {
250
258
  return false;
251
259
  }
252
260
  switch (value.type) {
261
+ case "audio":
253
262
  case "assistant":
254
263
  case "complete":
255
264
  case "error":
@@ -422,6 +431,7 @@ var createVoiceConnection = (path, options = {}) => {
422
431
 
423
432
  // src/client/store.ts
424
433
  var createInitialState = () => ({
434
+ assistantAudio: [],
425
435
  assistantTexts: [],
426
436
  error: null,
427
437
  isConnected: false,
@@ -439,6 +449,20 @@ var createVoiceStreamStore = () => {
439
449
  };
440
450
  const dispatch = (action) => {
441
451
  switch (action.type) {
452
+ case "audio":
453
+ state = {
454
+ ...state,
455
+ assistantAudio: [
456
+ ...state.assistantAudio,
457
+ {
458
+ chunk: action.chunk,
459
+ format: action.format,
460
+ receivedAt: action.receivedAt,
461
+ turnId: action.turnId
462
+ }
463
+ ]
464
+ };
465
+ break;
442
466
  case "assistant":
443
467
  state = {
444
468
  ...state,
@@ -578,6 +602,9 @@ var createVoiceStream = (path, options = {}) => {
578
602
  get assistantTexts() {
579
603
  return store.getSnapshot().assistantTexts;
580
604
  },
605
+ get assistantAudio() {
606
+ return store.getSnapshot().assistantAudio;
607
+ },
581
608
  sendAudio(audio) {
582
609
  connection.sendAudio(audio);
583
610
  },
@@ -776,6 +803,58 @@ var PRESET_INPUTS = {
776
803
  transcriptStabilityMs: 1650
777
804
  }
778
805
  },
806
+ "pstn-balanced": {
807
+ audioConditioning: {
808
+ enabled: true,
809
+ maxGain: 2.8,
810
+ noiseGateAttenuation: 0.07,
811
+ noiseGateThreshold: 0.005,
812
+ targetLevel: 0.08
813
+ },
814
+ capture: {
815
+ channelCount: 1,
816
+ sampleRateHz: 16000
817
+ },
818
+ connection: {
819
+ maxReconnectAttempts: 14,
820
+ pingInterval: 45000,
821
+ reconnect: true
822
+ },
823
+ sttLifecycle: "continuous",
824
+ turnDetection: {
825
+ qualityProfile: "noisy-room",
826
+ profile: "long-form",
827
+ silenceMs: 660,
828
+ speechThreshold: 0.012,
829
+ transcriptStabilityMs: 300
830
+ }
831
+ },
832
+ "pstn-fast": {
833
+ audioConditioning: {
834
+ enabled: true,
835
+ maxGain: 2.75,
836
+ noiseGateAttenuation: 0.06,
837
+ noiseGateThreshold: 0.005,
838
+ targetLevel: 0.08
839
+ },
840
+ capture: {
841
+ channelCount: 1,
842
+ sampleRateHz: 16000
843
+ },
844
+ connection: {
845
+ maxReconnectAttempts: 14,
846
+ pingInterval: 45000,
847
+ reconnect: true
848
+ },
849
+ sttLifecycle: "continuous",
850
+ turnDetection: {
851
+ qualityProfile: "noisy-room",
852
+ profile: "long-form",
853
+ silenceMs: 620,
854
+ speechThreshold: 0.012,
855
+ transcriptStabilityMs: 280
856
+ }
857
+ },
779
858
  reliability: {
780
859
  audioConditioning: {
781
860
  enabled: true,
@@ -819,6 +898,7 @@ var resolveVoiceRuntimePreset = (name = "default") => {
819
898
 
820
899
  // src/client/controller.ts
821
900
  var createInitialState2 = (stream) => ({
901
+ assistantAudio: [...stream.assistantAudio],
822
902
  assistantTexts: [...stream.assistantTexts],
823
903
  error: stream.error,
824
904
  isConnected: stream.isConnected,
@@ -847,6 +927,7 @@ var createVoiceController = (path, options = {}) => {
847
927
  const sync = () => {
848
928
  state = {
849
929
  ...state,
930
+ assistantAudio: [...stream.assistantAudio],
850
931
  assistantTexts: [...stream.assistantTexts],
851
932
  error: stream.error,
852
933
  isConnected: stream.isConnected,
@@ -974,6 +1055,9 @@ var createVoiceController = (path, options = {}) => {
974
1055
  },
975
1056
  get assistantTexts() {
976
1057
  return state.assistantTexts;
1058
+ },
1059
+ get assistantAudio() {
1060
+ return state.assistantAudio;
977
1061
  }
978
1062
  };
979
1063
  };
@@ -1,5 +1,7 @@
1
1
  export { createVoiceConnection } from './connection';
2
+ export { createVoiceAudioPlayer, decodeVoiceAudioChunk } from './audioPlayer';
2
3
  export { createVoiceStream } from './createVoiceStream';
3
4
  export { createVoiceController } from './controller';
5
+ export { bindVoiceBargeIn, createVoiceDuplexController } from './duplex';
4
6
  export { bindVoiceHTMX } from './htmx';
5
7
  export { createMicrophoneCapture } from './microphone';