@onereach/step-voice 6.1.20 → 6.1.22-HEAD.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/package.json +3 -1
- package/dst/Cancel.d.ts +0 -4
- package/dst/Cancel.js +0 -35
- package/dst/Choice.d.ts +0 -31
- package/dst/Choice.js +0 -282
- package/dst/Conference Dial.d.ts +0 -10
- package/dst/Conference Dial.js +0 -46
- package/dst/Custom Voice Input.d.ts +0 -31
- package/dst/Custom Voice Input.js +0 -212
- package/dst/Global Command.d.ts +0 -66
- package/dst/Global Command.js +0 -347
- package/dst/Hangup.d.ts +0 -5
- package/dst/Hangup.js +0 -41
- package/dst/Idle Music.d.ts +0 -12
- package/dst/Idle Music.js +0 -49
- package/dst/Initiate Call.d.ts +0 -29
- package/dst/Initiate Call.js +0 -210
- package/dst/Join Conference.d.ts +0 -14
- package/dst/Join Conference.js +0 -63
- package/dst/Keypad Input.d.ts +0 -30
- package/dst/Keypad Input.js +0 -182
- package/dst/Leave Conference.d.ts +0 -9
- package/dst/Leave Conference.js +0 -50
- package/dst/Pause.d.ts +0 -5
- package/dst/Pause.js +0 -16
- package/dst/Pickup.d.ts +0 -6
- package/dst/Pickup.js +0 -13
- package/dst/Resume.d.ts +0 -5
- package/dst/Resume.js +0 -15
- package/dst/Say Message.d.ts +0 -13
- package/dst/Say Message.js +0 -65
- package/dst/Send DTMF.d.ts +0 -11
- package/dst/Send DTMF.js +0 -82
- package/dst/Transfer.d.ts +0 -24
- package/dst/Transfer.js +0 -95
- package/dst/Voice Recording.d.ts +0 -19
- package/dst/Voice Recording.js +0 -79
- package/dst/Wait For Call.d.ts +0 -7
- package/dst/Wait For Call.js +0 -56
- package/dst/step.d.ts +0 -47
- package/dst/step.js +0 -166
- package/dst/voice.d.ts +0 -97
- package/dst/voice.js +0 -399
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onereach/step-voice",
|
|
3
|
-
"version": "6.1.
|
|
3
|
+
"version": "6.1.22-HEAD.0",
|
|
4
4
|
"author": "Roman Zolotarov <roman.zolotarov@onereach.com>",
|
|
5
5
|
"contributors": [
|
|
6
6
|
"Roman Zolotarov",
|
|
@@ -54,6 +54,8 @@
|
|
|
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",
|
|
58
|
+
"update-module-versions": "./scripts/update-module-versions.sh",
|
|
57
59
|
"test": "jest --forceExit"
|
|
58
60
|
},
|
|
59
61
|
"repository": {
|
package/dst/Cancel.d.ts
DELETED
package/dst/Cancel.js
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const tslib_1 = require("tslib");
|
|
4
|
-
const voice_1 = tslib_1.__importDefault(require("./voice"));
|
|
5
|
-
class VoiceCancel extends voice_1.default {
|
|
6
|
-
async runStep() {
|
|
7
|
-
// const conv = await this.getConversation()
|
|
8
|
-
// if (conv.lcl.length <= 1) {
|
|
9
|
-
// this.log.debug('nothing to cancel')
|
|
10
|
-
// this.exitStep('next')
|
|
11
|
-
// return
|
|
12
|
-
// }
|
|
13
|
-
const call = await this.fetchData();
|
|
14
|
-
this.triggers.local(`in/voice/${call.id}`, async (event) => {
|
|
15
|
-
switch (event.params.type) {
|
|
16
|
-
case 'hangup':
|
|
17
|
-
await this.handleHangup(call);
|
|
18
|
-
return await this.waitConvEnd();
|
|
19
|
-
case 'error':
|
|
20
|
-
return this.throwError(event.params.error);
|
|
21
|
-
case 'cancel': {
|
|
22
|
-
// await this.popConvStep() // pop current command (cancel)
|
|
23
|
-
await this.cancel(); // cancel previous command
|
|
24
|
-
return this.exitStep('next');
|
|
25
|
-
}
|
|
26
|
-
default:
|
|
27
|
-
return this.exitFlow();
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
this.triggers.otherwise(async () => {
|
|
31
|
-
await this.sendCommands(call, [{ name: 'cancel' }]);
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
exports.default = VoiceCancel;
|
package/dst/Choice.d.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import VoiceStep, { SensitiveData, TODO, VoiceEvent } from './voice';
|
|
2
|
-
interface INPUT {
|
|
3
|
-
textType: string;
|
|
4
|
-
asr: TODO;
|
|
5
|
-
tts: TODO;
|
|
6
|
-
audio: TODO[];
|
|
7
|
-
choices: TODO[];
|
|
8
|
-
prompts: TODO[];
|
|
9
|
-
usePromptsForUnrecognized?: boolean;
|
|
10
|
-
sensitiveData: SensitiveData;
|
|
11
|
-
noReplyDelay: number;
|
|
12
|
-
promptsTriggers: TODO[];
|
|
13
|
-
usePromptsTriggers: boolean;
|
|
14
|
-
useInterspeechTimeout: boolean;
|
|
15
|
-
interSpeechTimeout: number;
|
|
16
|
-
recognitionModel?: string;
|
|
17
|
-
longRecognition: boolean;
|
|
18
|
-
}
|
|
19
|
-
interface EVENT extends VoiceEvent {
|
|
20
|
-
callRecording?: TODO;
|
|
21
|
-
exitId?: string;
|
|
22
|
-
digit?: string;
|
|
23
|
-
digits?: string;
|
|
24
|
-
phrases?: TODO[];
|
|
25
|
-
tags?: string[];
|
|
26
|
-
out?: string;
|
|
27
|
-
}
|
|
28
|
-
export default class Choice extends VoiceStep<INPUT, {}, EVENT> {
|
|
29
|
-
runStep(): Promise<void>;
|
|
30
|
-
}
|
|
31
|
-
export {};
|
package/dst/Choice.js
DELETED
|
@@ -1,282 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const tslib_1 = require("tslib");
|
|
4
|
-
const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
|
5
|
-
const voice_1 = tslib_1.__importDefault(require("./voice"));
|
|
6
|
-
const digitWords = [
|
|
7
|
-
'zero',
|
|
8
|
-
'one',
|
|
9
|
-
'two',
|
|
10
|
-
'three',
|
|
11
|
-
'four',
|
|
12
|
-
'five',
|
|
13
|
-
'six',
|
|
14
|
-
'seven',
|
|
15
|
-
'eight',
|
|
16
|
-
'nine'
|
|
17
|
-
];
|
|
18
|
-
const containsOnlyDigits = (stringsList) => {
|
|
19
|
-
let isOnlyDigits = true;
|
|
20
|
-
stringsList.forEach((str) => {
|
|
21
|
-
if (digitWords.includes(String(str).toLowerCase())) {
|
|
22
|
-
// Do nothing
|
|
23
|
-
}
|
|
24
|
-
else if (isNaN(str)) {
|
|
25
|
-
isOnlyDigits = false;
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
return isOnlyDigits;
|
|
29
|
-
};
|
|
30
|
-
const getPhrasesForSpeechRec = (choices) => {
|
|
31
|
-
const texts = lodash_1.default.flatMap(choices, (choice) => choice.options.map((opt) => opt.text));
|
|
32
|
-
if (containsOnlyDigits(texts)) {
|
|
33
|
-
return ['$OOV_CLASS_DIGIT_SEQUENCE'];
|
|
34
|
-
}
|
|
35
|
-
return texts;
|
|
36
|
-
};
|
|
37
|
-
const getAsrSettings = (settings, choices, recognitionModel) => {
|
|
38
|
-
if (settings.engine === 'google' || settings.engine === 'google_beta') {
|
|
39
|
-
return {
|
|
40
|
-
...settings,
|
|
41
|
-
config: {
|
|
42
|
-
speechContexts: [
|
|
43
|
-
{
|
|
44
|
-
phrases: getPhrasesForSpeechRec(choices)
|
|
45
|
-
}
|
|
46
|
-
],
|
|
47
|
-
recognitionModel
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
return settings;
|
|
52
|
-
};
|
|
53
|
-
const isRepromptTrigger = (recogResult, promptsTriggers) => {
|
|
54
|
-
const phrases = recogResult.map((r) => {
|
|
55
|
-
return r.lexical;
|
|
56
|
-
});
|
|
57
|
-
const triggers = promptsTriggers.flatMap((trigger) => {
|
|
58
|
-
if (lodash_1.default.isEmpty(trigger.grammar)) {
|
|
59
|
-
return trigger.text.replace(/`/g, '');
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
return trigger.grammar.value.map((v) => {
|
|
63
|
-
return v.replace(/`/g, '');
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
return !lodash_1.default.isEmpty(phrases.filter((e) => triggers.includes(e)));
|
|
68
|
-
};
|
|
69
|
-
class Choice extends voice_1.default {
|
|
70
|
-
async runStep() {
|
|
71
|
-
const call = await this.fetchData();
|
|
72
|
-
const { textType, asr, tts, sensitiveData, noReplyDelay, usePromptsTriggers, recognitionModel, useInterspeechTimeout, interSpeechTimeout, longRecognition, usePromptsForUnrecognized } = this.data;
|
|
73
|
-
const exitExists = (exitId) => {
|
|
74
|
-
return lodash_1.default.some(choices, (choice) => choice.exitId === exitId);
|
|
75
|
-
};
|
|
76
|
-
const choices = this.buildChoices({ choices: this.data.choices });
|
|
77
|
-
const ttsSettings = tts.getSettings(call.tts);
|
|
78
|
-
const asrSettings = getAsrSettings(asr.getSettings(call.asr), choices, recognitionModel);
|
|
79
|
-
const repromptsList = this.buildReprompts({ prompts: this.data.prompts });
|
|
80
|
-
const speechSections = this.buildSections({ sections: this.data.audio, textType, ttsSettings });
|
|
81
|
-
const grammar = {
|
|
82
|
-
id: this.currentStepId,
|
|
83
|
-
choices,
|
|
84
|
-
asr: asrSettings
|
|
85
|
-
};
|
|
86
|
-
const command = {
|
|
87
|
-
name: 'speak',
|
|
88
|
-
params: {
|
|
89
|
-
grammar,
|
|
90
|
-
dictation: longRecognition
|
|
91
|
-
? 'continuous'
|
|
92
|
-
: useInterspeechTimeout,
|
|
93
|
-
interSpeechTimeout: interSpeechTimeout * 1000,
|
|
94
|
-
sections: []
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
// There's a specific need to do so. There might be ${variable} section
|
|
98
|
-
this.triggers.local(`in/voice/${call.id}`, async (event) => {
|
|
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
|
-
}
|
|
113
|
-
switch (event.params.type) {
|
|
114
|
-
case 'digit':
|
|
115
|
-
case 'digits': {
|
|
116
|
-
const params = event.params;
|
|
117
|
-
const digit = params.digit ?? params.digits;
|
|
118
|
-
const exitId = params.exitId;
|
|
119
|
-
// On bargeIn, we should stop playback
|
|
120
|
-
if (exitExists(exitId)) {
|
|
121
|
-
const exitStepLabel = this.getExitStepLabel(exitId) ?? '';
|
|
122
|
-
const message = lodash_1.default.replace(exitStepLabel, /^(\d+\. )?(~ )?/, '');
|
|
123
|
-
await this.transcript(call, {
|
|
124
|
-
keyPress: digit,
|
|
125
|
-
message: message,
|
|
126
|
-
reportingSettingsKey,
|
|
127
|
-
action: 'Call DTMF',
|
|
128
|
-
actionFromBot: false
|
|
129
|
-
});
|
|
130
|
-
await this.resumeRecording(call, sensitiveData);
|
|
131
|
-
return this.exitStep(exitId, this.exitChoiceData('dtmf', params), longRecognition);
|
|
132
|
-
}
|
|
133
|
-
else if ((lodash_1.default.isUndefined(usePromptsForUnrecognized) || usePromptsForUnrecognized) && this.rptsHasMore({ repromptsList })) {
|
|
134
|
-
await this.transcript(call, {
|
|
135
|
-
message: 'Unrecognized',
|
|
136
|
-
keyPress: digit,
|
|
137
|
-
reportingSettingsKey,
|
|
138
|
-
action: 'Call DTMF',
|
|
139
|
-
actionFromBot: false
|
|
140
|
-
});
|
|
141
|
-
await this.rptsSend(call, {
|
|
142
|
-
command,
|
|
143
|
-
repromptsList,
|
|
144
|
-
noReplyDelay,
|
|
145
|
-
speechSections,
|
|
146
|
-
textType,
|
|
147
|
-
ttsSettings,
|
|
148
|
-
sensitiveData
|
|
149
|
-
});
|
|
150
|
-
return this.exitFlow();
|
|
151
|
-
}
|
|
152
|
-
await this.transcript(call, {
|
|
153
|
-
message: 'Not Recognized',
|
|
154
|
-
keyPress: digit,
|
|
155
|
-
reportingSettingsKey,
|
|
156
|
-
action: 'Call DTMF',
|
|
157
|
-
actionFromBot: false
|
|
158
|
-
});
|
|
159
|
-
await this.resumeRecording(call, sensitiveData);
|
|
160
|
-
return this.exitStep('unrecognized', this.exitChoiceData('dtmf', { digit }), longRecognition);
|
|
161
|
-
}
|
|
162
|
-
case 'recognition': {
|
|
163
|
-
const params = event.params;
|
|
164
|
-
const exitId = params.exitId;
|
|
165
|
-
const phrases = params.phrases;
|
|
166
|
-
if (lodash_1.default.isEmpty(phrases)) {
|
|
167
|
-
await this.resumeRecording(call, sensitiveData);
|
|
168
|
-
return this.exitStep('unrecognized', {});
|
|
169
|
-
}
|
|
170
|
-
const voiceProcessResult = lodash_1.default.chain(phrases)
|
|
171
|
-
.map((p) => p.lexical)
|
|
172
|
-
.join(' | ')
|
|
173
|
-
.value();
|
|
174
|
-
// On bargeIn, we should stop playback
|
|
175
|
-
if (exitExists(exitId)) {
|
|
176
|
-
await this.transcript(call, {
|
|
177
|
-
message: lodash_1.default.replace(this.getExitStepLabel(exitId) ?? '', /^(\d+\. )?(~ )?/, ''),
|
|
178
|
-
voiceProcessResult,
|
|
179
|
-
reportingSettingsKey,
|
|
180
|
-
action: 'Call Recognition',
|
|
181
|
-
actionFromBot: false
|
|
182
|
-
});
|
|
183
|
-
await this.resumeRecording(call, sensitiveData);
|
|
184
|
-
// There might be hooks after this step which we will try to avoid
|
|
185
|
-
return this.exitStep(exitId, this.exitChoiceData('voice', params), longRecognition);
|
|
186
|
-
}
|
|
187
|
-
else if (((lodash_1.default.isUndefined(usePromptsForUnrecognized) || usePromptsForUnrecognized) ||
|
|
188
|
-
(usePromptsTriggers ? isRepromptTrigger(phrases, this.data.promptsTriggers) : false)) &&
|
|
189
|
-
this.rptsHasMore({ repromptsList })) {
|
|
190
|
-
await this.transcript(call, {
|
|
191
|
-
message: 'Unrecognized',
|
|
192
|
-
voiceProcessResult,
|
|
193
|
-
reportingSettingsKey,
|
|
194
|
-
action: 'Call Recognition',
|
|
195
|
-
actionFromBot: false
|
|
196
|
-
});
|
|
197
|
-
await this.rptsSend(call, {
|
|
198
|
-
command,
|
|
199
|
-
repromptsList,
|
|
200
|
-
noReplyDelay,
|
|
201
|
-
speechSections,
|
|
202
|
-
textType,
|
|
203
|
-
ttsSettings,
|
|
204
|
-
sensitiveData
|
|
205
|
-
});
|
|
206
|
-
return this.exitFlow();
|
|
207
|
-
}
|
|
208
|
-
// There's no more reprompts, should move on to unrecognized direction
|
|
209
|
-
await this.transcript(call, {
|
|
210
|
-
message: 'Not Recognized',
|
|
211
|
-
voiceProcessResult,
|
|
212
|
-
reportingSettingsKey,
|
|
213
|
-
action: 'Call Recognition',
|
|
214
|
-
actionFromBot: false
|
|
215
|
-
});
|
|
216
|
-
await this.resumeRecording(call, sensitiveData);
|
|
217
|
-
// We might end up in same session
|
|
218
|
-
return this.exitStep('unrecognized', this.exitChoiceData('voice', params), longRecognition);
|
|
219
|
-
}
|
|
220
|
-
case 'timeout': {
|
|
221
|
-
if (this.rptsHasMore({ repromptsList })) {
|
|
222
|
-
await this.transcript(call, {
|
|
223
|
-
message: 'No Reply',
|
|
224
|
-
reportingSettingsKey,
|
|
225
|
-
action: 'Call Prompt',
|
|
226
|
-
actionFromBot: false
|
|
227
|
-
});
|
|
228
|
-
await this.rptsSend(call, {
|
|
229
|
-
command,
|
|
230
|
-
repromptsList,
|
|
231
|
-
noReplyDelay,
|
|
232
|
-
speechSections,
|
|
233
|
-
textType,
|
|
234
|
-
ttsSettings,
|
|
235
|
-
sensitiveData
|
|
236
|
-
});
|
|
237
|
-
return this.exitFlow();
|
|
238
|
-
}
|
|
239
|
-
await this.transcript(call, {
|
|
240
|
-
message: 'Not Replied',
|
|
241
|
-
reportingSettingsKey,
|
|
242
|
-
action: 'Call Prompt',
|
|
243
|
-
actionFromBot: false
|
|
244
|
-
});
|
|
245
|
-
await this.resumeRecording(call, sensitiveData);
|
|
246
|
-
// We might end up in same session
|
|
247
|
-
return this.exitStep('no reply', {}, longRecognition);
|
|
248
|
-
}
|
|
249
|
-
case 'hangup': {
|
|
250
|
-
await this.handleHangup(call);
|
|
251
|
-
return await this.waitConvEnd();
|
|
252
|
-
}
|
|
253
|
-
case 'cancel': {
|
|
254
|
-
return this.handleCancel();
|
|
255
|
-
}
|
|
256
|
-
case 'error':
|
|
257
|
-
return this.throwError(event.params.error);
|
|
258
|
-
default:
|
|
259
|
-
return this.exitFlow();
|
|
260
|
-
}
|
|
261
|
-
});
|
|
262
|
-
this.triggers.otherwise(async () => {
|
|
263
|
-
const eventId = await this.transcript(call, {
|
|
264
|
-
sections: speechSections,
|
|
265
|
-
reprompt: {
|
|
266
|
-
maxAttempts: repromptsList.length,
|
|
267
|
-
attempt: 0
|
|
268
|
-
},
|
|
269
|
-
reportingSettingsKey: 'transcriptPrompt',
|
|
270
|
-
action: 'Call Prompt',
|
|
271
|
-
actionFromBot: true
|
|
272
|
-
});
|
|
273
|
-
command.params.reporterTranscriptEventId = eventId;
|
|
274
|
-
command.params.sections = speechSections;
|
|
275
|
-
command.params.timeout = this.rptsTimeout({ noReplyDelay, repromptsList, initial: true });
|
|
276
|
-
await this.pauseRecording(call, command, sensitiveData);
|
|
277
|
-
return this.exitFlow();
|
|
278
|
-
});
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
exports.default = Choice;
|
|
282
|
-
// --------------------------------------------------------------------
|
package/dst/Conference Dial.d.ts
DELETED
package/dst/Conference Dial.js
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const tslib_1 = require("tslib");
|
|
4
|
-
const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
|
5
|
-
const voice_1 = tslib_1.__importDefault(require("./voice"));
|
|
6
|
-
class ConferenceDial extends voice_1.default {
|
|
7
|
-
async runStep() {
|
|
8
|
-
const call = await this.fetchData();
|
|
9
|
-
this.triggers
|
|
10
|
-
.local(`in/voice/${call.id}`, async (event) => {
|
|
11
|
-
switch (event.params.type) {
|
|
12
|
-
case 'hangup':
|
|
13
|
-
await this.handleHangup(call);
|
|
14
|
-
return await this.waitConvEnd();
|
|
15
|
-
case 'conference-start':
|
|
16
|
-
if (this.data.stayInConference) {
|
|
17
|
-
return this.exitFlow();
|
|
18
|
-
}
|
|
19
|
-
else {
|
|
20
|
-
return this.exitStep('next', lodash_1.default.omit(event.params, ['type']));
|
|
21
|
-
}
|
|
22
|
-
case 'conference-end':
|
|
23
|
-
return this.data.stayInConference ? this.exitStep('next') : this.exitFlow();
|
|
24
|
-
case 'error':
|
|
25
|
-
return this.throwError(event.params.error);
|
|
26
|
-
default:
|
|
27
|
-
return this.exitFlow();
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
this.triggers.otherwise(async () => {
|
|
31
|
-
const { sourceConf, botNumber, headers, hearOnly } = this.data;
|
|
32
|
-
const command = {
|
|
33
|
-
name: 'conference.joinBot',
|
|
34
|
-
params: {
|
|
35
|
-
room: sourceConf,
|
|
36
|
-
botNumber,
|
|
37
|
-
headers,
|
|
38
|
-
hearOnly,
|
|
39
|
-
stayInConference: this.data.stayInConference
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
await this.sendCommands(call, [command]);
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
exports.default = ConferenceDial;
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import VoiceStep, { SensitiveData, TODO, VoiceEvent } from './voice';
|
|
2
|
-
interface INPUT {
|
|
3
|
-
textType: string;
|
|
4
|
-
asr: TODO;
|
|
5
|
-
tts: TODO;
|
|
6
|
-
audio: TODO[];
|
|
7
|
-
choices: TODO[];
|
|
8
|
-
prompts: TODO[];
|
|
9
|
-
sensitiveData: SensitiveData;
|
|
10
|
-
noReplyDelay: number;
|
|
11
|
-
promptsTriggers: TODO[];
|
|
12
|
-
usePromptsTriggers: boolean;
|
|
13
|
-
recognitionModel?: string;
|
|
14
|
-
resultInterpretation: string[];
|
|
15
|
-
phraseList: Array<{
|
|
16
|
-
phrase: string;
|
|
17
|
-
}>;
|
|
18
|
-
}
|
|
19
|
-
interface EVENT extends VoiceEvent {
|
|
20
|
-
callRecording?: TODO;
|
|
21
|
-
exitId?: string;
|
|
22
|
-
digit?: string;
|
|
23
|
-
digits?: string;
|
|
24
|
-
phrases?: TODO[];
|
|
25
|
-
tags?: string[];
|
|
26
|
-
out?: string;
|
|
27
|
-
}
|
|
28
|
-
export default class CustomVoiceInput extends VoiceStep<INPUT, {}, EVENT> {
|
|
29
|
-
runStep(): Promise<void>;
|
|
30
|
-
}
|
|
31
|
-
export {};
|
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const tslib_1 = require("tslib");
|
|
4
|
-
const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
|
5
|
-
const voice_1 = tslib_1.__importDefault(require("./voice"));
|
|
6
|
-
const getPhrasesForSpeechRec = (choices) => {
|
|
7
|
-
const texts = lodash_1.default.flatMap(choices, (choice) => choice.options.map((opt) => opt.text));
|
|
8
|
-
return texts;
|
|
9
|
-
};
|
|
10
|
-
const getAsrSettings = (choices, recognitionModel) => {
|
|
11
|
-
// this step works only with the Google engine
|
|
12
|
-
// hardcoded en-US lang will be changed to dynamic after step testing and design approval
|
|
13
|
-
return {
|
|
14
|
-
enabled: true,
|
|
15
|
-
engine: 'google',
|
|
16
|
-
language: 'en-US',
|
|
17
|
-
config: {
|
|
18
|
-
speechContexts: [
|
|
19
|
-
{
|
|
20
|
-
phrases: getPhrasesForSpeechRec(choices)
|
|
21
|
-
}
|
|
22
|
-
],
|
|
23
|
-
recognitionModel
|
|
24
|
-
}
|
|
25
|
-
};
|
|
26
|
-
};
|
|
27
|
-
const isRepromptTrigger = (recogResult, promptsTriggers) => {
|
|
28
|
-
const phrases = recogResult.map((r) => {
|
|
29
|
-
return r.lexical;
|
|
30
|
-
});
|
|
31
|
-
const triggers = promptsTriggers.flatMap((trigger) => {
|
|
32
|
-
if (lodash_1.default.isEmpty(trigger.grammar)) {
|
|
33
|
-
return trigger.text.replace(/`/g, '');
|
|
34
|
-
}
|
|
35
|
-
else {
|
|
36
|
-
return trigger.grammar.value.map((v) => {
|
|
37
|
-
return v.replace(/`/g, '');
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
return !lodash_1.default.isEmpty(phrases.filter((e) => triggers.includes(e)));
|
|
42
|
-
};
|
|
43
|
-
const alterRecognitionPhrases = (phrases, interpretation) => {
|
|
44
|
-
if (interpretation.length !== 1)
|
|
45
|
-
return;
|
|
46
|
-
switch (interpretation[0]) {
|
|
47
|
-
case '$POSTALCODE':
|
|
48
|
-
phrases.forEach(p => { p.lexical = p.lexical.replace(/\s+/g, ''); });
|
|
49
|
-
break;
|
|
50
|
-
case '$PERCENT':
|
|
51
|
-
phrases.forEach(p => { p.lexical = p.lexical.replace(/\s+(?=%)/, ''); });
|
|
52
|
-
break;
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
class CustomVoiceInput extends voice_1.default {
|
|
56
|
-
async runStep() {
|
|
57
|
-
const call = await this.fetchData();
|
|
58
|
-
const { textType, tts, sensitiveData, noReplyDelay, usePromptsTriggers, recognitionModel, phraseList } = this.data;
|
|
59
|
-
const exitExists = (exitId) => {
|
|
60
|
-
return lodash_1.default.some(choices, (choice) => choice.exitId === exitId);
|
|
61
|
-
};
|
|
62
|
-
const mainLeg = {
|
|
63
|
-
exitId: '5886d1ee-db6d-45ca-a2ce-d586862c65ff',
|
|
64
|
-
dtmf: null,
|
|
65
|
-
grxml: '',
|
|
66
|
-
text: '.+',
|
|
67
|
-
grammar: {}
|
|
68
|
-
};
|
|
69
|
-
const choices = this.buildChoices({ choices: [...this.data.choices, mainLeg] });
|
|
70
|
-
const ttsSettings = tts.getSettings(call.tts);
|
|
71
|
-
const asrSettings = getAsrSettings(choices, recognitionModel);
|
|
72
|
-
const repromptsList = this.buildReprompts({ prompts: this.data.prompts });
|
|
73
|
-
const speechSections = this.buildSections({ sections: this.data.audio, textType, ttsSettings });
|
|
74
|
-
const grammar = {
|
|
75
|
-
id: this.currentStepId,
|
|
76
|
-
choices,
|
|
77
|
-
asr: asrSettings
|
|
78
|
-
};
|
|
79
|
-
const command = {
|
|
80
|
-
name: 'double-asr',
|
|
81
|
-
params: {
|
|
82
|
-
grammar,
|
|
83
|
-
sections: [],
|
|
84
|
-
resultInterpretation: this.data.resultInterpretation,
|
|
85
|
-
tokenPhrases: phraseList || []
|
|
86
|
-
}
|
|
87
|
-
};
|
|
88
|
-
// There's a specific need to do so. There might be ${variable} section
|
|
89
|
-
this.triggers.local(`in/voice/${call.id}`, async (event) => {
|
|
90
|
-
const reportingSettingsKey = this.rptsStarted ? 'transcriptRepromptResponse' : 'transcriptResponse';
|
|
91
|
-
switch (event.params.type) {
|
|
92
|
-
// digit recognition removed
|
|
93
|
-
case 'recognition': {
|
|
94
|
-
const params = event.params;
|
|
95
|
-
const exitId = params.exitId;
|
|
96
|
-
alterRecognitionPhrases(params.phrases, this.data.resultInterpretation);
|
|
97
|
-
const phrases = params.phrases;
|
|
98
|
-
if (lodash_1.default.isEmpty(phrases)) {
|
|
99
|
-
await this.resumeRecording(call, sensitiveData);
|
|
100
|
-
return this.exitStep('unrecognized', {});
|
|
101
|
-
}
|
|
102
|
-
const voiceProcessResult = lodash_1.default.chain(phrases)
|
|
103
|
-
.map((p) => p.lexical)
|
|
104
|
-
.join(' | ')
|
|
105
|
-
.value();
|
|
106
|
-
// On bargeIn, we should stop playback
|
|
107
|
-
if (exitExists(exitId)) {
|
|
108
|
-
await this.transcript(call, {
|
|
109
|
-
message: lodash_1.default.replace(this.getExitStepLabel(exitId) ?? '', /^(\d+\. )?(~ )?/, ''),
|
|
110
|
-
voiceProcessResult,
|
|
111
|
-
reportingSettingsKey,
|
|
112
|
-
action: 'Call Recognition',
|
|
113
|
-
actionFromBot: false
|
|
114
|
-
});
|
|
115
|
-
await this.resumeRecording(call, sensitiveData);
|
|
116
|
-
// There might be hooks after this step which we will try to avoid
|
|
117
|
-
return this.exitStep(exitId, this.exitChoiceData('voice', params));
|
|
118
|
-
}
|
|
119
|
-
else if (this.rptsHasMore({ repromptsList }) &&
|
|
120
|
-
(usePromptsTriggers ? isRepromptTrigger(phrases, this.data.promptsTriggers) : true)) {
|
|
121
|
-
await this.transcript(call, {
|
|
122
|
-
message: 'Unrecognized',
|
|
123
|
-
voiceProcessResult,
|
|
124
|
-
reportingSettingsKey,
|
|
125
|
-
action: 'Call Recognition',
|
|
126
|
-
actionFromBot: false
|
|
127
|
-
});
|
|
128
|
-
await this.rptsSend(call, {
|
|
129
|
-
command,
|
|
130
|
-
repromptsList,
|
|
131
|
-
noReplyDelay,
|
|
132
|
-
speechSections,
|
|
133
|
-
textType,
|
|
134
|
-
ttsSettings,
|
|
135
|
-
sensitiveData
|
|
136
|
-
});
|
|
137
|
-
return this.exitFlow();
|
|
138
|
-
}
|
|
139
|
-
// There's no more reprompts, should move on to unrecognized direction
|
|
140
|
-
await this.transcript(call, {
|
|
141
|
-
message: 'Not Recognized',
|
|
142
|
-
voiceProcessResult,
|
|
143
|
-
reportingSettingsKey,
|
|
144
|
-
action: 'Call Recognition',
|
|
145
|
-
actionFromBot: false
|
|
146
|
-
});
|
|
147
|
-
await this.resumeRecording(call, sensitiveData);
|
|
148
|
-
// We might end up in same session
|
|
149
|
-
return this.exitStep('unrecognized', this.exitChoiceData('voice', params));
|
|
150
|
-
}
|
|
151
|
-
case 'timeout': {
|
|
152
|
-
if (this.rptsHasMore({ repromptsList })) {
|
|
153
|
-
await this.transcript(call, {
|
|
154
|
-
message: 'No Reply',
|
|
155
|
-
reportingSettingsKey,
|
|
156
|
-
action: 'Call Prompt',
|
|
157
|
-
actionFromBot: false
|
|
158
|
-
});
|
|
159
|
-
await this.rptsSend(call, {
|
|
160
|
-
command,
|
|
161
|
-
repromptsList,
|
|
162
|
-
noReplyDelay,
|
|
163
|
-
speechSections,
|
|
164
|
-
textType,
|
|
165
|
-
ttsSettings,
|
|
166
|
-
sensitiveData
|
|
167
|
-
});
|
|
168
|
-
return this.exitFlow();
|
|
169
|
-
}
|
|
170
|
-
await this.transcript(call, {
|
|
171
|
-
message: 'Not Replied',
|
|
172
|
-
reportingSettingsKey,
|
|
173
|
-
action: 'Call Prompt',
|
|
174
|
-
actionFromBot: false
|
|
175
|
-
});
|
|
176
|
-
await this.resumeRecording(call, sensitiveData);
|
|
177
|
-
// We might end up in same session
|
|
178
|
-
return this.exitStep('no reply', {});
|
|
179
|
-
}
|
|
180
|
-
case 'hangup': {
|
|
181
|
-
await this.handleHangup(call);
|
|
182
|
-
return await this.waitConvEnd();
|
|
183
|
-
}
|
|
184
|
-
case 'cancel': {
|
|
185
|
-
return this.handleCancel();
|
|
186
|
-
}
|
|
187
|
-
case 'error':
|
|
188
|
-
return this.throwError(event.params.error);
|
|
189
|
-
default:
|
|
190
|
-
return this.exitFlow();
|
|
191
|
-
}
|
|
192
|
-
});
|
|
193
|
-
this.triggers.otherwise(async () => {
|
|
194
|
-
await this.transcript(call, {
|
|
195
|
-
sections: speechSections,
|
|
196
|
-
reprompt: {
|
|
197
|
-
maxAttempts: repromptsList.length,
|
|
198
|
-
attempt: 0
|
|
199
|
-
},
|
|
200
|
-
reportingSettingsKey: 'transcriptPrompt',
|
|
201
|
-
action: 'Call Prompt',
|
|
202
|
-
actionFromBot: true
|
|
203
|
-
});
|
|
204
|
-
command.params.sections = speechSections;
|
|
205
|
-
command.params.timeout = this.rptsTimeout({ noReplyDelay, repromptsList, initial: true });
|
|
206
|
-
await this.pauseRecording(call, command, sensitiveData);
|
|
207
|
-
return this.exitFlow();
|
|
208
|
-
});
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
exports.default = CustomVoiceInput;
|
|
212
|
-
// --------------------------------------------------------------------
|