@onereach/step-voice 4.0.37 → 4.0.39

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.
@@ -0,0 +1,35 @@
1
+ import VoiceStep, { 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: {
10
+ muteStep: boolean;
11
+ muteUser: boolean;
12
+ muteBot: boolean;
13
+ };
14
+ noReplyDelay: number;
15
+ promptsTriggers: TODO[];
16
+ usePromptsTriggers: boolean;
17
+ recognitionModel?: string;
18
+ resultInterpretation?: string;
19
+ phraseList: Array<{
20
+ phrase: string;
21
+ }>;
22
+ }
23
+ interface EVENT extends VoiceEvent {
24
+ callRecording?: TODO;
25
+ exitId?: string;
26
+ digit?: string;
27
+ digits?: string;
28
+ phrases?: TODO[];
29
+ tags?: string[];
30
+ out?: string;
31
+ }
32
+ export default class CustomVoiceInput extends VoiceStep<INPUT, {}, EVENT> {
33
+ runStep(): Promise<void>;
34
+ }
35
+ export {};
@@ -0,0 +1,213 @@
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 = (settings, choices, recognitionModel) => {
11
+ if (settings.engine === 'google' || settings.engine === 'google_beta') {
12
+ return {
13
+ ...settings,
14
+ config: {
15
+ speechContexts: [
16
+ {
17
+ phrases: getPhrasesForSpeechRec(choices)
18
+ }
19
+ ],
20
+ recognitionModel
21
+ }
22
+ };
23
+ }
24
+ return settings;
25
+ };
26
+ const isRepromptTrigger = (recogResult, promptsTriggers) => {
27
+ const phrases = recogResult.map((r) => {
28
+ return r.lexical;
29
+ });
30
+ const triggers = promptsTriggers.flatMap((trigger) => {
31
+ if (lodash_1.default.isEmpty(trigger.grammar)) {
32
+ return trigger.text.replace(/`/g, '');
33
+ }
34
+ else {
35
+ return trigger.grammar.value.map((v) => {
36
+ return v.replace(/`/g, '');
37
+ });
38
+ }
39
+ });
40
+ return !lodash_1.default.isEmpty(phrases.filter((e) => triggers.includes(e)));
41
+ };
42
+ class CustomVoiceInput extends voice_1.default {
43
+ async runStep() {
44
+ const channel = await this.fetchData();
45
+ const { textType, asr, tts, sensitiveData, noReplyDelay, usePromptsTriggers, recognitionModel } = this.data;
46
+ const exitExists = (exitId) => {
47
+ return lodash_1.default.some(choices, (choice) => choice.exitId === exitId);
48
+ };
49
+ const mainLeg = {
50
+ exitId: '5886d1ee-db6d-45ca-a2ce-d586862c65ff',
51
+ dtmf: null,
52
+ grxml: '',
53
+ text: `.+`,
54
+ grammar: {},
55
+ };
56
+ const choices = this.buildChoices({ choices: [...this.data.choices, mainLeg] });
57
+ const ttsSettings = tts.getSettings(channel.tts);
58
+ const asrSettings = getAsrSettings(asr.getSettings(channel.asr), choices, recognitionModel);
59
+ const repromptsList = this.buildReprompts({ prompts: this.data.prompts });
60
+ const speechSections = this.buildSections({ sections: this.data.audio, textType, ttsSettings });
61
+ const grammar = {
62
+ id: this.currentStepId,
63
+ choices,
64
+ asr: asrSettings
65
+ };
66
+ const command = {
67
+ name: 'double-asr',
68
+ params: {
69
+ grammar,
70
+ sections: [],
71
+ resultInterpretation: this.data.resultInterpretation,
72
+ tokenPhrases: this.data.phraseList.map(item => item.phrase)
73
+ }
74
+ };
75
+ // There's a specific need to do so. There might be ${variable} section
76
+ this.triggers.once(`in/voice/${channel.id}/event`, async (event) => {
77
+ // await thisStep.refreshCallback(this, conversation, channel); -- ???
78
+ if (channel.recordCall && sensitiveData?.muteStep) {
79
+ await this.sendCommands(channel, [{
80
+ name: 'resume-record-session',
81
+ params: {
82
+ muteUser: sensitiveData.muteUser,
83
+ muteBot: sensitiveData.muteBot
84
+ }
85
+ }]);
86
+ }
87
+ const reportingSettingsKey = this.rptsStarted ? 'transcriptRepromptResponse' : 'transcriptResponse';
88
+ switch (event.params.type) {
89
+ // digit recognition removed
90
+ case 'recognition': {
91
+ const params = event.params;
92
+ const exitId = params.exitId;
93
+ const phrases = params.phrases;
94
+ if (lodash_1.default.isEmpty(phrases)) {
95
+ return this.exitStep('unrecognized', {});
96
+ }
97
+ const voiceProcessResult = lodash_1.default.chain(phrases)
98
+ .map((p) => p.lexical)
99
+ .join(' | ')
100
+ .value();
101
+ // On bargeIn, we should stop playback
102
+ if (exitExists(exitId)) {
103
+ await this.transcript(channel, {
104
+ message: lodash_1.default.replace(this.getExitStepLabel(exitId) ?? '', /^(\d+\. )?(~ )?/, ''),
105
+ voiceProcessResult,
106
+ reportingSettingsKey,
107
+ action: 'Call Recognition',
108
+ actionFromBot: false
109
+ });
110
+ // There might be hooks after this step which we will try to avoid
111
+ return this.exitStep(exitId, this.exitChoiceData('voice', params));
112
+ }
113
+ else if (this.rptsHasMore({ repromptsList }) &&
114
+ (usePromptsTriggers ? isRepromptTrigger(phrases, this.data.promptsTriggers) : true)) {
115
+ await this.transcript(channel, {
116
+ message: 'Unrecognized',
117
+ voiceProcessResult,
118
+ reportingSettingsKey,
119
+ action: 'Call Recognition',
120
+ actionFromBot: false
121
+ });
122
+ await this.rptsSend(channel, {
123
+ command,
124
+ repromptsList,
125
+ noReplyDelay,
126
+ speechSections,
127
+ textType,
128
+ ttsSettings
129
+ });
130
+ return this.exitFlow();
131
+ }
132
+ // There's no more reprompts, should move on to unrecognized direction
133
+ await this.transcript(channel, {
134
+ message: 'Not Recognized',
135
+ voiceProcessResult,
136
+ reportingSettingsKey,
137
+ action: 'Call Recognition',
138
+ actionFromBot: false
139
+ });
140
+ // We might end up in same session
141
+ return this.exitStep('unrecognized', this.exitChoiceData('voice', params));
142
+ }
143
+ case 'timeout': {
144
+ if (this.rptsHasMore({ repromptsList })) {
145
+ await this.transcript(channel, {
146
+ message: 'No Reply',
147
+ reportingSettingsKey,
148
+ action: 'Call Prompt',
149
+ actionFromBot: false
150
+ });
151
+ await this.rptsSend(channel, {
152
+ command,
153
+ repromptsList,
154
+ noReplyDelay,
155
+ speechSections,
156
+ textType,
157
+ ttsSettings
158
+ });
159
+ return this.exitFlow();
160
+ }
161
+ await this.transcript(channel, {
162
+ message: 'Not Replied',
163
+ reportingSettingsKey,
164
+ action: 'Call Prompt',
165
+ actionFromBot: false
166
+ });
167
+ // We might end up in same session
168
+ return this.exitStep('no reply', {});
169
+ }
170
+ case 'hangup': {
171
+ await this.handleHangup(channel);
172
+ return await this.waitConvEnd();
173
+ }
174
+ // case 'cancel': {
175
+ // return this.data.handleCancel === true && this.exitStep('cancel')
176
+ // }
177
+ case 'error':
178
+ return this.throwError(event.params.error);
179
+ default:
180
+ return this.exitFlow();
181
+ }
182
+ });
183
+ this.triggers.otherwise(async () => {
184
+ await this.transcript(channel, {
185
+ sections: speechSections,
186
+ reprompt: {
187
+ maxAttempts: repromptsList.length,
188
+ attempt: 0
189
+ },
190
+ reportingSettingsKey: 'transcriptPrompt',
191
+ action: 'Call Prompt',
192
+ actionFromBot: true
193
+ });
194
+ command.params.sections = speechSections;
195
+ command.params.timeout = this.rptsTimeout({ noReplyDelay, repromptsList });
196
+ await this.sendCommands(channel, [
197
+ ...channel.recordCall && sensitiveData?.muteStep
198
+ ? [{
199
+ name: 'stop-record-session',
200
+ params: {
201
+ muteUser: sensitiveData.muteUser,
202
+ muteBot: sensitiveData.muteBot
203
+ }
204
+ }]
205
+ : [],
206
+ command
207
+ ]);
208
+ return this.exitFlow();
209
+ });
210
+ }
211
+ }
212
+ exports.default = CustomVoiceInput;
213
+ // --------------------------------------------------------------------
package/dst/Transfer.d.ts CHANGED
@@ -9,7 +9,7 @@ interface INPUT {
9
9
  }>;
