wingbot 3.46.0-alpha.1 → 3.46.0-alpha.10

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wingbot",
3
- "version": "3.46.0-alpha.1",
3
+ "version": "3.46.0-alpha.10",
4
4
  "description": "Enterprise Messaging Bot Conversation Engine",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -9,7 +9,7 @@
9
9
  "doc": "npm run doc:gql && node ./bin/makeApiDoc.js && cpy ./CHANGELOG.md ./doc && gitbook install ./doc && gitbook build ./doc && rimraf -rf ./docs && rimraf --rf ./doc/CHANGELOG.md && move-cli ./doc/_book ./docs",
10
10
  "test": "npm run test:lint && npm run test:coverage && npm run test:coverage:threshold",
11
11
  "test:coverage": "nyc --reporter=html mocha ./test && nyc report",
12
- "test:coverage:threshold": "nyc check-coverage --lines 90 --functions 90 --branches 80",
12
+ "test:coverage:threshold": "nyc check-coverage --lines 90 --functions 89 --branches 80",
13
13
  "test:backend": "mocha ./test",
14
14
  "test:lint": "eslint --ext .js src test *.js plugins"
15
15
  },
@@ -42,6 +42,10 @@ const TrackingType = { // max length 12
42
42
  * @enum {string} TrackingCategory
43
43
  */
44
44
  const TrackingCategory = { // max length 3
45
+ // PAGE_VIEW: 'page_view'
46
+ PAGE_VIEW_FIRST: 'pf',
47
+ PAGE_VIEW_SUBSEQUENT: 'pp',
48
+
45
49
  // CONVERSATION_EVENT: 'conversation'
46
50
  STICKER: 'sti',
47
51
  IMAGE: 'img',
@@ -58,18 +62,22 @@ const TrackingCategory = { // max length 3
58
62
 
59
63
  // TRAINING: 'train'
60
64
  INTENT_DETECTION: 'int',
61
- HANDOVER_OCCURRED: 'hum',
62
65
  DISAMBIGUATION_SELECTED: 'dis',
63
66
  DISAMBIGUATION_OFFERED: 'dio',
64
67
 
65
68
  // REPORT: 'report'
66
- REPORT_FEEDBACK: 'fdb'
69
+ REPORT_FEEDBACK: 'fdb',
70
+ HANDOVER_OCCURRED: 'hum'
67
71
  };
68
72
 
69
73
  /**
70
74
  * @type {Object<TrackingCategory,string>}
71
75
  */
72
76
  const CATEGORY_LABELS = {
77
+ // PAGE_VIEW: 'page_view'
78
+ [TrackingCategory.PAGE_VIEW_FIRST]: 'Bot: Interaction',
79
+ [TrackingCategory.PAGE_VIEW_SUBSEQUENT]: 'Bot: Sub-interaction',
80
+
73
81
  // CONVERSATION_EVENT: 'conversation'
74
82
  [TrackingCategory.STICKER]: 'User: Sticker',
75
83
  [TrackingCategory.IMAGE]: 'User: Image',
@@ -86,12 +94,12 @@ const CATEGORY_LABELS = {
86
94
 
87
95
  // TRAINING: 'train'
88
96
  [TrackingCategory.INTENT_DETECTION]: 'Intent: Detection',
89
- [TrackingCategory.HANDOVER_OCCURRED]: 'Bot: Handover out',
90
97
  [TrackingCategory.DISAMBIGUATION_SELECTED]: 'Disambiguation: selected',
91
98
  [TrackingCategory.DISAMBIGUATION_OFFERED]: 'Disambiguation: offered',
92
99
 
93
100
  // REPORT: 'report'
94
- [TrackingCategory.REPORT_FEEDBACK]: 'User: Feedback'
101
+ [TrackingCategory.REPORT_FEEDBACK]: 'User: Feedback',
102
+ [TrackingCategory.HANDOVER_OCCURRED]: 'Bot: Handover out'
95
103
  };
96
104
 
97
105
  module.exports = {
@@ -31,6 +31,56 @@ const {
31
31
  * @prop {string} [action]
32
32
  * @prop {string} [label]
33
33
  * @prop {number} [value]
34
+ * @prop {string} [lang]
35
+ */
36
+
37
+ /**
38
+ * @typedef {object} ConversationEventExtension
39
+ * @prop {string} [lastAction]
40
+ * @prop {string} [skill]
41
+ * @prop {string} [text]
42
+ * @prop {string} [expected]
43
+ * @prop {boolean} expectedTaken
44
+ * @prop {boolean} isContextUpdate
45
+ * @prop {boolean} isAttachment
46
+ * @prop {boolean} isNotification
47
+ * @prop {boolean} isQuickReply
48
+ * @prop {boolean} isPassThread
49
+ * @prop {boolean} isPostback
50
+ * @prop {boolean} isText
51
+ * @prop {boolean} didHandover
52
+ * @prop {boolean} withUser
53
+ * @prop {string} [userId]
54
+ * @prop {number} [feedback]
55
+ * @prop {string} [winnerAction]
56
+ * @prop {string} [winnerIntent]
57
+ * @prop {string[]|string} [winnerEntities]
58
+ * @prop {number} [winnerScore]
59
+ * @prop {boolean} [winnerTaken]
60
+ * @prop {string} [intent]
61
+ * @prop {number} [intentScore]
62
+ * @prop {string[]|string} [entities]
63
+ * @prop {string[]|string} allActions
64
+ * @prop {boolean} nonInteractive
65
+ *
66
+ * @typedef {Event & ConversationEventExtension} ConversationEvent
67
+ */
68
+
69
+ /**
70
+ * @typedef {object} PageViewEventExtension
71
+ * @prop {string} [lastAction]
72
+ * @prop {string} [prevAction]
73
+ * @prop {string} [skill]
74
+ * @prop {string[]|string} allActions
75
+ * @prop {boolean} nonInteractive
76
+ * @prop {boolean} isGoto
77
+ * @prop {boolean} withUser
78
+ *
79
+ * @typedef {Event & PageViewEventExtension} PageViewEvent
80
+ */
81
+
82
+ /**
83
+ * @typedef {ConversationEvent | Event | PageViewEvent} TrackingEvent
34
84
  */
35
85
 
36
86
  /**
@@ -40,6 +90,11 @@ const {
40
90
  * @prop {string} [action]
41
91
  * @prop {string} [snapshot]
42
92
  * @prop {string} [botId]
93
+ * @prop {boolean} [didHandover]
94
+ * @prop {number|null} [feedback]
95
+ * @prop {string} [timeZone]
96
+ * @prop {number} [sessionStart]
97
+ * @prop {number} [sessionDuration]
43
98
  */
44
99
 
45
100
  /**
@@ -50,7 +105,6 @@ const {
50
105
  * @param {SessionMetadata} [metadata]
51
106
  * @param {number} [ts]
52
107
  * @param {boolean} [nonInteractive]
53
- * @param {string} [timeZone]
54
108
  * @returns {Promise}
55
109
  */
56
110
 
@@ -59,12 +113,12 @@ const {
59
113
  * @param {string} pageId
60
114
  * @param {string} senderId
61
115
  * @param {string} sessionId
62
- * @param {Event[]} events
116
+ * @param {TrackingEvent[]} events
63
117
  * @param {GAUser} [user]
64
118
  * @param {number} [ts]
65
119
  * @param {boolean} [nonInteractive]
66
120
  * @param {boolean} [sessionStarted]
67
- * @param {string} [timeZone]
121
+ * @param {SessionMetadata} [metadata]
68
122
  * @returns {Promise}
69
123
  */
70
124
 
@@ -82,6 +136,7 @@ const {
82
136
  * @prop {boolean} [supportsArrays]
83
137
  * @prop {boolean} [useDescriptiveCategories]
84
138
  * @prop {boolean} [useExtendedScalars]
139
+ * @prop {boolean} [parallelSessionInsert]
85
140
  */
86
141
 
87
142
  /**
@@ -98,7 +153,7 @@ const {
98
153
 
99
154
  /**
100
155
  * @typedef {object} TrackingEvents
101
- * @prop {Event[]} events
156
+ * @prop {TrackingEvent[]} events
102
157
  */
103
158
 
104
159
  /**
@@ -160,13 +215,14 @@ function onInteractionHandler (
160
215
  supportsArrays = false,
161
216
  useExtendedScalars = false,
162
217
  hasExtendedEvents = false,
163
- useDescriptiveCategories = true
218
+ useDescriptiveCategories = true,
219
+ parallelSessionInsert = false
164
220
  } = analyticsStorage;
165
221
 
166
222
  const asArray = (data = []) => (supportsArrays ? data : data.join(','));
167
223
  const asCategory = (cat) => (useDescriptiveCategories && CATEGORY_LABELS[cat]) || cat;
168
224
  const noneAction = useExtendedScalars ? null : '(none)';
169
- const noneValue = useExtendedScalars ? -1 : 0;
225
+ const noneValue = useExtendedScalars ? null : 0;
170
226
 
171
227
  /**
172
228
  * @param {InteractionEvent} params
@@ -201,26 +257,59 @@ function onInteractionHandler (
201
257
  lang
202
258
  } = req.state;
203
259
 
260
+ const trackEvents = [];
261
+
204
262
  const [action = noneAction, ...otherActions] = actions;
205
263
 
206
- if (createSession) {
207
- const metadata = {
208
- sessionCount,
209
- lang,
210
- action,
211
- snapshot,
212
- botId
213
- };
264
+ const feedbackEvent = events.find((e) => e.type === TrackingType.REPORT
265
+ && e.category === TrackingCategory.REPORT_FEEDBACK);
266
+ const feedback = feedbackEvent
267
+ ? feedbackEvent.value
268
+ : noneValue;
269
+ let didHandover = flag === ResponseFlag.HANDOVER;
270
+ const hasHandoverEvent = events
271
+ .some((e) => e.category === TrackingCategory.HANDOVER_OCCURRED);
272
+
273
+ if (didHandover && !hasHandoverEvent) {
274
+ trackEvents.push({
275
+ type: TrackingType.REPORT,
276
+ category: asCategory(TrackingCategory.HANDOVER_OCCURRED),
277
+ action: null,
278
+ label: null,
279
+ value: noneValue
280
+ });
281
+ } else if (hasHandoverEvent) {
282
+ didHandover = true;
283
+ }
284
+
285
+ const metadata = {
286
+ sessionCount,
287
+ lang,
288
+ action,
289
+ snapshot,
290
+ botId,
291
+ didHandover,
292
+ feedback,
293
+ timeZone,
294
+ sessionStart,
295
+ sessionDuration: sessionTs - sessionStart
296
+ };
214
297
 
215
- await analyticsStorage.createUserSession(
298
+ let sessionPromise;
299
+ if (createSession) {
300
+ sessionPromise = analyticsStorage.createUserSession(
216
301
  pageId,
217
302
  senderId,
218
303
  sessionId,
219
304
  metadata,
220
305
  timestamp,
221
- nonInteractive,
222
- timeZone
306
+ nonInteractive
223
307
  );
308
+
309
+ if (!parallelSessionInsert) {
310
+ await sessionPromise;
311
+ sessionPromise = null;
312
+ }
224
313
  }
225
314
 
226
315
  const [{
@@ -233,6 +322,7 @@ function onInteractionHandler (
233
322
  : anonymize(
234
323
  replaceDiacritics(req.text()).replace(/\s+/g, ' ').toLowerCase().trim()
235
324
  );
325
+ const useSkill = (skill && webalize(skill)) || noneAction;
236
326
 
237
327
  let winnerAction = '';
238
328
  let winnerScore = 0;
@@ -253,14 +343,6 @@ function onInteractionHandler (
253
343
  }
254
344
 
255
345
  const expected = req.expected() ? req.expected().action : '';
256
-
257
- const feedbackEvent = events.find((e) => e.type === TrackingType.REPORT
258
- && e.category === TrackingCategory.REPORT_FEEDBACK);
259
- const feedback = feedbackEvent
260
- ? feedbackEvent.value
261
- : noneValue;
262
- const didHandover = flag === ResponseFlag.HANDOVER;
263
-
264
346
  const user = userExtractor(req.state);
265
347
 
266
348
  const isContextUpdate = req.isSetContext();
@@ -274,12 +356,12 @@ function onInteractionHandler (
274
356
  const allActions = asArray(actions);
275
357
  const requestAction = req.action();
276
358
 
277
- const trackEvents = [];
278
-
279
359
  const langsExtension = hasExtendedEvents
280
360
  ? { lang }
281
361
  : { cd1: lang };
282
362
 
363
+ const withUser = user !== null && !!user.id;
364
+
283
365
  const actionMeta = {
284
366
  requestAction: req.action() || noneAction,
285
367
  expected,
@@ -292,13 +374,9 @@ function onInteractionHandler (
292
374
  isText,
293
375
  isPostback,
294
376
  didHandover,
295
- withUser: user !== null && !!user.id,
296
- sessionStart,
297
- sessionDuration: sessionTs - sessionStart,
377
+ withUser,
298
378
  feedback,
299
- skill: webalize(skill),
300
- snapshot,
301
- botId,
379
+ skill: useSkill,
302
380
  winnerAction,
303
381
  winnerIntent,
304
382
  winnerEntities: asArray(winnerEntities.map((e) => e.entity)),
@@ -311,16 +389,24 @@ function onInteractionHandler (
311
389
  allActions
312
390
  };
313
391
 
392
+ const notHandled = actions.some((a) => a.match(/\*$/)) && !req.isQuickReply();
393
+ const value = notHandled ? 1 : 0;
394
+
314
395
  trackEvents.push({
315
396
  type: TrackingType.PAGE_VIEW,
397
+ category: asCategory(TrackingCategory.PAGE_VIEW_FIRST),
316
398
  action,
399
+ label: (isText || isQuickReply ? text : null),
400
+ value,
317
401
  allActions,
318
402
  nonInteractive,
319
403
  lastAction,
404
+ // @ts-ignore
320
405
  prevAction: lastAction,
321
- skill,
322
- lang,
323
- cd1: req.state.lang,
406
+ skill: useSkill,
407
+ isGoto: false,
408
+ withUser,
409
+ ...langsExtension,
324
410
  ...(hasExtendedEvents ? {} : actionMeta)
325
411
  });
326
412
 
@@ -330,12 +416,14 @@ function onInteractionHandler (
330
416
  ...otherActions.map((a) => {
331
417
  const r = {
332
418
  type: TrackingType.PAGE_VIEW,
419
+ category: asCategory(TrackingCategory.PAGE_VIEW_SUBSEQUENT),
333
420
  action: a,
421
+ value: 0,
334
422
  allActions,
335
423
  nonInteractive: false,
336
424
  lastAction,
337
425
  prevAction,
338
- skill,
426
+ skill: useSkill,
339
427
  isGoto: true,
340
428
  ...langsExtension
341
429
  };
@@ -347,14 +435,14 @@ function onInteractionHandler (
347
435
 
348
436
  trackEvents.push(
349
437
  ...events.map(({
350
- type, category, action: eventAction, label, value
438
+ type, category, action: eventAction, label, value: eVal
351
439
  }) => ({
352
440
  lastAction,
353
441
  type,
354
- category,
442
+ category: asCategory(category),
355
443
  action: eventAction,
356
444
  label,
357
- value,
445
+ value: eVal,
358
446
  ...langsExtension
359
447
  }))
360
448
  );
@@ -375,11 +463,8 @@ function onInteractionHandler (
375
463
  });
376
464
  }
377
465
 
378
- const notHandled = actions.some((a) => a.match(/\*$/)) && !req.isQuickReply();
379
-
380
466
  let actionCategory;
381
467
  let label = noneAction;
382
- const value = notHandled ? 1 : 0;
383
468
 
384
469
  if (isPassThread) {
385
470
  actionCategory = TrackingCategory.HANDOVER_TO_BOT;
@@ -408,7 +493,7 @@ function onInteractionHandler (
408
493
  actionCategory = TrackingCategory.REFERRAL;
409
494
  } else if (isPostback) {
410
495
  actionCategory = TrackingCategory.POSTBACK_BUTTON;
411
- label = req.data.postback.title || '(unknown)';
496
+ label = req.event.postback.title || (useExtendedScalars ? null : '(unknown)');
412
497
  } else {
413
498
  actionCategory = TrackingCategory.OTHER;
414
499
  }
@@ -416,7 +501,6 @@ function onInteractionHandler (
416
501
  trackEvents.push({
417
502
  ...(analyticsStorage.hasExtendedEvents ? actionMeta : {}),
418
503
  type: TrackingType.CONVERSATION_EVENT,
419
- // @ts-ignore
420
504
  lastAction,
421
505
  category: asCategory(actionCategory),
422
506
  action,
@@ -426,18 +510,21 @@ function onInteractionHandler (
426
510
  });
427
511
  }
428
512
 
429
- await analyticsStorage.storeEvents(
430
- pageId,
431
- senderId,
432
- sessionId,
433
- // @ts-ignore
434
- trackEvents,
435
- user,
436
- timestamp,
437
- nonInteractive,
438
- createSession,
439
- timeZone
440
- );
513
+ await Promise.all([
514
+ analyticsStorage.storeEvents(
515
+ pageId,
516
+ senderId,
517
+ sessionId,
518
+ // @ts-ignore
519
+ trackEvents,
520
+ user,
521
+ timestamp,
522
+ nonInteractive,
523
+ createSession,
524
+ metadata
525
+ ),
526
+ sessionPromise
527
+ ]);
441
528
  } catch (e) {
442
529
  if (throwException) {
443
530
  throw e;