@onereach/step-voice 6.1.16-changegrammarstructure.0 → 6.1.17-test.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.
package/dst/Choice.js CHANGED
@@ -81,7 +81,7 @@ class Choice extends voice_1.default {
81
81
  const grammar = {
82
82
  id: this.currentStepId,
83
83
  choices,
84
- asrSettings
84
+ asr: asrSettings
85
85
  };
86
86
  const command = {
87
87
  name: 'speak',
@@ -97,6 +97,19 @@ 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
113
  switch (event.params.type) {
101
114
  case 'digit':
102
115
  case 'digits': {
@@ -105,9 +118,11 @@ class Choice extends voice_1.default {
105
118
  const exitId = params.exitId;
106
119
  // On bargeIn, we should stop playback
107
120
  if (exitExists(exitId)) {
121
+ const exitStepLabel = this.getExitStepLabel(exitId) ?? '';
122
+ const message = lodash_1.default.replace(exitStepLabel, /^(\d+\. )?(~ )?/, '');
108
123
  await this.transcript(call, {
109
124
  keyPress: digit,
110
- message: lodash_1.default.replace(this.getExitStepLabel(exitId) ?? '', /^(\d+\. )?(~ )?/, ''),
125
+ message: message,
111
126
  reportingSettingsKey,
112
127
  action: 'Call DTMF',
113
128
  actionFromBot: false
@@ -245,7 +260,7 @@ class Choice extends voice_1.default {
245
260
  }
246
261
  });
247
262
  this.triggers.otherwise(async () => {
248
- await this.transcript(call, {
263
+ const eventId = await this.transcript(call, {
249
264
  sections: speechSections,
250
265
  reprompt: {
251
266
  maxAttempts: repromptsList.length,
@@ -255,6 +270,7 @@ class Choice extends voice_1.default {
255
270
  action: 'Call Prompt',
256
271
  actionFromBot: true
257
272
  });
273
+ command.params.reporterTranscriptEventId = eventId;
258
274
  command.params.sections = speechSections;
259
275
  command.params.timeout = this.rptsTimeout({ noReplyDelay, repromptsList, initial: true });
260
276
  await this.pauseRecording(call, command, sensitiveData);
@@ -74,7 +74,7 @@ class CustomVoiceInput extends voice_1.default {
74
74
  const grammar = {
75
75
  id: this.currentStepId,
76
76
  choices,
77
- asrSettings
77
+ asr: asrSettings
78
78
  };
79
79
  const command = {
80
80
  name: 'double-asr',
@@ -331,7 +331,7 @@ class GlobalCommand extends voice_1.default {
331
331
  return {
332
332
  id: this.currentStepId,
333
333
  choices,
334
- asrSettings: asr.getSettings(call.asr)
334
+ asr: asr.getSettings(call.asr)
335
335
  };
336
336
  }
337
337
  acceptAck(eventParams) {
@@ -34,7 +34,7 @@ class KeypadInput extends voice_1.default {
34
34
  const asrSettings = asr.getSettings(call.asr);
35
35
  const grammar = {
36
36
  id: this.currentStepId,
37
- asrSettings: {
37
+ asr: {
38
38
  ...asrSettings,
39
39
  config: {
40
40
  version: 'v1beta',
@@ -8,7 +8,26 @@ class SayMessage extends voice_1.default {
8
8
  async runStep() {
9
9
  const { audio, textType, tts, sensitiveData } = this.data;
10
10
  const call = await this.fetchData();
11
+ const speechSections = lodash_1.default.map(audio, (section) => ({
12
+ text: section.voiceTextMsg,
13
+ url: section.audioUrl,
14
+ bargeInVoice: false,
15
+ bargeInKeypad: false,
16
+ textType,
17
+ provider: ttsSettings.provider,
18
+ ...ttsSettings
19
+ }));
20
+ const ttsSettings = tts.getSettings(call.tts);
11
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
+ }
12
31
  switch (event.params.type) {
13
32
  case 'hangup':
14
33
  await this.handleHangup(call);
@@ -26,19 +45,10 @@ class SayMessage extends voice_1.default {
26
45
  }
27
46
  });
28
47
  this.triggers.otherwise(async () => {
29
- const ttsSettings = tts.getSettings(call.tts);
30
48
  const command = {
31
49
  name: 'speak',
32
50
  params: {
33
- sections: lodash_1.default.map(audio, (section) => ({
34
- text: section.voiceTextMsg,
35
- url: section.audioUrl,
36
- bargeInVoice: false,
37
- bargeInKeypad: false,
38
- textType,
39
- provider: ttsSettings.provider,
40
- ...ttsSettings
41
- }))
51
+ sections: speechSections
42
52
  }
43
53
  };
44
54
  await this.transcript(call, {
package/dst/voice.d.ts CHANGED
@@ -42,10 +42,19 @@ export type VoicerError = Error & {
42
42
  date?: never;
43
43
  originateStatus?: never;
44
44
  };
45
+ export interface VoiceInterruptionMetadata {
46
+ interruptionReason: 'keypad' | 'voice';
47
+ interruptionTime: number;
48
+ playedTime: number;
49
+ sectionIndex: number;
50
+ sectionDuration: number;
51
+ reporterTranscriptEventId: string;
52
+ }
45
53
  export interface VoiceEvent {
46
54
  type: EventType;
47
55
  global?: boolean;
48
56
  error?: VoicerError;
57
+ interruptionMetadata: VoiceInterruptionMetadata;
49
58
  }
50
59
  export interface CallStartEvent extends VoiceEvent {
51
60
  channel: IVoiceCall;
@@ -61,14 +70,15 @@ export default class VoiceStep<TIn = unknown, TOut = unknown, TParams extends Vo
61
70
  sendCommands({ id, type, callback }: IVoiceCall, commands: TODO[]): Promise<void>;
62
71
  handleHeartbeat(call: IVoiceCall): Promise<void>;
63
72
  handleCancel(): void;
64
- extractSectionMessages(sections: IPromtpSection[]): string;
73
+ extractSectionMessages(sections: IPromtpSection[], interruptionMetadata?: VoiceInterruptionMetadata): string;
74
+ extractPlayedSectionMessage(text: string, sectionDuration: number, playedTime: number): string;
65
75
  extractSectionFiles(sections: IPromtpSection[]): Array<{
66
76
  fileUrl: string;
67
77
  fileType: string;
68
78
  }>;
69
79
  pauseRecording(call: IVoiceCall, command: any, sensitiveData?: SensitiveData): Promise<void>;
70
80
  resumeRecording(call: IVoiceCall, sensitiveData?: SensitiveData): Promise<void>;
71
- transcript(call: IVoiceCall, data?: Partial<IVoiceReporterTranscriptEventArgs>): Promise<string>;
81
+ transcript(call: IVoiceCall, data?: Partial<IVoiceReporterTranscriptEventArgs>, interruptionMetadata?: VoiceInterruptionMetadata): Promise<string>;
72
82
  throwError(error?: VoicerError): never;
73
83
  handleHangup(call: IVoiceCall): Promise<void>;
74
84
  buildSections({ sections, textType, ttsSettings, allowKeypadBargeIn }: TODO): TODO;
package/dst/voice.js CHANGED
@@ -103,16 +103,33 @@ class VoiceStep extends step_1.default {
103
103
  else
104
104
  this.end();
105
105
  }
106
- extractSectionMessages(sections) {
106
+ extractSectionMessages(sections, interruptionMetadata) {
107
107
  return lodash_1.default.chain(sections)
108
108
  .filter(s => Boolean(s.text))
109
- .map(s => {
109
+ .map((s, index) => {
110
110
  // Should escape html, max length 4000 symbols
111
- return s.text?.slice(0, 4000).replace(/(<[^>]+>|<\/[^>]+>)/gi, ' ');
111
+ let text = s.text?.slice(0, 4000).replace(/(<[^>]+>|<\/[^>]+>)/gi, ' ') ?? '';
112
+ // Extracts the portion of the section text that corresponds to the played time.
113
+ if (interruptionMetadata) {
114
+ const { playedTime, sectionDuration, sectionIndex } = interruptionMetadata;
115
+ if (sectionIndex === index) {
116
+ text = this.extractPlayedSectionMessage(text, sectionDuration, playedTime);
117
+ }
118
+ }
119
+ return text;
112
120
  })
113
121
  .join(' ')
114
122
  .value();
115
123
  }
124
+ extractPlayedSectionMessage(text, sectionDuration, playedTime) {
125
+ const words = text.split(' ');
126
+ const totalWords = words.length;
127
+ const sectionDurationSec = sectionDuration / 1000;
128
+ const playedTimeSec = playedTime / 1000;
129
+ const wordsPerSecond = totalWords / sectionDurationSec;
130
+ const wordsPlayed = Math.floor(wordsPerSecond * playedTimeSec);
131
+ return words.slice(0, wordsPlayed).join(' ');
132
+ }
116
133
  extractSectionFiles(sections) {
117
134
  return lodash_1.default.chain(sections)
118
135
  .filter(s => Boolean(s.url))
@@ -151,7 +168,7 @@ class VoiceStep extends step_1.default {
151
168
  }
152
169
  }]);
153
170
  }
154
- async transcript(call, data = {}) {
171
+ async transcript(call, data = {}, interruptionMetadata) {
155
172
  const { previousTranscriptId = call.lastTranscriptId, action, keyPress, message, voiceProcessResult, reportingSettingsKey, sections, reprompt, recording, conferenceId, actionFromBot = false } = data;
156
173
  const eventId = (0, uuid_1.v4)();
157
174
  const fromIdentifier = actionFromBot ? call.botNumber : call.endUserNumber;
@@ -175,7 +192,7 @@ class VoiceStep extends step_1.default {
175
192
  eventId
176
193
  };
177
194
  if (sections != null) {
178
- const allMessages = this.extractSectionMessages(sections);
195
+ const allMessages = this.extractSectionMessages(sections, interruptionMetadata);
179
196
  const allFiles = this.extractSectionFiles(sections);
180
197
  if (!lodash_1.default.isEmpty(allMessages))
181
198
  reportingObject.message = allMessages;
@@ -195,7 +212,30 @@ class VoiceStep extends step_1.default {
195
212
  reportingObject.keyPress = keyPress;
196
213
  else if (voiceProcessResult)
197
214
  reportingObject.voiceProcessResult = voiceProcessResult;
198
- await this.reporter.reportTranscriptEvent(reportingObject);
215
+ /**
216
+ * If we have the previous transcript event ID,
217
+ * which was returned from the interrupted message,
218
+ * try to update the reporting message.
219
+ */
220
+ if (interruptionMetadata?.reporterTranscriptEventId) {
221
+ 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
+ await this.process.cache.hitl.queueEvents([updateReportingObject]);
234
+ }
235
+ }
236
+ else {
237
+ await this.reporter.reportTranscriptEvent(reportingObject);
238
+ }
199
239
  call.lastTranscriptId = eventId;
200
240
  await this.updateData();
201
241
  return eventId;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onereach/step-voice",
3
- "version": "6.1.16-changegrammarstructure.0",
3
+ "version": "6.1.17-test.0",
4
4
  "author": "Roman Zolotarov <roman.zolotarov@onereach.com>",
5
5
  "contributors": [
6
6
  "Roman Zolotarov",