@onereach/step-voice 6.1.22-VOIC1406.8 → 6.1.26-VOIC1449.10

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/dst/Choice.js CHANGED
@@ -97,19 +97,13 @@ class Choice extends voice_1.default {
97
97
  // There's a specific need to do so. There might be ${variable} section
98
98
  this.triggers.local(`in/voice/${call.id}`, async (event) => {
99
99
  const reportingSettingsKey = this.rptsStarted ? 'transcriptRepromptResponse' : 'transcriptResponse';
100
- const interruptionMetadata = event.params.interruptionMetadata ?? null;
101
- if (interruptionMetadata) {
102
- await this.transcript(call, {
103
- sections: speechSections,
104
- reprompt: {
105
- maxAttempts: repromptsList.length,
106
- attempt: 0
107
- },
108
- reportingSettingsKey: 'transcriptPrompt',
109
- action: 'Call Prompt',
110
- actionFromBot: true
111
- }, interruptionMetadata);
112
- }
100
+ await this.handleInterruption({
101
+ call,
102
+ event,
103
+ speechSections,
104
+ repromptsList,
105
+ reportingSettingsKey
106
+ });
113
107
  switch (event.params.type) {
114
108
  case 'digit':
115
109
  case 'digits': {
@@ -279,4 +273,3 @@ class Choice extends voice_1.default {
279
273
  }
280
274
  }
281
275
  exports.default = Choice;
282
- // --------------------------------------------------------------------
@@ -88,6 +88,13 @@ class CustomVoiceInput extends voice_1.default {
88
88
  // There's a specific need to do so. There might be ${variable} section
89
89
  this.triggers.local(`in/voice/${call.id}`, async (event) => {
90
90
  const reportingSettingsKey = this.rptsStarted ? 'transcriptRepromptResponse' : 'transcriptResponse';
91
+ await this.handleInterruption({
92
+ call,
93
+ event,
94
+ speechSections,
95
+ repromptsList,
96
+ reportingSettingsKey
97
+ });
91
98
  switch (event.params.type) {
92
99
  // digit recognition removed
93
100
  case 'recognition': {
@@ -191,7 +198,7 @@ class CustomVoiceInput extends voice_1.default {
191
198
  }
192
199
  });
193
200
  this.triggers.otherwise(async () => {
194
- await this.transcript(call, {
201
+ const eventId = await this.transcript(call, {
195
202
  sections: speechSections,
196
203
  reprompt: {
197
204
  maxAttempts: repromptsList.length,
@@ -201,6 +208,7 @@ class CustomVoiceInput extends voice_1.default {
201
208
  action: 'Call Prompt',
202
209
  actionFromBot: true
203
210
  });
211
+ command.params.reporterTranscriptEventId = eventId;
204
212
  command.params.sections = speechSections;
205
213
  command.params.timeout = this.rptsTimeout({ noReplyDelay, repromptsList, initial: true });
206
214
  await this.pauseRecording(call, command, sensitiveData);
@@ -70,6 +70,13 @@ class KeypadInput extends voice_1.default {
70
70
  const speechSections = this.buildSections({ sections: this.data.audio, textType, ttsSettings, allowKeypadBargeIn: keypadBargeIn });
71
71
  this.triggers.local(`in/voice/${call.id}`, async (event) => {
72
72
  const reportingSettingsKey = this.rptsStarted ? 'transcriptRepromptResponse' : 'transcriptResponse';
73
+ await this.handleInterruption({
74
+ call,
75
+ event,
76
+ speechSections,
77
+ repromptsList,
78
+ reportingSettingsKey
79
+ });
73
80
  switch (event.params.type) {
74
81
  case 'digits': {
75
82
  const digits = event.params.digits;
@@ -162,7 +169,7 @@ class KeypadInput extends voice_1.default {
162
169
  }
163
170
  });
164
171
  this.triggers.otherwise(async () => {
165
- await this.transcript(call, {
172
+ const eventId = await this.transcript(call, {
166
173
  sections: speechSections,
167
174
  reprompt: {
168
175
  maxAttempts: repromptsList.length,
@@ -172,6 +179,7 @@ class KeypadInput extends voice_1.default {
172
179
  action: 'Call Prompt',
173
180
  actionFromBot: true
174
181
  });
182
+ command.params.reporterTranscriptEventId = eventId;
175
183
  command.params.firstDigitTimeout = this.rptsTimeout({ noReplyDelay, repromptsList, initial: true });
176
184
  command.params.sections = speechSections;
177
185
  await this.pauseRecording(call, command, sensitiveData);
@@ -19,15 +19,11 @@ class SayMessage extends voice_1.default {
19
19
  ...ttsSettings
20
20
  }));
21
21
  this.triggers.local(`in/voice/${call.id}`, async (event) => {
22
- const interruptionMetadata = event.params.interruptionMetadata ?? null;
23
- if (interruptionMetadata) {
24
- await this.transcript(call, {
25
- action: 'Call Prompt',
26
- sections: speechSections,
27
- reportingSettingsKey: 'transcript',
28
- actionFromBot: true
29
- }, interruptionMetadata);
30
- }
22
+ await this.handleInterruption({
23
+ call,
24
+ event,
25
+ speechSections
26
+ });
31
27
  switch (event.params.type) {
32
28
  case 'hangup':
33
29
  await this.handleHangup(call);
@@ -48,15 +44,17 @@ class SayMessage extends voice_1.default {
48
44
  const command = {
49
45
  name: 'speak',
50
46
  params: {
51
- sections: speechSections
47
+ sections: speechSections,
48
+ reporterTranscriptEventId: ''
52
49
  }
53
50
  };
54
- await this.transcript(call, {
51
+ const eventId = await this.transcript(call, {
55
52
  action: 'Call Prompt',
56
53
  sections: command.params.sections,
57
54
  reportingSettingsKey: 'transcript',
58
55
  actionFromBot: true
59
56
  });
57
+ command.params.reporterTranscriptEventId = eventId;
60
58
  await this.pauseRecording(call, command, sensitiveData);
61
59
  return this.exitFlow();
62
60
  });
package/dst/Transfer.js CHANGED
@@ -77,6 +77,11 @@ class Transfer extends voice_1.default {
77
77
  timeout
78
78
  }
79
79
  };
80
+ console.log('transfer otherwise', {
81
+ data: { ...this.data },
82
+ headers,
83
+ command
84
+ });
80
85
  const muteAfterTransfer = !!muteRecording;
81
86
  await this.pauseRecording(call, command, { muteStep: muteAfterTransfer, muteBot: muteAfterTransfer, muteUser: muteAfterTransfer });
82
87
  await this.transcript(call, {
@@ -8,6 +8,7 @@ interface INPUT {
8
8
  recordDurationSeconds: string;
9
9
  isTerminateOnSilence: boolean;
10
10
  silenceHits: string;
11
+ disableDefaultBeepSound: boolean;
11
12
  }
12
13
  interface EVENT extends VoiceEvent {
13
14
  mediaPath: string;
@@ -9,12 +9,13 @@ class Recording extends voice_1.default {
9
9
  const { tts, sensitiveData, textType } = this.data;
10
10
  const ttsSettings = tts.getSettings(call.tts);
11
11
  const sections = this.buildSections({ sections: this.data.audio, textType, ttsSettings });
12
- sections.push({
13
- // TODO make this configurable?
14
- url: 'https://bot-service-recordings.s3.us-west-2.amazonaws.com/beep_sound.wav',
15
- bargeInVoice: false,
16
- bargeInKeypad: false
17
- });
12
+ if (!this.data?.disableDefaultBeepSound) {
13
+ sections.push({
14
+ url: 'https://bot-service-recordings.s3.us-west-2.amazonaws.com/beep_sound.wav',
15
+ bargeInVoice: false,
16
+ bargeInKeypad: false
17
+ });
18
+ }
18
19
  const command = {
19
20
  name: 'start-record',
20
21
  params: {
@@ -24,11 +25,18 @@ class Recording extends voice_1.default {
24
25
  terminator: this.data.terminationKey
25
26
  }),
26
27
  duration: parseInt(this.data.recordDurationSeconds),
27
- sections
28
+ sections,
29
+ reporterTranscriptEventId: ''
28
30
  }
29
31
  };
30
32
  this.triggers.local(`in/voice/${call.id}`, async (event) => {
31
33
  const url = event.params.mediaPath;
34
+ await this.handleInterruption({
35
+ call,
36
+ event,
37
+ speechSections: sections,
38
+ reportingSettingsKey: 'transcriptPrompt'
39
+ });
32
40
  switch (event.params.type) {
33
41
  case 'hangup':
34
42
  // TODO do we need zombie?
@@ -65,12 +73,13 @@ class Recording extends voice_1.default {
65
73
  this.triggers.otherwise(async () => {
66
74
  // TODO figure out Global Command compatibility
67
75
  lodash_1.default.set(this.state.hooks, 'skipVoiceEventTypes', ['hangup']);
68
- await this.transcript(call, {
76
+ const eventId = await this.transcript(call, {
69
77
  sections,
70
78
  reportingSettingsKey: 'transcriptPrompt',
71
79
  action: 'Call Prompt',
72
80
  actionFromBot: true
73
81
  });
82
+ command.params.reporterTranscriptEventId = eventId;
74
83
  await this.pauseRecording(call, command, sensitiveData);
75
84
  return this.exitFlow();
76
85
  });
@@ -23,6 +23,8 @@ class WaitForCall extends voice_1.default {
23
23
  }
24
24
  async onCall(event) {
25
25
  const { asr, tts, endOfInputTimeout } = this.data;
26
+ this.log.debug('ON_CALL_X', event);
27
+ console.log('ON_CALL_X', { event });
26
28
  const call = {
27
29
  headers: event.params.headers,
28
30
  // @ts-expect-error
@@ -36,13 +38,20 @@ class WaitForCall extends voice_1.default {
36
38
  delete call.from;
37
39
  delete call.to;
38
40
  const presetTime = (Number(endOfInputTimeout) || 0) * 60 * 1000;
41
+ const { sessionId: previousSessionId = '', beginningSessionId = '', } = event?.reporting ?? {};
39
42
  await this.session.start({
40
43
  timeout: presetTime || defaultSessionTimeout,
41
44
  reporting: {
42
45
  settingsKey: 'session',
43
46
  startedBy: 'Visitor',
44
- sessionType: 'Phone'
45
- }
47
+ sessionType: 'Phone',
48
+ previousSessionId,
49
+ beginningSessionId
50
+ },
51
+ reportingSessions: [{
52
+ previousSessionId,
53
+ beginningSessionId
54
+ }]
46
55
  });
47
56
  await this.startConversation(call);
48
57
  await this.transcript(call, {
package/dst/voice.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ICallback, IVoiceReporterTranscriptEventArgs, IPromtpSection } from '@onereach/flow-sdk/dst/types';
1
+ import { ICallback, IVoiceReporterTranscriptEventArgs, IPromtpSection, ITypedEvent } from '@onereach/flow-sdk/dst/types';
2
2
  import ConvStep, { IConversationData } from './step';
3
3
  import BasicError from '@onereach/flow-sdk/dst/errors/base';
4
4
  export type TODO = any;
@@ -54,12 +54,25 @@ export interface VoiceEvent {
54
54
  type: EventType;
55
55
  global?: boolean;
56
56
  error?: VoicerError;
57
- interruptionMetadata: VoiceInterruptionMetadata;
57
+ interruptionMetadata?: VoiceInterruptionMetadata;
58
+ result?: {
59
+ interruptionMetadata?: VoiceInterruptionMetadata;
60
+ };
58
61
  }
59
62
  export interface CallStartEvent extends VoiceEvent {
60
63
  channel: IVoiceCall;
61
64
  headers?: Record<string, string>;
62
65
  }
66
+ export interface HandleInterruptionParams<TParams extends VoiceEvent = VoiceEvent> {
67
+ call: IVoiceCall;
68
+ event: ITypedEvent<TParams>;
69
+ speechSections: IPromtpSection[];
70
+ repromptsList?: {
71
+ message?: string;
72
+ fileName?: string;
73
+ }[];
74
+ reportingSettingsKey?: string;
75
+ }
63
76
  export default class VoiceStep<TIn = unknown, TOut = unknown, TParams extends VoiceEvent = VoiceEvent> extends ConvStep<IVoiceCall, TIn & {
64
77
  handleCancel?: boolean;
65
78
  }, TOut, TParams> {
@@ -94,4 +107,6 @@ export default class VoiceStep<TIn = unknown, TOut = unknown, TParams extends Vo
94
107
  get rptsStarted(): boolean;
95
108
  canVoicerHearbeat(call: IVoiceCall): boolean;
96
109
  canVoicerAck(call: IVoiceCall): boolean;
110
+ getInterruptionMetadata(event: ITypedEvent<TParams>): VoiceInterruptionMetadata | null;
111
+ handleInterruption(params: HandleInterruptionParams<TParams>): Promise<void>;
97
112
  }
package/dst/voice.js CHANGED
@@ -63,7 +63,10 @@ class VoiceStep extends step_1.default {
63
63
  commands,
64
64
  step: { key: this.session.key, trd: this.isGlobal ? this.workerThreadId : this.thread.id } // response should be sent to this session
65
65
  },
66
- reporting: this.session.getSessionRef()
66
+ reporting: {
67
+ ...this.session.getSessionRef(),
68
+ beginningSessionId: 'd75d278c-0846-48e7-8615-46c8d75d3ade'
69
+ }
67
70
  }, {
68
71
  target: callback,
69
72
  invocationType: 'async',
@@ -104,22 +107,26 @@ class VoiceStep extends step_1.default {
104
107
  this.end();
105
108
  }
106
109
  extractSectionMessages(sections, interruptionMetadata) {
107
- return lodash_1.default.chain(sections)
108
- .filter(s => Boolean(s.text))
110
+ const { sectionIndex } = interruptionMetadata ?? {};
111
+ const slicedTo = sectionIndex != null ? sectionIndex + 1 : sections.length;
112
+ return sections
113
+ .slice(0, slicedTo)
109
114
  .map((s, index) => {
110
115
  // Should escape html, max length 4000 symbols
111
- let text = s.text?.slice(0, 4000).replace(/(<[^>]+>|<\/[^>]+>)/gi, ' ') ?? '';
116
+ let text = (s.text ?? '')
117
+ .slice(0, 4000)
118
+ .replace(/(<[^>]+>|<\/[^>]+>)/gi, ' ')
119
+ .trim();
112
120
  // Extracts the portion of the section text that corresponds to the played time.
113
121
  if (interruptionMetadata) {
114
- const { playedTime, sectionDuration, sectionIndex } = interruptionMetadata;
122
+ const { playedTime, sectionDuration } = interruptionMetadata;
115
123
  if (sectionIndex === index) {
116
124
  text = this.extractPlayedSectionMessage(text, sectionDuration, playedTime);
117
125
  }
118
126
  }
119
127
  return text;
120
128
  })
121
- .join(' ')
122
- .value();
129
+ .join(' ');
123
130
  }
124
131
  extractPlayedSectionMessage(text, sectionDuration, playedTime) {
125
132
  const words = text.split(' ');
@@ -128,7 +135,7 @@ class VoiceStep extends step_1.default {
128
135
  const playedTimeSec = playedTime / 1000;
129
136
  const wordsPerSecond = totalWords / sectionDurationSec;
130
137
  const wordsPlayed = Math.floor(wordsPerSecond * playedTimeSec);
131
- return words.slice(0, wordsPlayed).join(' ');
138
+ return words.slice(0, wordsPlayed).join(' ').trim();
132
139
  }
133
140
  extractSectionFiles(sections) {
134
141
  return lodash_1.default.chain(sections)
@@ -217,19 +224,25 @@ class VoiceStep extends step_1.default {
217
224
  * which was returned from the interrupted message,
218
225
  * try to update the reporting message.
219
226
  */
220
- if (interruptionMetadata?.reporterTranscriptEventId) {
227
+ if (interruptionMetadata?.reporterTranscriptEventId &&
228
+ reportingObject.message) {
229
+ const updateReportingObject = {
230
+ EventId: eventId,
231
+ Timestamp: new Date().toISOString(),
232
+ Event: 'Augment',
233
+ EventValue: {
234
+ eventId: interruptionMetadata.reporterTranscriptEventId,
235
+ eventValue: {
236
+ Message: reportingObject.message,
237
+ },
238
+ },
239
+ };
240
+ this.log.debug(`Augment Transcript`, {
241
+ interruptionMetadata,
242
+ updateReportingObject,
243
+ shouldBeSendToHitl: this.process.cache.hitl != null,
244
+ });
221
245
  if (this.process.cache.hitl) {
222
- const updateReportingObject = {
223
- EventId: eventId,
224
- Timestamp: new Date().toISOString(),
225
- Event: 'Augment',
226
- EventValue: {
227
- eventId: interruptionMetadata.reporterTranscriptEventId,
228
- eventValue: {
229
- Message: reportingObject.message,
230
- }
231
- }
232
- };
233
246
  await this.process.cache.hitl.queueEvents([updateReportingObject]);
234
247
  }
235
248
  }
@@ -366,7 +379,8 @@ class VoiceStep extends step_1.default {
366
379
  if (reporting) {
367
380
  lodash_1.default.assign(reportingObject, reporting);
368
381
  }
369
- await this.transcript(call, reportingObject);
382
+ const eventId = await this.transcript(call, reportingObject);
383
+ params.reporterTranscriptEventId = eventId;
370
384
  if (call.vv >= 2)
371
385
  await this.pauseRecording(call, command, sensitiveData);
372
386
  else
@@ -394,6 +408,35 @@ class VoiceStep extends step_1.default {
394
408
  canVoicerAck(call) {
395
409
  return call.vv >= 2;
396
410
  }
411
+ getInterruptionMetadata(event) {
412
+ return event.params?.interruptionMetadata
413
+ ?? event.params?.result?.interruptionMetadata
414
+ ?? null;
415
+ }
416
+ async handleInterruption(params) {
417
+ const { call, event, speechSections, repromptsList = [], reportingSettingsKey = 'transcript' } = params;
418
+ const interruptionMetadata = this.getInterruptionMetadata(event);
419
+ this.log.debug('handleInterruption', { event, speechSections, repromptsList });
420
+ if (!interruptionMetadata)
421
+ return;
422
+ const sections = [];
423
+ if (repromptsList.length && reportingSettingsKey === 'transcriptRepromptResponse') {
424
+ const current = repromptsList[this.rptsIndex - 1];
425
+ sections.push({
426
+ url: current?.fileName,
427
+ text: current?.message,
428
+ });
429
+ }
430
+ else {
431
+ sections.push(...speechSections);
432
+ }
433
+ await this.transcript(call, {
434
+ action: 'Call Prompt',
435
+ actionFromBot: true,
436
+ sections,
437
+ reportingSettingsKey,
438
+ }, interruptionMetadata);
439
+ }
397
440
  }
398
441
  exports.default = VoiceStep;
399
442
  module.exports = VoiceStep;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onereach/step-voice",
3
- "version": "6.1.22-VOIC1406.8",
3
+ "version": "6.1.26-VOIC1449.10",
4
4
  "author": "Roman Zolotarov <roman.zolotarov@onereach.com>",
5
5
  "contributors": [
6
6
  "Roman Zolotarov",
@@ -9,8 +9,8 @@
9
9
  "description": "Onereach.ai Voice Steps",
10
10
  "main": "index.js",
11
11
  "engines": {
12
- "node": ">= 8.9.0",
13
- "npm": ">= 6.0.0"
12
+ "node": ">= 20",
13
+ "npm": ">= 10"
14
14
  },
15
15
  "dependencies": {
16
16
  "@onereach/step-conversation": "^1.0.40",
@@ -54,8 +54,9 @@
54
54
  "download": "./scripts/download.sh",
55
55
  "upload": "./scripts/upload.sh",
56
56
  "pub": "./scripts/publish.sh",
57
- "pub-beta": "./scripts/publish-beta.sh",
57
+ "pub-prerelease": "./scripts/publish-prerelease.sh",
58
58
  "update-module-versions": "./scripts/update-module-versions.sh",
59
+ "patch-steps": "./scripts/update-steps-versions.sh patch",
59
60
  "test": "jest --forceExit"
60
61
  },
61
62
  "repository": {