botium-connector-voip 0.0.14 → 0.0.16
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/dist/botium-connector-voip-cjs.js +100 -148
- package/dist/botium-connector-voip-cjs.js.map +1 -1
- package/dist/botium-connector-voip-es.js +98 -147
- package/dist/botium-connector-voip-es.js.map +1 -1
- package/index.js +3 -1
- package/package.json +3 -2
- package/src/confidence-threshold-logichook.js +13 -0
- package/src/connector.js +58 -34
|
@@ -5,18 +5,20 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
5
5
|
var ws = require('ws');
|
|
6
6
|
var lodash = require('lodash');
|
|
7
7
|
var axios = require('axios');
|
|
8
|
-
var debug$
|
|
8
|
+
var debug$4 = require('debug');
|
|
9
9
|
var path = require('path');
|
|
10
|
+
var musicMetadata = require('music-metadata');
|
|
10
11
|
|
|
11
12
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
12
13
|
|
|
13
14
|
var ws__default = /*#__PURE__*/_interopDefaultLegacy(ws);
|
|
14
15
|
var lodash__default = /*#__PURE__*/_interopDefaultLegacy(lodash);
|
|
15
16
|
var axios__default = /*#__PURE__*/_interopDefaultLegacy(axios);
|
|
16
|
-
var debug__default = /*#__PURE__*/_interopDefaultLegacy(debug$
|
|
17
|
+
var debug__default = /*#__PURE__*/_interopDefaultLegacy(debug$4);
|
|
17
18
|
var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
|
|
19
|
+
var musicMetadata__default = /*#__PURE__*/_interopDefaultLegacy(musicMetadata);
|
|
18
20
|
|
|
19
|
-
const debug$
|
|
21
|
+
const debug$3 = debug__default["default"]('botium-connector-voip');
|
|
20
22
|
const Capabilities = {
|
|
21
23
|
VOIP_STT_URL_STREAM: 'VOIP_STT_URL_STREAM',
|
|
22
24
|
VOIP_STT_PARAMS_STREAM: 'VOIP_STT_PARAMS_STREAM',
|
|
@@ -58,7 +60,8 @@ const Capabilities = {
|
|
|
58
60
|
VOIP_SILENCE_DURATION_TIMEOUT_ENABLE: 'VOIP_SILENCE_DURATION_TIMEOUT_ENABLE',
|
|
59
61
|
VOIP_SILENCE_DURATION_TIMEOUT: 'VOIP_SILENCE_DURATION_TIMEOUT',
|
|
60
62
|
VOIP_SILENCE_DURATION_TIMEOUT_START_ENABLE: 'VOIP_SILENCE_DURATION_TIMEOUT_START_ENABLE',
|
|
61
|
-
VOIP_SILENCE_DURATION_TIMEOUT_START: 'VOIP_SILENCE_DURATION_TIMEOUT_START'
|
|
63
|
+
VOIP_SILENCE_DURATION_TIMEOUT_START: 'VOIP_SILENCE_DURATION_TIMEOUT_START',
|
|
64
|
+
VOIP_STT_CONFIDENCE_THRESHOLD: 'VOIP_STT_CONFIDENCE_THRESHOLD'
|
|
62
65
|
};
|
|
63
66
|
const Defaults = {
|
|
64
67
|
VOIP_STT_METHOD: 'POST',
|
|
@@ -74,9 +77,9 @@ const Defaults = {
|
|
|
74
77
|
VOIP_SILENCE_DURATION_TIMEOUT: 2500,
|
|
75
78
|
VOIP_SILENCE_DURATION_TIMEOUT_ENABLE: false,
|
|
76
79
|
VOIP_SILENCE_DURATION_TIMEOUT_START: 1000,
|
|
77
|
-
VOIP_SILENCE_DURATION_TIMEOUT_START_ENABLE: false
|
|
80
|
+
VOIP_SILENCE_DURATION_TIMEOUT_START_ENABLE: false,
|
|
81
|
+
VOIP_STT_CONFIDENCE_THRESHOLD: 0.5
|
|
78
82
|
};
|
|
79
|
-
|
|
80
83
|
class BotiumConnectorVoip {
|
|
81
84
|
constructor({
|
|
82
85
|
queueBotSays,
|
|
@@ -91,11 +94,9 @@ class BotiumConnectorVoip {
|
|
|
91
94
|
this.sentencesFinal = 0;
|
|
92
95
|
this.sentenceBuilding = false;
|
|
93
96
|
}
|
|
94
|
-
|
|
95
97
|
async Validate() {
|
|
96
|
-
debug$
|
|
97
|
-
debug$
|
|
98
|
-
|
|
98
|
+
debug$3('Validate called');
|
|
99
|
+
debug$3(this.caps.VOIP_STT_MESSAGE_HANDLING);
|
|
99
100
|
if (this.caps.VOIP_TTS_URL) {
|
|
100
101
|
this.axiosTtsParams = {
|
|
101
102
|
url: this.caps.VOIP_TTS_URL,
|
|
@@ -104,16 +105,15 @@ class BotiumConnectorVoip {
|
|
|
104
105
|
timeout: this.caps.VOIP_TTS_TIMEOUT,
|
|
105
106
|
headers: this._getHeaders(Capabilities.VOIP_TTS_HEADERS)
|
|
106
107
|
};
|
|
107
|
-
|
|
108
108
|
try {
|
|
109
109
|
const {
|
|
110
110
|
data
|
|
111
|
-
} = await axios__default["default"]({
|
|
111
|
+
} = await axios__default["default"]({
|
|
112
|
+
...this.axiosTtsParams,
|
|
112
113
|
url: this._getAxiosUrl(this.caps.VOIP_TTS_URL, '/api/status')
|
|
113
114
|
});
|
|
114
|
-
|
|
115
115
|
if (data && data.status === 'OK') {
|
|
116
|
-
debug$
|
|
116
|
+
debug$3(`Checking TTS Status response: ${this._getAxiosShortenedOutput(data)}`);
|
|
117
117
|
} else {
|
|
118
118
|
throw new Error(`Checking TTS Status failed, response is: ${this._getAxiosShortenedOutput(data)}`);
|
|
119
119
|
}
|
|
@@ -121,28 +121,23 @@ class BotiumConnectorVoip {
|
|
|
121
121
|
throw new Error(`Checking TTS Status failed - ${this._getAxiosErrOutput(err)}`);
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
|
-
|
|
125
124
|
this.caps = Object.assign({}, Defaults, this.caps);
|
|
126
125
|
}
|
|
127
|
-
|
|
128
126
|
async Start() {
|
|
129
|
-
debug$
|
|
130
|
-
debug$
|
|
127
|
+
debug$3('Start called');
|
|
128
|
+
debug$3(this.caps[Capabilities.VOIP_TTS_URL]);
|
|
131
129
|
this.stopCalled = false;
|
|
132
130
|
this.fullRecord = '';
|
|
133
131
|
this.end = false;
|
|
134
132
|
this.connected = false;
|
|
135
133
|
this.convoStep = null;
|
|
136
|
-
|
|
137
134
|
const sendBotMsg = botMsg => {
|
|
138
135
|
setTimeout(() => this.queueBotSays(botMsg), 0);
|
|
139
136
|
};
|
|
140
|
-
|
|
141
137
|
const joinBotMsg = (botMsgs, joinLastPrevMsg) => {
|
|
142
138
|
const botMsg = {};
|
|
143
|
-
botMsg.messageText = botMsgs.map(m => m.messageText).join(this.caps[Capabilities.VOIP_STT_MESSAGE_HANDLING_DELIMITER]);
|
|
139
|
+
botMsg.messageText = botMsgs.map(m => m.messageText).join(this.caps[Capabilities.VOIP_STT_MESSAGE_HANDLING_DELIMITER] || '');
|
|
144
140
|
botMsg.sourceData = botMsgs.map(m => m.sourceData);
|
|
145
|
-
|
|
146
141
|
if (lodash__default["default"].isNil(joinLastPrevMsg)) {
|
|
147
142
|
botMsg.sourceData[0].silenceDuration = botMsgs[0].sourceData.data.start;
|
|
148
143
|
botMsg.sourceData[0].voiceDuration = botMsgs[botMsgs.length - 1].sourceData.data.end - botMsgs[0].sourceData.data.start;
|
|
@@ -150,23 +145,17 @@ class BotiumConnectorVoip {
|
|
|
150
145
|
botMsg.sourceData[0].silenceDuration = botMsgs[0].sourceData.data.start - joinLastPrevMsg.sourceData.data.end;
|
|
151
146
|
botMsg.sourceData[0].voiceDuration = botMsgs[botMsgs.length - 1].sourceData.data.end - botMsgs[0].sourceData.data.start;
|
|
152
147
|
}
|
|
153
|
-
|
|
154
148
|
return botMsg;
|
|
155
149
|
};
|
|
156
|
-
|
|
157
150
|
const splitBotMsgs = botMsgs => {
|
|
158
151
|
const splitSentences = s => s.match(new RegExp(`[^${this.caps[Capabilities.VOIP_STT_MESSAGE_HANDLING_PUNCTUATION]}]+[${this.caps[Capabilities.VOIP_STT_MESSAGE_HANDLING_PUNCTUATION]}]+`, 'g'));
|
|
159
|
-
|
|
160
152
|
const botMsgsFinal = [];
|
|
161
|
-
|
|
162
153
|
for (const botMsg of botMsgs) {
|
|
163
154
|
const sentences = splitSentences(botMsg.messageText);
|
|
164
|
-
|
|
165
155
|
if (lodash__default["default"].isNil(sentences)) {
|
|
166
156
|
botMsgsFinal.push(botMsg);
|
|
167
157
|
} else {
|
|
168
158
|
let botMsgCount = 0;
|
|
169
|
-
|
|
170
159
|
for (const sentence of sentences) {
|
|
171
160
|
botMsgsFinal.push({
|
|
172
161
|
messageText: sentence,
|
|
@@ -176,16 +165,12 @@ class BotiumConnectorVoip {
|
|
|
176
165
|
}
|
|
177
166
|
}
|
|
178
167
|
}
|
|
179
|
-
|
|
180
168
|
return botMsgsFinal;
|
|
181
169
|
};
|
|
182
|
-
|
|
183
170
|
let data = null;
|
|
184
171
|
let headers = null;
|
|
185
|
-
|
|
186
172
|
const connect = async retryIndex => {
|
|
187
173
|
retryIndex = retryIndex || 0;
|
|
188
|
-
|
|
189
174
|
try {
|
|
190
175
|
const res = await axios__default["default"]({
|
|
191
176
|
method: 'post',
|
|
@@ -194,29 +179,25 @@ class BotiumConnectorVoip {
|
|
|
194
179
|
},
|
|
195
180
|
url: new URL(path__default["default"].join(`${this.caps[Capabilities.VOIP_WORKER_URL].replace('wss', 'https').replace('ws', 'http')}`, 'initCall')).toString()
|
|
196
181
|
});
|
|
197
|
-
|
|
198
182
|
if (res) {
|
|
199
183
|
data = res.data;
|
|
200
184
|
headers = res.headers;
|
|
201
185
|
}
|
|
202
186
|
} catch (err) {
|
|
203
|
-
debug$
|
|
204
|
-
|
|
187
|
+
debug$3(`Retry ${retryIndex} / ${this.caps[Capabilities.VOIP_WEBSOCKET_CONNECT_MAXRETRIES]}: Connecting to VOIP Worker failed: ${err.message || 'Not reachable'}`);
|
|
205
188
|
if (retryIndex === this.caps[Capabilities.VOIP_WEBSOCKET_CONNECT_MAXRETRIES]) {
|
|
206
189
|
throw new Error(`Connecting to VOIP Worker failed: ${err.message || 'Not reachable'}`);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
await new Promise(resolve => setTimeout(resolve, this.caps[Capabilities.VOIP_WEBSOCKET_CONNECT_TIMEOUT])); // Retry the connection
|
|
190
|
+
}
|
|
191
|
+
// Retry after the defined timeout
|
|
192
|
+
await new Promise(resolve => setTimeout(resolve, this.caps[Capabilities.VOIP_WEBSOCKET_CONNECT_TIMEOUT]));
|
|
211
193
|
|
|
194
|
+
// Retry the connection
|
|
212
195
|
await connect(retryIndex + 1);
|
|
213
196
|
}
|
|
214
197
|
};
|
|
215
|
-
|
|
216
198
|
await connect();
|
|
217
199
|
return new Promise((resolve, reject) => {
|
|
218
200
|
const wsEndpoint = `${this.caps[Capabilities.VOIP_WORKER_URL]}/ws/${data.port}`;
|
|
219
|
-
|
|
220
201
|
const connect = retryIndex => {
|
|
221
202
|
retryIndex = retryIndex || 0;
|
|
222
203
|
return new Promise((resolve, reject) => {
|
|
@@ -229,7 +210,6 @@ class BotiumConnectorVoip {
|
|
|
229
210
|
} else {
|
|
230
211
|
this.ws = new ws__default["default"](wsEndpoint);
|
|
231
212
|
}
|
|
232
|
-
|
|
233
213
|
this.ws.on('open', () => {
|
|
234
214
|
resolve();
|
|
235
215
|
});
|
|
@@ -237,12 +217,10 @@ class BotiumConnectorVoip {
|
|
|
237
217
|
if (retryIndex === this.caps[Capabilities.VOIP_WEBSOCKET_CONNECT_MAXRETRIES]) {
|
|
238
218
|
reject(new Error(`Websocket connection failed to ${wsEndpoint}`));
|
|
239
219
|
}
|
|
240
|
-
|
|
241
220
|
setTimeout(() => connect(retryIndex + 1).then(resolve).catch(reject), this.caps[Capabilities.VOIP_WEBSOCKET_CONNECT_TIMEOUT]);
|
|
242
221
|
});
|
|
243
222
|
});
|
|
244
223
|
};
|
|
245
|
-
|
|
246
224
|
connect().then(() => {
|
|
247
225
|
if (!lodash__default["default"].isArray(this.caps[Capabilities.VOIP_ICE_STUN_SERVERS])) {
|
|
248
226
|
if (this.caps[Capabilities.VOIP_ICE_STUN_SERVERS] === '') {
|
|
@@ -251,7 +229,6 @@ class BotiumConnectorVoip {
|
|
|
251
229
|
this.caps[Capabilities.VOIP_ICE_STUN_SERVERS] = this.caps[Capabilities.VOIP_ICE_STUN_SERVERS].split(',');
|
|
252
230
|
}
|
|
253
231
|
}
|
|
254
|
-
|
|
255
232
|
this.eventEmitter.on('CONVO_STEP_NEXT', (container, convoStep) => {
|
|
256
233
|
this.convoStep = convoStep;
|
|
257
234
|
});
|
|
@@ -261,7 +238,7 @@ class BotiumConnectorVoip {
|
|
|
261
238
|
this.firstSttInfoReceived = false;
|
|
262
239
|
this.silenceTimeout = null;
|
|
263
240
|
this.wsOpened = true;
|
|
264
|
-
debug$
|
|
241
|
+
debug$3(`Websocket connection to ${wsEndpoint} opened.`);
|
|
265
242
|
const request = {
|
|
266
243
|
METHOD: 'initCall',
|
|
267
244
|
SIP_CALLER_AUTO: this.caps[Capabilities.VOIP_SIP_POOL_CALLER_ENABLE],
|
|
@@ -292,11 +269,10 @@ class BotiumConnectorVoip {
|
|
|
292
269
|
tts_body: this.caps[Capabilities.VOIP_TTS_BODY] || null
|
|
293
270
|
}
|
|
294
271
|
};
|
|
295
|
-
debug$
|
|
272
|
+
debug$3(JSON.stringify(request, null, 2));
|
|
296
273
|
this.ws.send(JSON.stringify(request));
|
|
297
274
|
this.ws.on('error', err => {
|
|
298
|
-
debug$
|
|
299
|
-
|
|
275
|
+
debug$3(err);
|
|
300
276
|
if (!this.wsOpened) {
|
|
301
277
|
this.end = true;
|
|
302
278
|
reject(new Error(`${this.sessionId} - Websocket connection to ${wsEndpoint} error: ${err.message || err}`));
|
|
@@ -304,30 +280,25 @@ class BotiumConnectorVoip {
|
|
|
304
280
|
});
|
|
305
281
|
this.ws.on('message', async data => {
|
|
306
282
|
const parsedData = JSON.parse(data);
|
|
307
|
-
|
|
308
283
|
const parsedDataLog = lodash__default["default"].cloneDeep(parsedData);
|
|
284
|
+
parsedDataLog.fullRecord = '<full_record_buffer>';
|
|
309
285
|
|
|
310
|
-
|
|
286
|
+
// debug(JSON.stringify(parsedDataLog, null, 2))
|
|
311
287
|
|
|
312
288
|
if (parsedData && parsedData.type === 'callinfo' && parsedData.status === 'initialized') {
|
|
313
289
|
this.sessionId = parsedData.voipConfig.sessionId;
|
|
314
290
|
}
|
|
315
|
-
|
|
316
291
|
if (parsedData && parsedData.type === 'callinfo' && parsedData.status === 'unauthorized') {
|
|
317
292
|
reject(new Error('Error: Cannot open a call: SIP Authorization failed'));
|
|
318
293
|
}
|
|
319
|
-
|
|
320
294
|
if (parsedData && parsedData.type === 'callinfo' && parsedData.status === 'forbidden' && parsedData.event === 'onCallRegState') {
|
|
321
295
|
reject(new Error('Error: Sip Registration failed'));
|
|
322
296
|
}
|
|
323
|
-
|
|
324
297
|
if (parsedData && parsedData.type === 'callinfo' && parsedData.status === 'connected') {
|
|
325
298
|
resolve();
|
|
326
299
|
}
|
|
327
|
-
|
|
328
300
|
if (parsedData && parsedData.type === 'callinfo' && parsedData.status === 'disconnected') {
|
|
329
301
|
const apiKey = this._extractApiKey(this._getBody(Capabilities.VOIP_STT_BODY));
|
|
330
|
-
|
|
331
302
|
if (parsedData.connectDuration && parsedData.connectDuration > 0) {
|
|
332
303
|
this.eventEmitter.emit('CONSUMPTION_METADATA', this, {
|
|
333
304
|
type: lodash__default["default"].isNil(apiKey) ? 'INBUILT' : 'THIRD_PARTY',
|
|
@@ -338,13 +309,11 @@ class BotiumConnectorVoip {
|
|
|
338
309
|
});
|
|
339
310
|
}
|
|
340
311
|
}
|
|
341
|
-
|
|
342
312
|
if (parsedData && parsedData.type === 'error') {
|
|
343
313
|
this.end = true;
|
|
344
314
|
reject(new Error(`Error: ${parsedData.message}`));
|
|
345
315
|
sendBotMsg(new Error(`Error: ${parsedData.message}`));
|
|
346
316
|
}
|
|
347
|
-
|
|
348
317
|
if (parsedData && parsedData.type === 'silence') {
|
|
349
318
|
if (lodash__default["default"].isNil(this._getIgnoreSilenceDurationAsserterLogicHook(this.convoStep))) {
|
|
350
319
|
if (lodash__default["default"].isNil(this._getJoinLogicHook(this.convoStep)) && parsedData.data.silence.length > 0) {
|
|
@@ -353,7 +322,6 @@ class BotiumConnectorVoip {
|
|
|
353
322
|
}
|
|
354
323
|
}
|
|
355
324
|
}
|
|
356
|
-
|
|
357
325
|
if (parsedData && parsedData.type === 'fullRecord') {
|
|
358
326
|
this.eventEmitter.emit('MESSAGE_ATTACHMENT', this.container, {
|
|
359
327
|
name: 'full_record.wav',
|
|
@@ -362,36 +330,28 @@ class BotiumConnectorVoip {
|
|
|
362
330
|
});
|
|
363
331
|
this.end = true;
|
|
364
332
|
}
|
|
365
|
-
|
|
366
333
|
if (parsedData && parsedData.data && parsedData.data.final === false) {
|
|
367
334
|
if (this.silenceTimeout) {
|
|
368
335
|
clearTimeout(this.silenceTimeout);
|
|
369
336
|
}
|
|
370
|
-
|
|
371
337
|
if (lodash__default["default"].isNil(this._getIgnoreSilenceDurationAsserterLogicHook(this.convoStep))) {
|
|
372
338
|
if (!this.firstSttInfoReceived && lodash__default["default"].isNil(this._getJoinLogicHook(this.convoStep)) && this.caps[Capabilities.VOIP_SILENCE_DURATION_TIMEOUT_START_ENABLE] && parsedData.data.start && parsedData.data.start * 1000 > this.caps[Capabilities.VOIP_SILENCE_DURATION_TIMEOUT_START]) {
|
|
373
339
|
this.end = true;
|
|
374
340
|
sendBotMsg(new Error(`Silence Duration of ${parsedData.data.start}s exceeded Initial Silence Duration Timeout of ${this.caps[Capabilities.VOIP_SILENCE_DURATION_TIMEOUT_START] / 1000}s`));
|
|
375
341
|
}
|
|
376
342
|
}
|
|
377
|
-
|
|
378
343
|
this.firstSttInfoReceived = true;
|
|
379
|
-
|
|
380
344
|
if (this.prevData) {
|
|
381
345
|
if (!lodash__default["default"].isNil(parsedData.data.start)) {
|
|
382
346
|
const silenceDuration = parsedData.data.start - this.prevData.data.end;
|
|
383
|
-
|
|
384
347
|
const joinLogicHook = this._getJoinLogicHook(this.convoStep);
|
|
385
|
-
|
|
386
348
|
const isJoinMethod = this.caps[Capabilities.VOIP_STT_MESSAGE_HANDLING] === 'JOIN';
|
|
387
349
|
let matched = false;
|
|
388
|
-
|
|
389
350
|
if ((!lodash__default["default"].isNil(joinLogicHook) && isJoinMethod && silenceDuration > parseInt(joinLogicHook.args[0])) / 1000) {
|
|
390
351
|
matched = true;
|
|
391
352
|
} else if (lodash__default["default"].isNil(joinLogicHook) && isJoinMethod && silenceDuration > parseInt(this.caps[Capabilities.VOIP_STT_MESSAGE_HANDLING_TIMEOUT]) / 1000) {
|
|
392
353
|
matched = true;
|
|
393
354
|
}
|
|
394
|
-
|
|
395
355
|
if (matched && this.botMsgs.length > 0) {
|
|
396
356
|
sendBotMsg(joinBotMsg(this.botMsgs, this.joinLastPrevMsg));
|
|
397
357
|
this.firstMsg = false;
|
|
@@ -401,13 +361,14 @@ class BotiumConnectorVoip {
|
|
|
401
361
|
}
|
|
402
362
|
}
|
|
403
363
|
}
|
|
404
|
-
|
|
405
364
|
if (parsedData && parsedData.data && parsedData.data.type === 'stt' && parsedData.data.final) {
|
|
365
|
+
const confidenceThreshold = this._getConfidenceScoreLogicHook(this.convoStep) && this._getConfidenceScoreLogicHook(this.convoStep).args[0] || this.caps[Capabilities.VOIP_STT_CONFIDENCE_THRESHOLD];
|
|
366
|
+
const successfulConfidenceScore = this._getConfidenceScore(parsedData) >= confidenceThreshold;
|
|
367
|
+
debug$3(`Message: ${parsedData.data.message} / Confidence Score: ${this._getConfidenceScore(parsedData)} (Threshold: ${confidenceThreshold})`);
|
|
406
368
|
if (this.caps[Capabilities.VOIP_STT_MESSAGE_HANDLING] === 'ORIGINAL' && lodash__default["default"].isNil(this._getJoinLogicHook(this.convoStep))) {
|
|
407
369
|
let botMsg = {
|
|
408
370
|
messageText: parsedData.data.message
|
|
409
371
|
};
|
|
410
|
-
|
|
411
372
|
if (this.firstMsg) {
|
|
412
373
|
const sourceData = parsedData;
|
|
413
374
|
sourceData.silenceDuration = parsedData.data.start;
|
|
@@ -424,18 +385,17 @@ class BotiumConnectorVoip {
|
|
|
424
385
|
sourceData
|
|
425
386
|
});
|
|
426
387
|
}
|
|
427
|
-
|
|
428
388
|
this.prevData = parsedData;
|
|
429
|
-
|
|
430
|
-
|
|
389
|
+
if (successfulConfidenceScore) {
|
|
390
|
+
this.botMsgs.push(botMsg);
|
|
391
|
+
this.botMsgs.forEach(botMsg => sendBotMsg(botMsg));
|
|
392
|
+
}
|
|
431
393
|
this.botMsgs = [];
|
|
432
394
|
}
|
|
433
|
-
|
|
434
395
|
if (this.caps[Capabilities.VOIP_STT_MESSAGE_HANDLING] === 'SPLIT' || this.caps[Capabilities.VOIP_STT_MESSAGE_HANDLING] === 'EXPAND') {
|
|
435
396
|
let botMsg = {
|
|
436
397
|
messageText: parsedData.data.message
|
|
437
398
|
};
|
|
438
|
-
|
|
439
399
|
if (this.firstMsg) {
|
|
440
400
|
const sourceData = parsedData;
|
|
441
401
|
sourceData.silenceDuration = parsedData.data.start;
|
|
@@ -452,31 +412,32 @@ class BotiumConnectorVoip {
|
|
|
452
412
|
sourceData
|
|
453
413
|
});
|
|
454
414
|
}
|
|
455
|
-
|
|
456
415
|
this.prevData = parsedData;
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
416
|
+
if (successfulConfidenceScore) {
|
|
417
|
+
this.botMsgs.push(botMsg);
|
|
418
|
+
const botMsgsExpanded = splitBotMsgs(this.botMsgs);
|
|
419
|
+
botMsgsExpanded.forEach(botMsg => sendBotMsg(botMsg));
|
|
420
|
+
}
|
|
460
421
|
this.botMsgs = [];
|
|
461
422
|
}
|
|
462
|
-
|
|
463
423
|
if (this.caps[Capabilities.VOIP_STT_MESSAGE_HANDLING] === 'JOIN' || this.caps[Capabilities.VOIP_STT_MESSAGE_HANDLING] === 'CONCAT' || !lodash__default["default"].isNil(this._getJoinLogicHook(this.convoStep))) {
|
|
464
424
|
const botMsg = {
|
|
465
425
|
messageText: parsedData.data.message,
|
|
466
426
|
sourceData: parsedData
|
|
467
427
|
};
|
|
468
|
-
this.botMsgs.push(botMsg);
|
|
469
428
|
this.prevData = parsedData;
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
429
|
+
if (successfulConfidenceScore) {
|
|
430
|
+
this.botMsgs.push(botMsg);
|
|
431
|
+
this.silenceTimeout = setTimeout(() => {
|
|
432
|
+
if (this.botMsgs.length > 0) {
|
|
433
|
+
debug$3('Silence Duration Timeout (PSST):', this._getJoinLogicHook(this.convoStep) && parseInt(this._getJoinLogicHook(this.convoStep).args[0]) || this.caps[Capabilities.VOIP_STT_MESSAGE_HANDLING_TIMEOUT], 'ms');
|
|
434
|
+
sendBotMsg(joinBotMsg(this.botMsgs, this.joinLastPrevMsg));
|
|
435
|
+
this.firstMsg = false;
|
|
436
|
+
this.joinLastPrevMsg = this.botMsgs[this.botMsgs.length - 1];
|
|
437
|
+
this.botMsgs = [];
|
|
438
|
+
}
|
|
439
|
+
}, this._getJoinLogicHook(this.convoStep) && parseInt(this._getJoinLogicHook(this.convoStep).args[0]) || this.caps[Capabilities.VOIP_STT_MESSAGE_HANDLING_TIMEOUT]);
|
|
440
|
+
}
|
|
480
441
|
}
|
|
481
442
|
}
|
|
482
443
|
});
|
|
@@ -485,19 +446,15 @@ class BotiumConnectorVoip {
|
|
|
485
446
|
});
|
|
486
447
|
});
|
|
487
448
|
}
|
|
488
|
-
|
|
489
449
|
async UserSays(msg) {
|
|
490
|
-
debug$
|
|
491
|
-
debug$
|
|
492
|
-
|
|
450
|
+
debug$3('UserSays called');
|
|
451
|
+
debug$3(msg);
|
|
493
452
|
if (!msg.attachments) {
|
|
494
453
|
msg.attachments = [];
|
|
495
454
|
}
|
|
496
|
-
|
|
497
455
|
return new Promise((resolve, reject) => {
|
|
498
456
|
setTimeout(async () => {
|
|
499
457
|
let duration = 0;
|
|
500
|
-
|
|
501
458
|
if (msg && msg.buttons && msg.buttons.length > 0) {
|
|
502
459
|
const request = JSON.stringify({
|
|
503
460
|
METHOD: 'sendDtmf',
|
|
@@ -507,10 +464,11 @@ class BotiumConnectorVoip {
|
|
|
507
464
|
this.ws.send(request);
|
|
508
465
|
} else if (msg && msg.messageText) {
|
|
509
466
|
if (!this.axiosTtsParams) reject(new Error('TTS not configured, only audio input supported'));
|
|
510
|
-
|
|
511
467
|
if (this.axiosTtsParams) {
|
|
512
|
-
const ttsRequest = {
|
|
513
|
-
|
|
468
|
+
const ttsRequest = {
|
|
469
|
+
...this.axiosTtsParams,
|
|
470
|
+
params: {
|
|
471
|
+
...(this.axiosTtsParams.params || {}),
|
|
514
472
|
text: msg.messageText
|
|
515
473
|
},
|
|
516
474
|
data: this._getBody(Capabilities.VOIP_TTS_BODY),
|
|
@@ -518,16 +476,13 @@ class BotiumConnectorVoip {
|
|
|
518
476
|
};
|
|
519
477
|
msg.sourceData = ttsRequest;
|
|
520
478
|
let ttsResponse = null;
|
|
521
|
-
|
|
522
479
|
try {
|
|
523
480
|
ttsResponse = await axios__default["default"](ttsRequest);
|
|
524
481
|
} catch (err) {
|
|
525
482
|
reject(new Error(`TTS "${msg.messageText}" failed - ${this._getAxiosErrOutput(err)}`));
|
|
526
483
|
}
|
|
527
|
-
|
|
528
484
|
if (msg && msg.messageText && msg.messageText.length > 0) {
|
|
529
485
|
const apiKey = this._extractApiKey(this._getBody(Capabilities.VOIP_TTS_BODY));
|
|
530
|
-
|
|
531
486
|
this.eventEmitter.emit('CONSUMPTION_METADATA', this.container, {
|
|
532
487
|
type: lodash__default["default"].isNil(apiKey) ? 'INBUILT' : 'THIRD_PARTY',
|
|
533
488
|
metricName: 'consumption.e2e.voip.tts.characters',
|
|
@@ -535,7 +490,6 @@ class BotiumConnectorVoip {
|
|
|
535
490
|
apiKey
|
|
536
491
|
});
|
|
537
492
|
}
|
|
538
|
-
|
|
539
493
|
if (Buffer.isBuffer(ttsResponse.data)) {
|
|
540
494
|
duration = ttsResponse.headers['content-duration'];
|
|
541
495
|
const request = JSON.stringify({
|
|
@@ -555,7 +509,6 @@ class BotiumConnectorVoip {
|
|
|
555
509
|
}
|
|
556
510
|
}
|
|
557
511
|
}
|
|
558
|
-
|
|
559
512
|
if (msg && msg.media && msg.media.length > 0 && msg.media[0].buffer) {
|
|
560
513
|
const request = JSON.stringify({
|
|
561
514
|
METHOD: 'sendAudio',
|
|
@@ -568,34 +521,24 @@ class BotiumConnectorVoip {
|
|
|
568
521
|
mimeType: msg.media[0].mimeType,
|
|
569
522
|
base64: msg.media[0].buffer.toString('base64')
|
|
570
523
|
});
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
'
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
maxBodyLength: Infinity
|
|
582
|
-
});
|
|
583
|
-
|
|
584
|
-
if (data && data.duration) {
|
|
585
|
-
duration = parseInt(data.duration);
|
|
586
|
-
} else {
|
|
587
|
-
reject(new Error('Getting audio duration from Speech Api failed'));
|
|
524
|
+
try {
|
|
525
|
+
const metadata = await musicMetadata__default["default"].parseBuffer(msg.media[0].buffer);
|
|
526
|
+
if (metadata && metadata.format && metadata.format.duration) {
|
|
527
|
+
debug$3('Audio duration of user audio:', metadata.format.duration, 'seconds');
|
|
528
|
+
duration = Math.round(metadata.format.duration);
|
|
529
|
+
} else {
|
|
530
|
+
reject(new Error('Could not determine audio duration from metadata'));
|
|
531
|
+
}
|
|
532
|
+
} catch (err) {
|
|
533
|
+
reject(new Error(`Getting audio duration failed: ${err.message}`));
|
|
588
534
|
}
|
|
589
535
|
}
|
|
590
|
-
|
|
591
536
|
setTimeout(resolve, duration * 1000);
|
|
592
537
|
}, 0);
|
|
593
538
|
});
|
|
594
539
|
}
|
|
595
|
-
|
|
596
540
|
async Stop() {
|
|
597
|
-
debug$
|
|
598
|
-
|
|
541
|
+
debug$3(`${this.sessionId} - Stop called`);
|
|
599
542
|
if (this.ws && this.ws.readyState !== ws__default["default"].CLOSED) {
|
|
600
543
|
const request = JSON.stringify({
|
|
601
544
|
METHOD: 'stopCall',
|
|
@@ -623,35 +566,27 @@ class BotiumConnectorVoip {
|
|
|
623
566
|
this.firstSttInfoReceived = false;
|
|
624
567
|
}
|
|
625
568
|
}
|
|
626
|
-
|
|
627
569
|
_getParams(capParams) {
|
|
628
570
|
if (this.caps[capParams]) {
|
|
629
571
|
if (lodash__default["default"].isString(this.caps[capParams])) return JSON.parse(this.caps[capParams]);else return this.caps[capParams];
|
|
630
572
|
}
|
|
631
|
-
|
|
632
573
|
return {};
|
|
633
574
|
}
|
|
634
|
-
|
|
635
575
|
_getBody(capBody) {
|
|
636
576
|
if (this.caps[capBody]) {
|
|
637
577
|
if (lodash__default["default"].isString(this.caps[capBody])) return JSON.parse(this.caps[capBody]);else return this.caps[capBody];
|
|
638
578
|
}
|
|
639
|
-
|
|
640
579
|
return null;
|
|
641
580
|
}
|
|
642
|
-
|
|
643
581
|
_getHeaders(capHeaders) {
|
|
644
582
|
if (this.caps[capHeaders]) {
|
|
645
583
|
if (lodash__default["default"].isString(this.caps[capHeaders])) return JSON.parse(this.caps[capHeaders]);else return this.caps[capHeaders];
|
|
646
584
|
}
|
|
647
|
-
|
|
648
585
|
return {};
|
|
649
586
|
}
|
|
650
|
-
|
|
651
587
|
_getAxiosUrl(baseUrl, extUrl) {
|
|
652
588
|
return baseUrl.substr(0, baseUrl.indexOf('/', 8)) + extUrl;
|
|
653
589
|
}
|
|
654
|
-
|
|
655
590
|
_getAxiosShortenedOutput(data) {
|
|
656
591
|
if (data) {
|
|
657
592
|
if (lodash__default["default"].isBuffer(data)) {
|
|
@@ -659,7 +594,6 @@ class BotiumConnectorVoip {
|
|
|
659
594
|
data = data.toString();
|
|
660
595
|
} catch (err) {}
|
|
661
596
|
}
|
|
662
|
-
|
|
663
597
|
return lodash__default["default"].truncate(lodash__default["default"].isString(data) ? data : JSON.stringify(data), {
|
|
664
598
|
length: 200
|
|
665
599
|
});
|
|
@@ -667,7 +601,6 @@ class BotiumConnectorVoip {
|
|
|
667
601
|
return '';
|
|
668
602
|
}
|
|
669
603
|
}
|
|
670
|
-
|
|
671
604
|
_getAxiosErrOutput(err) {
|
|
672
605
|
if (err && err.response) {
|
|
673
606
|
return `Status: ${err.response.status} / Response: ${this._getAxiosShortenedOutput(err.response.data)}`;
|
|
@@ -675,53 +608,71 @@ class BotiumConnectorVoip {
|
|
|
675
608
|
return err.message;
|
|
676
609
|
}
|
|
677
610
|
}
|
|
678
|
-
|
|
679
611
|
_extractApiKey(body) {
|
|
680
612
|
return lodash__default["default"].get(body, 'polly.credentials.accessKeyId') || lodash__default["default"].get(body, 'google.credentials.client_email') || lodash__default["default"].get(body, 'ibm.credentials.apikey') || lodash__default["default"].get(body, 'awstranscribe.credentials.accessKeyId') || lodash__default["default"].get(body, 'azure.credentials.subscriptionKey') || null;
|
|
681
613
|
}
|
|
682
|
-
|
|
683
614
|
_getJoinLogicHook(convoStep) {
|
|
684
615
|
if (lodash__default["default"].isNil(convoStep)) return null;
|
|
685
616
|
if (lodash__default["default"].isNil(convoStep.logicHooks)) return null;
|
|
686
617
|
return convoStep && convoStep.logicHooks && convoStep.logicHooks.find(lh => lh.name === 'VOIP_JOIN_SILENCE_DURATION');
|
|
687
618
|
}
|
|
688
|
-
|
|
689
619
|
_getIgnoreSilenceDurationAsserterLogicHook(convoStep) {
|
|
690
620
|
if (lodash__default["default"].isNil(convoStep)) return null;
|
|
691
621
|
if (lodash__default["default"].isNil(convoStep.logicHooks)) return null;
|
|
692
622
|
return convoStep && convoStep.logicHooks && convoStep.logicHooks.find(lh => lh.name === 'VOIP_IGNORE_SILENCE_DURATION');
|
|
693
623
|
}
|
|
694
|
-
|
|
624
|
+
_getConfidenceScoreLogicHook(convoStep) {
|
|
625
|
+
if (lodash__default["default"].isNil(convoStep)) return null;
|
|
626
|
+
if (lodash__default["default"].isNil(convoStep.logicHooks)) return null;
|
|
627
|
+
return convoStep && convoStep.logicHooks && convoStep.logicHooks.find(lh => lh.name === 'VOIP_CONFIDENCE_THRESHOLD');
|
|
628
|
+
}
|
|
629
|
+
_getConfidenceScore(parsedData) {
|
|
630
|
+
// Azure Speech Service
|
|
631
|
+
if (parsedData?.data?.source?.debug?.privJson) {
|
|
632
|
+
const privJson = JSON.parse(parsedData?.data?.source?.debug?.privJson);
|
|
633
|
+
if (privJson && privJson.NBest && privJson.NBest.length > 0) {
|
|
634
|
+
return Math.max(...privJson.NBest.map(n => n.Confidence));
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
return null;
|
|
638
|
+
}
|
|
695
639
|
}
|
|
696
|
-
|
|
697
640
|
var connector = BotiumConnectorVoip;
|
|
698
641
|
|
|
699
|
-
const debug$
|
|
642
|
+
const debug$2 = debug__default["default"]('botium-voip-logichook-ignore-silence-duration');
|
|
700
643
|
var ignoreSdLogichook = class IgnoreSilenceDurationLogicHook {
|
|
701
644
|
constructor(context, caps = {}, args = {}) {
|
|
702
645
|
this.context = context;
|
|
703
646
|
this.caps = caps;
|
|
704
647
|
this.globalArgs = args;
|
|
705
648
|
}
|
|
706
|
-
|
|
707
649
|
async onBotPrepare(props) {
|
|
708
|
-
debug$
|
|
650
|
+
debug$2('Silence duration assertion ignored by logic hook');
|
|
709
651
|
}
|
|
710
|
-
|
|
711
652
|
};
|
|
712
653
|
|
|
713
|
-
const debug = debug__default["default"]('botium-voip-logichook-join-silence-duration');
|
|
654
|
+
const debug$1 = debug__default["default"]('botium-voip-logichook-join-silence-duration');
|
|
714
655
|
var joinLogichook = class JoinLogicHook {
|
|
715
656
|
constructor(context, caps = {}, args = {}) {
|
|
716
657
|
this.context = context;
|
|
717
658
|
this.caps = caps;
|
|
718
659
|
this.globalArgs = args;
|
|
719
660
|
}
|
|
720
|
-
|
|
721
661
|
async onBotPrepare(props) {
|
|
722
|
-
debug('Joined bot messages because of JOIN logic hook');
|
|
662
|
+
debug$1('Joined bot messages because of JOIN logic hook');
|
|
723
663
|
}
|
|
664
|
+
};
|
|
724
665
|
|
|
666
|
+
const debug = debug__default["default"]('botium-voip-logichook-confidence-threshold');
|
|
667
|
+
var confidenceThresholdLogichook = class ConfidenceThresholdLogicHook {
|
|
668
|
+
constructor(context, caps = {}, args = {}) {
|
|
669
|
+
this.context = context;
|
|
670
|
+
this.caps = caps;
|
|
671
|
+
this.globalArgs = args;
|
|
672
|
+
}
|
|
673
|
+
async onBotPrepare(props) {
|
|
674
|
+
debug('Updated confidence threshold because of ConfidenceThreshold LogicHook');
|
|
675
|
+
}
|
|
725
676
|
};
|
|
726
677
|
|
|
727
678
|
var botiumConnectorVoip = {
|
|
@@ -748,7 +699,8 @@ var botiumConnectorVoip = {
|
|
|
748
699
|
},
|
|
749
700
|
PluginLogicHooks: {
|
|
750
701
|
VOIP_IGNORE_SILENCE_DURATION: ignoreSdLogichook,
|
|
751
|
-
VOIP_JOIN_SILENCE_DURATION: joinLogichook
|
|
702
|
+
VOIP_JOIN_SILENCE_DURATION: joinLogichook,
|
|
703
|
+
VOIP_CONFIDENCE_THRESHOLD: confidenceThresholdLogichook
|
|
752
704
|
}
|
|
753
705
|
};
|
|
754
706
|
var botiumConnectorVoip_1 = botiumConnectorVoip.PluginVersion;
|