10
10
  refer: boolean;
11
11
  gatewaySettigsMode?: string;
12
- identifierForInheritance?: string;
12
+ from?: string;
13
13
  sipHost?: string;
14
14
  sipUser?: string;
15
15
  sipPassword?: string;
package/dst/Transfer.js CHANGED
@@ -48,7 +48,7 @@ class Transfer extends voice_1.default {
48
48
  return this.exitFlow();
49
49
  });
50
50
  this.triggers.otherwise(async () => {
51
- const { phoneNumber, sessionTimeout, destination, sipHeaders = [], sipHost, sipUser, sipPassword, refer, gatewaySettigsMode, identifierForInheritance } = this.data;
51
+ const { phoneNumber, sessionTimeout, destination, sipHeaders = [], sipHost, sipUser, sipPassword, refer, gatewaySettigsMode, from } = this.data;
52
52
  const destinationIsSip = (/^sip:/i).test(destination);
53
53
  const destinationIsUser = (/^user:/i).test(destination);
54
54
  const callerID = phoneNumber;
@@ -58,7 +58,7 @@ class Transfer extends voice_1.default {
58
58
  const command = {
59
59
  name: destinationIsSip ? (refer ? 'refer' : 'bridge_sip') : (destinationIsUser ? 'bridge_user' : 'bridge'),
60
60
  params: {
61
- botNumber: inheritGatewaySetting ? identifierForInheritance : channel.botNumber,
61
+ botNumber: inheritGatewaySetting ? from : channel.botNumber,
62
62
  transferFrom: callerID,
63
63
  transferTo: destination,
64
64
  headers,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onereach/step-voice",
3
- "version": "4.0.37",
3
+ "version": "4.0.39",
4
4
  "author": "Roman Zolotarov <roman.zolotarov@onereach.com>",
5
5
  "contributors": [
6
6
  "Roman Zolotarov",