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