wingbot 3.45.1 → 3.46.0-alpha.1
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/index.js +9 -3
- package/package.json +1 -1
- package/src/BotApp.js +11 -2
- package/src/BuildRouter.js +17 -2
- package/src/Processor.js +52 -21
- package/src/Request.js +17 -2
- package/src/Responder.js +11 -8
- package/src/ReturnSender.js +6 -2
- package/src/analytics/consts.js +102 -0
- package/src/analytics/onInteractionHandler.js +106 -59
- package/src/flags.js +7 -1
- package/src/utils/quickReplies.js +3 -3
- package/src/utils/stateVariables.js +6 -3
package/index.js
CHANGED
|
@@ -52,7 +52,11 @@ const {
|
|
|
52
52
|
bufferloader,
|
|
53
53
|
MemoryStateStorage
|
|
54
54
|
} = require('./src/tools');
|
|
55
|
-
const
|
|
55
|
+
const {
|
|
56
|
+
TrackingCategory,
|
|
57
|
+
TrackingType,
|
|
58
|
+
ResponseFlag
|
|
59
|
+
} = require('./src/analytics/consts');
|
|
56
60
|
|
|
57
61
|
const { version: wingbotVersion } = require('./package.json');
|
|
58
62
|
|
|
@@ -122,8 +126,10 @@ module.exports = {
|
|
|
122
126
|
// tests
|
|
123
127
|
ConversationTester,
|
|
124
128
|
|
|
125
|
-
// flags
|
|
126
|
-
|
|
129
|
+
// flags & tracking
|
|
130
|
+
TrackingCategory,
|
|
131
|
+
TrackingType,
|
|
132
|
+
ResponseFlag,
|
|
127
133
|
|
|
128
134
|
wingbotVersion,
|
|
129
135
|
|
package/package.json
CHANGED
package/src/BotApp.js
CHANGED
|
@@ -116,6 +116,8 @@ class BotApp {
|
|
|
116
116
|
this._senderLogger = chatLogStorage;
|
|
117
117
|
this._verify = promisify(jwt.verify);
|
|
118
118
|
|
|
119
|
+
this._bot = bot;
|
|
120
|
+
|
|
119
121
|
this._processor = new Processor(bot, {
|
|
120
122
|
...processorOptions,
|
|
121
123
|
secret,
|
|
@@ -198,11 +200,18 @@ class BotApp {
|
|
|
198
200
|
registerAnalyticsStorage (analyticsStorage, options = {}) {
|
|
199
201
|
const log = this._logger || options.log;
|
|
200
202
|
|
|
201
|
-
analyticsStorage.setDefaultLogger
|
|
203
|
+
if (typeof analyticsStorage.setDefaultLogger === 'function') {
|
|
204
|
+
analyticsStorage.setDefaultLogger(log);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// @ts-ignore
|
|
208
|
+
const { snapshot = null, botId = null } = this._bot;
|
|
202
209
|
|
|
203
210
|
const { onInteraction, onEvent } = onInteractionHandler({
|
|
204
211
|
log,
|
|
205
212
|
anonymize: this._textFilter,
|
|
213
|
+
snapshot,
|
|
214
|
+
botId,
|
|
206
215
|
...options
|
|
207
216
|
}, analyticsStorage);
|
|
208
217
|
|
|
@@ -221,7 +230,7 @@ class BotApp {
|
|
|
221
230
|
* @param {boolean} [nonInteractive]
|
|
222
231
|
*/
|
|
223
232
|
async trackEvent (pageId, senderId, event, ts = Date.now(), nonInteractive = false) {
|
|
224
|
-
const state = this._processor.stateStorage.getState(senderId, pageId);
|
|
233
|
+
const state = await this._processor.stateStorage.getState(senderId, pageId);
|
|
225
234
|
|
|
226
235
|
if (!state) {
|
|
227
236
|
throw new Error(`State ${pageId}:${senderId} not found. Ensure the #trackEvent() method was called after the conversation has started`);
|
package/src/BuildRouter.js
CHANGED
|
@@ -39,6 +39,7 @@ const MESSAGE_RESOLVER_NAME = 'botbuild.message';
|
|
|
39
39
|
* @typedef {object} Route
|
|
40
40
|
* @prop {number} id
|
|
41
41
|
* @prop {string|null} path
|
|
42
|
+
* @prop {string|null} [skill]
|
|
42
43
|
* @prop {Resolver[]} resolvers
|
|
43
44
|
* @prop {boolean} [isFallback]
|
|
44
45
|
* @prop {string[]} [aiTags]
|
|
@@ -238,6 +239,14 @@ class BuildRouter extends Router {
|
|
|
238
239
|
}
|
|
239
240
|
}
|
|
240
241
|
|
|
242
|
+
get snapshot () {
|
|
243
|
+
return this._snapshot;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
get botId () {
|
|
247
|
+
return this._botId;
|
|
248
|
+
}
|
|
249
|
+
|
|
241
250
|
/**
|
|
242
251
|
* @returns {C}
|
|
243
252
|
*/
|
|
@@ -674,9 +683,10 @@ class BuildRouter extends Router {
|
|
|
674
683
|
*
|
|
675
684
|
* @param {TransformedRoute} route
|
|
676
685
|
* @param {boolean} nextRouteIsSameResponder
|
|
686
|
+
* @param {string} includedBlockId
|
|
677
687
|
* @returns {Middleware<S,C>[]}
|
|
678
688
|
*/
|
|
679
|
-
_buildRouteHead (route, nextRouteIsSameResponder) {
|
|
689
|
+
_buildRouteHead (route, nextRouteIsSameResponder, includedBlockId) {
|
|
680
690
|
const resolvers = [];
|
|
681
691
|
|
|
682
692
|
if (!route.isFallback) {
|
|
@@ -712,6 +722,11 @@ class BuildRouter extends Router {
|
|
|
712
722
|
if (bounceResolver) {
|
|
713
723
|
resolvers.push(bounceResolver);
|
|
714
724
|
}
|
|
725
|
+
} else if (!includedBlockId && route.skill) {
|
|
726
|
+
resolvers.push((req, res) => {
|
|
727
|
+
res.trackAsSkill(route.skill);
|
|
728
|
+
return Router.CONTINUE;
|
|
729
|
+
});
|
|
715
730
|
}
|
|
716
731
|
}
|
|
717
732
|
|
|
@@ -752,7 +767,7 @@ class BuildRouter extends Router {
|
|
|
752
767
|
};
|
|
753
768
|
|
|
754
769
|
const resolvers = [
|
|
755
|
-
...this._buildRouteHead(route, nextRouteIsSameResponder),
|
|
770
|
+
...this._buildRouteHead(route, nextRouteIsSameResponder, includedBlockId),
|
|
756
771
|
...this.buildResolvers(route.resolvers, route, buildInfo)
|
|
757
772
|
];
|
|
758
773
|
|
package/src/Processor.js
CHANGED
|
@@ -16,6 +16,9 @@ const { mergeState, isUserInteraction } = require('./utils/stateVariables');
|
|
|
16
16
|
/** @typedef {import('./ReducerWrapper')} ReducerWrapper */
|
|
17
17
|
/** @typedef {import('./Router')} Router */
|
|
18
18
|
/** @typedef {import('./BuildRouter')} BuildRouter */
|
|
19
|
+
/** @typedef {import('./analytics/consts').TrackingCategory} TrackingCategory */
|
|
20
|
+
/** @typedef {import('./analytics/consts').TrackingType} TrackingType */
|
|
21
|
+
/** @typedef {import('./analytics/consts').ResponseFlag} ResponseFlag */
|
|
19
22
|
|
|
20
23
|
/**
|
|
21
24
|
* @typedef {object} AutoTypingConfig
|
|
@@ -35,8 +38,8 @@ const { mergeState, isUserInteraction } = require('./utils/stateVariables');
|
|
|
35
38
|
|
|
36
39
|
/**
|
|
37
40
|
* @typedef {object} TrackingEvent
|
|
38
|
-
* @prop {
|
|
39
|
-
* @prop {
|
|
41
|
+
* @prop {TrackingType} type
|
|
42
|
+
* @prop {TrackingCategory} category
|
|
40
43
|
* @prop {string} action
|
|
41
44
|
* @prop {string} label
|
|
42
45
|
* @prop {number} value
|
|
@@ -55,7 +58,10 @@ const { mergeState, isUserInteraction } = require('./utils/stateVariables');
|
|
|
55
58
|
* @prop {object} state
|
|
56
59
|
* @prop {object} data
|
|
57
60
|
* @prop {string|null} skill
|
|
58
|
-
* @prop {TrackingObject} tracking
|
|
61
|
+
* @prop {TrackingObject} tracking - deprecated
|
|
62
|
+
* @prop {TrackingEvent[]} events
|
|
63
|
+
* @prop {ResponseFlag|null} flag
|
|
64
|
+
* @prop {boolean} nonInteractive
|
|
59
65
|
*/
|
|
60
66
|
|
|
61
67
|
/**
|
|
@@ -134,6 +140,19 @@ function NAME_FROM_STATE (state) {
|
|
|
134
140
|
}
|
|
135
141
|
|
|
136
142
|
const MAX_TS = 9999999999999;
|
|
143
|
+
const CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
|
|
144
|
+
|
|
145
|
+
function toBase (number) {
|
|
146
|
+
let result = '';
|
|
147
|
+
let integer = number;
|
|
148
|
+
|
|
149
|
+
do {
|
|
150
|
+
result = CHARS[integer % 62] + result;
|
|
151
|
+
integer = Math.floor(integer / 62);
|
|
152
|
+
} while (integer > 0);
|
|
153
|
+
|
|
154
|
+
return result;
|
|
155
|
+
}
|
|
137
156
|
|
|
138
157
|
/**
|
|
139
158
|
* Messaging event processor
|
|
@@ -381,7 +400,7 @@ class Processor extends EventEmitter {
|
|
|
381
400
|
} = await this
|
|
382
401
|
._processMessage(message, pageId, messageSender, responderData, preloadPromise));
|
|
383
402
|
|
|
384
|
-
await this._emitInteractionEvent(req, messageSender, state, data);
|
|
403
|
+
await this._emitInteractionEvent(req, res, messageSender, state, data);
|
|
385
404
|
|
|
386
405
|
return messageSender.finished(req, res, null, errorHandler);
|
|
387
406
|
} catch (e) {
|
|
@@ -394,12 +413,13 @@ class Processor extends EventEmitter {
|
|
|
394
413
|
/**
|
|
395
414
|
*
|
|
396
415
|
* @param {Request} req
|
|
416
|
+
* @param {Responder} res
|
|
397
417
|
* @param {ReturnSender} messageSender
|
|
398
418
|
* @param {object} state
|
|
399
419
|
* @param {object} data
|
|
400
420
|
* @returns {Promise}
|
|
401
421
|
*/
|
|
402
|
-
_emitInteractionEvent (req, messageSender, state, data) {
|
|
422
|
+
_emitInteractionEvent (req, res, messageSender, state, data) {
|
|
403
423
|
const shouldNotTrack = data._initialEventShouldNotBeTracked === true;
|
|
404
424
|
|
|
405
425
|
if (shouldNotTrack) {
|
|
@@ -408,7 +428,10 @@ class Processor extends EventEmitter {
|
|
|
408
428
|
|
|
409
429
|
const { _lastAction: lastAction = null } = req.state;
|
|
410
430
|
const actions = messageSender.visitedInteractions;
|
|
411
|
-
const skill =
|
|
431
|
+
const skill = typeof res.newState._trackAsSkill === 'undefined'
|
|
432
|
+
? (req.state._trackAsSkill || null)
|
|
433
|
+
: res.newState._trackAsSkill;
|
|
434
|
+
const { events = [] } = messageSender.tracking;
|
|
412
435
|
|
|
413
436
|
const event = {
|
|
414
437
|
req,
|
|
@@ -417,7 +440,10 @@ class Processor extends EventEmitter {
|
|
|
417
440
|
state,
|
|
418
441
|
data,
|
|
419
442
|
skill,
|
|
420
|
-
tracking: messageSender.tracking
|
|
443
|
+
tracking: messageSender.tracking,
|
|
444
|
+
events,
|
|
445
|
+
flag: res.senderMeta.flag,
|
|
446
|
+
nonInteractive: !isUserInteraction(req)
|
|
421
447
|
};
|
|
422
448
|
|
|
423
449
|
return Promise.allSettled([
|
|
@@ -575,27 +601,35 @@ class Processor extends EventEmitter {
|
|
|
575
601
|
let {
|
|
576
602
|
_sct: sessionCount = 0,
|
|
577
603
|
_sid: sessionId = null,
|
|
578
|
-
|
|
604
|
+
_sst: sessionStart = 0,
|
|
605
|
+
_sts: sessionTs = (state._segStamp || 0),
|
|
579
606
|
_snew: sessionCreated
|
|
580
607
|
} = state;
|
|
581
608
|
|
|
609
|
+
const interactive = isUserInteraction(req);
|
|
610
|
+
|
|
582
611
|
if ((isUserInteraction(req)
|
|
583
|
-
&& (
|
|
612
|
+
&& (sessionTs + this.options.sessionDuration) < Date.now())
|
|
584
613
|
|| !sessionId) {
|
|
585
614
|
|
|
615
|
+
sessionStart = timestamp;
|
|
616
|
+
sessionTs = timestamp;
|
|
586
617
|
sessionId = Processor._createSessionId(req.pageId, req.senderId, timestamp);
|
|
587
618
|
sessionCount++;
|
|
588
619
|
sessionCreated = true;
|
|
589
620
|
} else {
|
|
590
621
|
sessionCreated = false;
|
|
591
|
-
}
|
|
592
622
|
|
|
593
|
-
|
|
623
|
+
if (interactive) {
|
|
624
|
+
sessionTs = timestamp;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
594
627
|
|
|
595
628
|
Object.assign(state, {
|
|
596
629
|
_sct: sessionCount,
|
|
597
630
|
_sid: sessionId,
|
|
598
|
-
|
|
631
|
+
_sst: sessionStart,
|
|
632
|
+
_sts: sessionTs,
|
|
599
633
|
_snew: sessionCreated
|
|
600
634
|
});
|
|
601
635
|
} else {
|
|
@@ -785,21 +819,18 @@ class Processor extends EventEmitter {
|
|
|
785
819
|
.digest('hex');
|
|
786
820
|
|
|
787
821
|
return senderHash.match(/[a-f0-9]{1,13}/g)
|
|
788
|
-
.map((v) => parseInt(v, 16)
|
|
822
|
+
.map((v) => toBase(parseInt(v, 16)))
|
|
789
823
|
.join('');
|
|
790
824
|
}
|
|
791
825
|
|
|
792
826
|
static _createSessionId (pageId, senderId, timestamp = Date.now()) {
|
|
793
|
-
const senderShort = Processor._shakeShort(`${senderId}|${pageId}}`,
|
|
827
|
+
const senderShort = Processor._shakeShort(`${senderId}|${pageId}}`, 12);
|
|
794
828
|
|
|
795
|
-
const rand = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER)
|
|
796
|
-
.toString(36);
|
|
829
|
+
const rand = toBase(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER));
|
|
797
830
|
|
|
798
|
-
const randTS = Math.floor(Date.now() %
|
|
799
|
-
.toString(36);
|
|
831
|
+
const randTS = toBase(Math.floor(Date.now() % 10000));
|
|
800
832
|
|
|
801
|
-
const ts = Math.floor(MAX_TS - timestamp)
|
|
802
|
-
.toString(36);
|
|
833
|
+
const ts = toBase(Math.floor(MAX_TS - timestamp));
|
|
803
834
|
|
|
804
835
|
// console.log({
|
|
805
836
|
// base: `${ts}.${senderShort}`.length,
|
|
@@ -811,7 +842,7 @@ class Processor extends EventEmitter {
|
|
|
811
842
|
// });
|
|
812
843
|
|
|
813
844
|
return `${ts}.${senderShort}`
|
|
814
|
-
.padEnd(
|
|
845
|
+
.padEnd(28, randTS)
|
|
815
846
|
.padEnd(32, rand);
|
|
816
847
|
}
|
|
817
848
|
|
package/src/Request.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
const Ai = require('./Ai');
|
|
7
7
|
const { tokenize, parseActionPayload } = require('./utils');
|
|
8
8
|
const { quickReplyAction } = require('./utils/quickReplies');
|
|
9
|
-
const {
|
|
9
|
+
const { ResponseFlag } = require('./analytics/consts');
|
|
10
10
|
const { getSetState } = require('./utils/getUpdate');
|
|
11
11
|
const { vars, checkSetState } = require('./utils/stateVariables');
|
|
12
12
|
const OrchestratorClient = require('./OrchestratorClient');
|
|
@@ -391,7 +391,7 @@ class Request {
|
|
|
391
391
|
data: {
|
|
392
392
|
...data,
|
|
393
393
|
_senderMeta: {
|
|
394
|
-
flag:
|
|
394
|
+
flag: ResponseFlag.DISAMBIGUATION_SELECTED,
|
|
395
395
|
likelyIntent: intent.intent,
|
|
396
396
|
disambText: text
|
|
397
397
|
}
|
|
@@ -801,6 +801,7 @@ class Request {
|
|
|
801
801
|
* @returns {Action|null}
|
|
802
802
|
*/
|
|
803
803
|
expected () {
|
|
804
|
+
// @ts-ignore
|
|
804
805
|
return this.state._expected || null;
|
|
805
806
|
}
|
|
806
807
|
|
|
@@ -816,6 +817,7 @@ class Request {
|
|
|
816
817
|
*/
|
|
817
818
|
expectedKeywords (justOnce = false) {
|
|
818
819
|
const {
|
|
820
|
+
// @ts-ignore
|
|
819
821
|
_expectedKeywords: exKeywords
|
|
820
822
|
} = this.state;
|
|
821
823
|
|
|
@@ -855,7 +857,9 @@ class Request {
|
|
|
855
857
|
*/
|
|
856
858
|
expectedContext (justOnce = false, includeKeywords = false) {
|
|
857
859
|
const ad = this.actionData();
|
|
860
|
+
// @ts-ignore
|
|
858
861
|
const expected = ad._useExpected || this.state._expected;
|
|
862
|
+
// @ts-ignore
|
|
859
863
|
const confident = this.state._expectedConfidentInput;
|
|
860
864
|
|
|
861
865
|
const ret = {};
|
|
@@ -1097,6 +1101,7 @@ class Request {
|
|
|
1097
1101
|
* @returns {boolean}
|
|
1098
1102
|
*/
|
|
1099
1103
|
isConfidentInput () {
|
|
1104
|
+
// @ts-ignore
|
|
1100
1105
|
return this.state._expectedConfidentInput === true;
|
|
1101
1106
|
}
|
|
1102
1107
|
|
|
@@ -1123,11 +1128,15 @@ class Request {
|
|
|
1123
1128
|
res = parseActionPayload(this.message.quick_reply);
|
|
1124
1129
|
}
|
|
1125
1130
|
|
|
1131
|
+
// @ts-ignore
|
|
1126
1132
|
if (!res && this.state._expectedKeywords) {
|
|
1133
|
+
// @ts-ignore
|
|
1127
1134
|
res = this._actionByExpectedKeywords(this.state._expected);
|
|
1128
1135
|
}
|
|
1129
1136
|
|
|
1137
|
+
// @ts-ignore
|
|
1130
1138
|
if (!res && this.state._expected) {
|
|
1139
|
+
// @ts-ignore
|
|
1131
1140
|
res = parseActionPayload(this.state._expected);
|
|
1132
1141
|
}
|
|
1133
1142
|
|
|
@@ -1215,7 +1224,9 @@ class Request {
|
|
|
1215
1224
|
}
|
|
1216
1225
|
|
|
1217
1226
|
_getLocalPathRegexp () {
|
|
1227
|
+
// @ts-ignore
|
|
1218
1228
|
if (this.state._lastVisitedPath) {
|
|
1229
|
+
// @ts-ignore
|
|
1219
1230
|
return new RegExp(`^${this.state._lastVisitedPath}/[^/]+`);
|
|
1220
1231
|
}
|
|
1221
1232
|
let expected = this.expected();
|
|
@@ -1295,6 +1306,7 @@ class Request {
|
|
|
1295
1306
|
}
|
|
1296
1307
|
|
|
1297
1308
|
_actionByExpectedKeywords (expected) {
|
|
1309
|
+
// @ts-ignore
|
|
1298
1310
|
if (!this.state._expectedKeywords) {
|
|
1299
1311
|
return null;
|
|
1300
1312
|
}
|
|
@@ -1315,8 +1327,10 @@ class Request {
|
|
|
1315
1327
|
|
|
1316
1328
|
_resolveQuickReplyActions () {
|
|
1317
1329
|
if (this._quickReplyActions === null) {
|
|
1330
|
+
// @ts-ignore
|
|
1318
1331
|
if (this.state._expectedKeywords) {
|
|
1319
1332
|
this._quickReplyActions = quickReplyAction(
|
|
1333
|
+
// @ts-ignore
|
|
1320
1334
|
this.state._expectedKeywords,
|
|
1321
1335
|
this,
|
|
1322
1336
|
Ai.ai
|
|
@@ -1377,6 +1391,7 @@ class Request {
|
|
|
1377
1391
|
*/
|
|
1378
1392
|
expectedEntities () {
|
|
1379
1393
|
const {
|
|
1394
|
+
// @ts-ignore
|
|
1380
1395
|
_expectedKeywords: exKeywords
|
|
1381
1396
|
} = this.state;
|
|
1382
1397
|
|
package/src/Responder.js
CHANGED
|
@@ -9,7 +9,7 @@ const ButtonTemplate = require('./templates/ButtonTemplate');
|
|
|
9
9
|
const GenericTemplate = require('./templates/GenericTemplate');
|
|
10
10
|
const ListTemplate = require('./templates/ListTemplate');
|
|
11
11
|
const { makeAbsolute, makeQuickReplies } = require('./utils');
|
|
12
|
-
const {
|
|
12
|
+
const { ResponseFlag } = require('./analytics/consts');
|
|
13
13
|
const { checkSetState } = require('./utils/stateVariables');
|
|
14
14
|
const {
|
|
15
15
|
FEATURE_VOICE,
|
|
@@ -23,6 +23,9 @@ const TYPE_MESSAGE_TAG = 'MESSAGE_TAG';
|
|
|
23
23
|
const EXCEPTION_HOPCOUNT_THRESHOLD = 5;
|
|
24
24
|
|
|
25
25
|
/** @typedef {import('./Request')} Request */
|
|
26
|
+
/** @typedef {import('./ReturnSender').UploadResult} UploadResult */
|
|
27
|
+
/** @typedef {import('./analytics/consts').TrackingCategory} TrackingCategory */
|
|
28
|
+
/** @typedef {import('./analytics/consts').TrackingType} TrackingType */
|
|
26
29
|
|
|
27
30
|
/**
|
|
28
31
|
* @enum {string} ExpectedInput
|
|
@@ -48,7 +51,7 @@ Object.freeze(ExpectedInput);
|
|
|
48
51
|
|
|
49
52
|
/**
|
|
50
53
|
* @typedef {object} SenderMeta
|
|
51
|
-
* @prop {
|
|
54
|
+
* @prop {ResponseFlag|null} flag
|
|
52
55
|
* @prop {string} [likelyIntent]
|
|
53
56
|
* @prop {string} [disambText]
|
|
54
57
|
* @prop {string[]} [disambiguationIntents]
|
|
@@ -71,8 +74,6 @@ Object.freeze(ExpectedInput);
|
|
|
71
74
|
* @returns {VoiceControl}
|
|
72
75
|
*/
|
|
73
76
|
|
|
74
|
-
/** @typedef {import('./ReturnSender').UploadResult} UploadResult */
|
|
75
|
-
|
|
76
77
|
/**
|
|
77
78
|
* Instance of responder is passed as second parameter of handler (res)
|
|
78
79
|
*
|
|
@@ -200,7 +201,7 @@ class Responder {
|
|
|
200
201
|
* @returns {this}
|
|
201
202
|
*/
|
|
202
203
|
doNotLogTheEvent () {
|
|
203
|
-
this._senderMeta = { flag:
|
|
204
|
+
this._senderMeta = { flag: ResponseFlag.DO_NOT_LOG };
|
|
204
205
|
return this;
|
|
205
206
|
}
|
|
206
207
|
|
|
@@ -209,8 +210,8 @@ class Responder {
|
|
|
209
210
|
* Events are aggregated within ReturnSender and can be caught
|
|
210
211
|
* within Processor's `interaction` event (event.tracking.events)
|
|
211
212
|
*
|
|
212
|
-
* @param {
|
|
213
|
-
* @param {
|
|
213
|
+
* @param {TrackingType} type - (log,report,conversation,audit,user,training)
|
|
214
|
+
* @param {TrackingCategory} category
|
|
214
215
|
* @param {string} [action]
|
|
215
216
|
* @param {string} [label]
|
|
216
217
|
* @param {number} [value]
|
|
@@ -471,7 +472,7 @@ class Responder {
|
|
|
471
472
|
|
|
472
473
|
if (disambiguationIntents.length > 0) {
|
|
473
474
|
this._senderMeta = {
|
|
474
|
-
flag:
|
|
475
|
+
flag: ResponseFlag.DISAMBIGUATION_OFFERED,
|
|
475
476
|
disambiguationIntents
|
|
476
477
|
};
|
|
477
478
|
}
|
|
@@ -1015,6 +1016,8 @@ class Responder {
|
|
|
1015
1016
|
$hopCount++;
|
|
1016
1017
|
}
|
|
1017
1018
|
|
|
1019
|
+
this._senderMeta = { flag: ResponseFlag.HANDOVER };
|
|
1020
|
+
|
|
1018
1021
|
if (data === null) {
|
|
1019
1022
|
metadata = JSON.stringify({
|
|
1020
1023
|
data: { $hopCount }
|
package/src/ReturnSender.js
CHANGED
|
@@ -5,10 +5,11 @@
|
|
|
5
5
|
|
|
6
6
|
const ai = require('./Ai');
|
|
7
7
|
const { FEATURE_PHRASES, FEATURE_TRACKING } = require('./features');
|
|
8
|
-
const {
|
|
8
|
+
const { ResponseFlag } = require('./analytics/consts');
|
|
9
9
|
|
|
10
10
|
/** @typedef {import('./Request')} Request */
|
|
11
11
|
/** @typedef {import('./Responder')} Responder */
|
|
12
|
+
/** @typedef {import('./Processor').TrackingObject} TrackingObject */
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* @typedef {object} ChatLogStorage
|
|
@@ -155,6 +156,9 @@ class ReturnSender {
|
|
|
155
156
|
});
|
|
156
157
|
}
|
|
157
158
|
|
|
159
|
+
/**
|
|
160
|
+
* @returns {TrackingObject}
|
|
161
|
+
*/
|
|
158
162
|
get tracking () {
|
|
159
163
|
return this._tracking;
|
|
160
164
|
}
|
|
@@ -531,7 +535,7 @@ class ReturnSender {
|
|
|
531
535
|
};
|
|
532
536
|
}
|
|
533
537
|
|
|
534
|
-
if (!this._logger || meta.flag ===
|
|
538
|
+
if (!this._logger || meta.flag === ResponseFlag.DO_NOT_LOG) {
|
|
535
539
|
// noop
|
|
536
540
|
} else if (error) {
|
|
537
541
|
await Promise.resolve(this._logger
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author David Menger
|
|
3
|
+
*/
|
|
4
|
+
'use strict';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @enum {string}
|
|
8
|
+
*/
|
|
9
|
+
const ResponseFlag = {
|
|
10
|
+
/**
|
|
11
|
+
* Disambiguation quick reply was selected
|
|
12
|
+
*/
|
|
13
|
+
DISAMBIGUATION_SELECTED: 'd',
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Disambiguation occured - user was asked to choose the right meaning
|
|
17
|
+
*/
|
|
18
|
+
DISAMBIGUATION_OFFERED: 'o',
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Do not log the event
|
|
22
|
+
*/
|
|
23
|
+
DO_NOT_LOG: '!',
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Handover occurred
|
|
27
|
+
*/
|
|
28
|
+
HANDOVER: 'h'
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @enum {string}
|
|
33
|
+
*/
|
|
34
|
+
const TrackingType = { // max length 12
|
|
35
|
+
CONVERSATION_EVENT: 'conversation',
|
|
36
|
+
TRAINING: 'train',
|
|
37
|
+
PAGE_VIEW: 'page_view',
|
|
38
|
+
REPORT: 'report'
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @enum {string} TrackingCategory
|
|
43
|
+
*/
|
|
44
|
+
const TrackingCategory = { // max length 3
|
|
45
|
+
// CONVERSATION_EVENT: 'conversation'
|
|
46
|
+
STICKER: 'sti',
|
|
47
|
+
IMAGE: 'img',
|
|
48
|
+
LOCATION: 'loc',
|
|
49
|
+
ATTACHMENT: 'att',
|
|
50
|
+
TEXT: 'txt',
|
|
51
|
+
QUICK_REPLY: 'qr',
|
|
52
|
+
OPT_IN: 'oin',
|
|
53
|
+
REFERRAL: 'ref',
|
|
54
|
+
POSTBACK_BUTTON: 'btn',
|
|
55
|
+
URL_LINK: 'url',
|
|
56
|
+
OTHER: 'oth',
|
|
57
|
+
HANDOVER_TO_BOT: 'bot',
|
|
58
|
+
|
|
59
|
+
// TRAINING: 'train'
|
|
60
|
+
INTENT_DETECTION: 'int',
|
|
61
|
+
HANDOVER_OCCURRED: 'hum',
|
|
62
|
+
DISAMBIGUATION_SELECTED: 'dis',
|
|
63
|
+
DISAMBIGUATION_OFFERED: 'dio',
|
|
64
|
+
|
|
65
|
+
// REPORT: 'report'
|
|
66
|
+
REPORT_FEEDBACK: 'fdb'
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* @type {Object<TrackingCategory,string>}
|
|
71
|
+
*/
|
|
72
|
+
const CATEGORY_LABELS = {
|
|
73
|
+
// CONVERSATION_EVENT: 'conversation'
|
|
74
|
+
[TrackingCategory.STICKER]: 'User: Sticker',
|
|
75
|
+
[TrackingCategory.IMAGE]: 'User: Image',
|
|
76
|
+
[TrackingCategory.LOCATION]: 'User: Location',
|
|
77
|
+
[TrackingCategory.ATTACHMENT]: 'User: Attachement', // yes, with typo
|
|
78
|
+
[TrackingCategory.TEXT]: 'User: Text',
|
|
79
|
+
[TrackingCategory.QUICK_REPLY]: 'User: Quick reply',
|
|
80
|
+
[TrackingCategory.OPT_IN]: 'Entry: Optin',
|
|
81
|
+
[TrackingCategory.REFERRAL]: 'Entry: Referral',
|
|
82
|
+
[TrackingCategory.POSTBACK_BUTTON]: 'User: Button - bot',
|
|
83
|
+
[TrackingCategory.URL_LINK]: 'User: Button - url',
|
|
84
|
+
[TrackingCategory.OTHER]: 'User: Other',
|
|
85
|
+
[TrackingCategory.HANDOVER_TO_BOT]: 'Entry: Handover in',
|
|
86
|
+
|
|
87
|
+
// TRAINING: 'train'
|
|
88
|
+
[TrackingCategory.INTENT_DETECTION]: 'Intent: Detection',
|
|
89
|
+
[TrackingCategory.HANDOVER_OCCURRED]: 'Bot: Handover out',
|
|
90
|
+
[TrackingCategory.DISAMBIGUATION_SELECTED]: 'Disambiguation: selected',
|
|
91
|
+
[TrackingCategory.DISAMBIGUATION_OFFERED]: 'Disambiguation: offered',
|
|
92
|
+
|
|
93
|
+
// REPORT: 'report'
|
|
94
|
+
[TrackingCategory.REPORT_FEEDBACK]: 'User: Feedback'
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
module.exports = {
|
|
98
|
+
CATEGORY_LABELS,
|
|
99
|
+
TrackingType,
|
|
100
|
+
TrackingCategory,
|
|
101
|
+
ResponseFlag
|
|
102
|
+
};
|
|
@@ -3,8 +3,11 @@
|
|
|
3
3
|
*/
|
|
4
4
|
'use strict';
|
|
5
5
|
|
|
6
|
-
const { replaceDiacritics } = require('webalize');
|
|
6
|
+
const { replaceDiacritics, webalize } = require('webalize');
|
|
7
7
|
const Ai = require('../Ai');
|
|
8
|
+
const {
|
|
9
|
+
TrackingType, TrackingCategory, CATEGORY_LABELS, ResponseFlag
|
|
10
|
+
} = require('./consts');
|
|
8
11
|
|
|
9
12
|
/** @typedef {import('../Processor').InteractionEvent} InteractionEvent */
|
|
10
13
|
/** @typedef {import('../Processor').IInteractionHandler} IInteractionHandler */
|
|
@@ -23,8 +26,8 @@ const Ai = require('../Ai');
|
|
|
23
26
|
|
|
24
27
|
/**
|
|
25
28
|
* @typedef {object} Event
|
|
26
|
-
* @prop {
|
|
27
|
-
* @prop {
|
|
29
|
+
* @prop {TrackingType} type
|
|
30
|
+
* @prop {TrackingCategory} [category]
|
|
28
31
|
* @prop {string} [action]
|
|
29
32
|
* @prop {string} [label]
|
|
30
33
|
* @prop {number} [value]
|
|
@@ -35,6 +38,8 @@ const Ai = require('../Ai');
|
|
|
35
38
|
* @prop {number} [sessionCount]
|
|
36
39
|
* @prop {string} [lang]
|
|
37
40
|
* @prop {string} [action]
|
|
41
|
+
* @prop {string} [snapshot]
|
|
42
|
+
* @prop {string} [botId]
|
|
38
43
|
*/
|
|
39
44
|
|
|
40
45
|
/**
|
|
@@ -45,6 +50,7 @@ const Ai = require('../Ai');
|
|
|
45
50
|
* @param {SessionMetadata} [metadata]
|
|
46
51
|
* @param {number} [ts]
|
|
47
52
|
* @param {boolean} [nonInteractive]
|
|
53
|
+
* @param {string} [timeZone]
|
|
48
54
|
* @returns {Promise}
|
|
49
55
|
*/
|
|
50
56
|
|
|
@@ -58,6 +64,7 @@ const Ai = require('../Ai');
|
|
|
58
64
|
* @param {number} [ts]
|
|
59
65
|
* @param {boolean} [nonInteractive]
|
|
60
66
|
* @param {boolean} [sessionStarted]
|
|
67
|
+
* @param {string} [timeZone]
|
|
61
68
|
* @returns {Promise}
|
|
62
69
|
*/
|
|
63
70
|
|
|
@@ -72,6 +79,9 @@ const Ai = require('../Ai');
|
|
|
72
79
|
* @prop {StoreEvents} storeEvents
|
|
73
80
|
* @prop {CreateUserSession} createUserSession
|
|
74
81
|
* @prop {boolean} [hasExtendedEvents]
|
|
82
|
+
* @prop {boolean} [supportsArrays]
|
|
83
|
+
* @prop {boolean} [useDescriptiveCategories]
|
|
84
|
+
* @prop {boolean} [useExtendedScalars]
|
|
75
85
|
*/
|
|
76
86
|
|
|
77
87
|
/**
|
|
@@ -98,6 +108,9 @@ const Ai = require('../Ai');
|
|
|
98
108
|
|
|
99
109
|
/**
|
|
100
110
|
* @typedef {object} HandlerConfig
|
|
111
|
+
* @prop {string} [snapshot]
|
|
112
|
+
* @prop {string} [botId]
|
|
113
|
+
* @prop {string} [timeZone] - default UTC
|
|
101
114
|
* @prop {boolean} [enabled] - default true
|
|
102
115
|
* @prop {boolean} [throwException] - default false
|
|
103
116
|
* @prop {IGALogger} [log] - console like logger
|
|
@@ -134,12 +147,26 @@ function onInteractionHandler (
|
|
|
134
147
|
enabled = true,
|
|
135
148
|
throwException = false,
|
|
136
149
|
log = console,
|
|
150
|
+
snapshot,
|
|
151
|
+
botId,
|
|
152
|
+
timeZone = 'UTC',
|
|
137
153
|
anonymize = (x) => x,
|
|
138
154
|
userExtractor = (state) => null // eslint-disable-line no-unused-vars
|
|
139
155
|
},
|
|
140
156
|
analyticsStorage,
|
|
141
157
|
ai = Ai.ai
|
|
142
158
|
) {
|
|
159
|
+
const {
|
|
160
|
+
supportsArrays = false,
|
|
161
|
+
useExtendedScalars = false,
|
|
162
|
+
hasExtendedEvents = false,
|
|
163
|
+
useDescriptiveCategories = true
|
|
164
|
+
} = analyticsStorage;
|
|
165
|
+
|
|
166
|
+
const asArray = (data = []) => (supportsArrays ? data : data.join(','));
|
|
167
|
+
const asCategory = (cat) => (useDescriptiveCategories && CATEGORY_LABELS[cat]) || cat;
|
|
168
|
+
const noneAction = useExtendedScalars ? null : '(none)';
|
|
169
|
+
const noneValue = useExtendedScalars ? -1 : 0;
|
|
143
170
|
|
|
144
171
|
/**
|
|
145
172
|
* @param {InteractionEvent} params
|
|
@@ -151,13 +178,14 @@ function onInteractionHandler (
|
|
|
151
178
|
// state,
|
|
152
179
|
// data,
|
|
153
180
|
skill,
|
|
154
|
-
|
|
181
|
+
events,
|
|
182
|
+
flag,
|
|
183
|
+
nonInteractive
|
|
155
184
|
}) {
|
|
156
185
|
if (!enabled) {
|
|
157
186
|
return;
|
|
158
187
|
}
|
|
159
188
|
try {
|
|
160
|
-
const nonInteractive = !!req.campaign;
|
|
161
189
|
const {
|
|
162
190
|
pageId,
|
|
163
191
|
senderId,
|
|
@@ -168,16 +196,20 @@ function onInteractionHandler (
|
|
|
168
196
|
_snew: createSession,
|
|
169
197
|
_sct: sessionCount,
|
|
170
198
|
_sid: sessionId,
|
|
199
|
+
_sst: sessionStart,
|
|
200
|
+
_sts: sessionTs,
|
|
171
201
|
lang
|
|
172
202
|
} = req.state;
|
|
173
203
|
|
|
174
|
-
const [action =
|
|
204
|
+
const [action = noneAction, ...otherActions] = actions;
|
|
175
205
|
|
|
176
206
|
if (createSession) {
|
|
177
207
|
const metadata = {
|
|
178
208
|
sessionCount,
|
|
179
209
|
lang,
|
|
180
|
-
action
|
|
210
|
+
action,
|
|
211
|
+
snapshot,
|
|
212
|
+
botId
|
|
181
213
|
};
|
|
182
214
|
|
|
183
215
|
await analyticsStorage.createUserSession(
|
|
@@ -186,7 +218,8 @@ function onInteractionHandler (
|
|
|
186
218
|
sessionId,
|
|
187
219
|
metadata,
|
|
188
220
|
timestamp,
|
|
189
|
-
nonInteractive
|
|
221
|
+
nonInteractive,
|
|
222
|
+
timeZone
|
|
190
223
|
);
|
|
191
224
|
}
|
|
192
225
|
|
|
@@ -211,7 +244,7 @@ function onInteractionHandler (
|
|
|
211
244
|
|
|
212
245
|
if (winners.length > 0) {
|
|
213
246
|
[{
|
|
214
|
-
action: winnerAction =
|
|
247
|
+
action: winnerAction = noneAction,
|
|
215
248
|
sort: winnerScore = 0,
|
|
216
249
|
intent: { intent: winnerIntent, entities: winnerEntities = [] }
|
|
217
250
|
}] = winners;
|
|
@@ -221,6 +254,15 @@ function onInteractionHandler (
|
|
|
221
254
|
|
|
222
255
|
const expected = req.expected() ? req.expected().action : '';
|
|
223
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
|
+
const user = userExtractor(req.state);
|
|
265
|
+
|
|
224
266
|
const isContextUpdate = req.isSetContext();
|
|
225
267
|
const isNotification = !!req.campaign;
|
|
226
268
|
const isAttachment = req.isAttachment();
|
|
@@ -229,13 +271,17 @@ function onInteractionHandler (
|
|
|
229
271
|
const isText = !isQuickReply && req.isText();
|
|
230
272
|
const isPostback = req.isPostBack();
|
|
231
273
|
|
|
232
|
-
const allActions = actions
|
|
274
|
+
const allActions = asArray(actions);
|
|
233
275
|
const requestAction = req.action();
|
|
234
276
|
|
|
235
|
-
const
|
|
277
|
+
const trackEvents = [];
|
|
278
|
+
|
|
279
|
+
const langsExtension = hasExtendedEvents
|
|
280
|
+
? { lang }
|
|
281
|
+
: { cd1: lang };
|
|
236
282
|
|
|
237
283
|
const actionMeta = {
|
|
238
|
-
requestAction: req.action() ||
|
|
284
|
+
requestAction: req.action() || noneAction,
|
|
239
285
|
expected,
|
|
240
286
|
expectedTaken: requestAction === expected,
|
|
241
287
|
isContextUpdate,
|
|
@@ -245,20 +291,28 @@ function onInteractionHandler (
|
|
|
245
291
|
isPassThread,
|
|
246
292
|
isText,
|
|
247
293
|
isPostback,
|
|
294
|
+
didHandover,
|
|
295
|
+
withUser: user !== null && !!user.id,
|
|
296
|
+
sessionStart,
|
|
297
|
+
sessionDuration: sessionTs - sessionStart,
|
|
298
|
+
feedback,
|
|
299
|
+
skill: webalize(skill),
|
|
300
|
+
snapshot,
|
|
301
|
+
botId,
|
|
248
302
|
winnerAction,
|
|
249
303
|
winnerIntent,
|
|
250
|
-
winnerEntities: winnerEntities.map((e) => e.entity)
|
|
304
|
+
winnerEntities: asArray(winnerEntities.map((e) => e.entity)),
|
|
251
305
|
winnerScore,
|
|
252
306
|
winnerTaken,
|
|
253
307
|
intent,
|
|
254
308
|
intentScore: score,
|
|
255
|
-
entities: req.entities.map((e) => e.entity)
|
|
309
|
+
entities: asArray(req.entities.map((e) => e.entity)),
|
|
256
310
|
text,
|
|
257
311
|
allActions
|
|
258
312
|
};
|
|
259
313
|
|
|
260
|
-
|
|
261
|
-
type:
|
|
314
|
+
trackEvents.push({
|
|
315
|
+
type: TrackingType.PAGE_VIEW,
|
|
262
316
|
action,
|
|
263
317
|
allActions,
|
|
264
318
|
nonInteractive,
|
|
@@ -267,15 +321,15 @@ function onInteractionHandler (
|
|
|
267
321
|
skill,
|
|
268
322
|
lang,
|
|
269
323
|
cd1: req.state.lang,
|
|
270
|
-
...(
|
|
324
|
+
...(hasExtendedEvents ? {} : actionMeta)
|
|
271
325
|
});
|
|
272
326
|
|
|
273
327
|
let prevAction = action;
|
|
274
328
|
|
|
275
|
-
|
|
329
|
+
trackEvents.push(
|
|
276
330
|
...otherActions.map((a) => {
|
|
277
331
|
const r = {
|
|
278
|
-
type:
|
|
332
|
+
type: TrackingType.PAGE_VIEW,
|
|
279
333
|
action: a,
|
|
280
334
|
allActions,
|
|
281
335
|
nonInteractive: false,
|
|
@@ -283,9 +337,7 @@ function onInteractionHandler (
|
|
|
283
337
|
prevAction,
|
|
284
338
|
skill,
|
|
285
339
|
isGoto: true,
|
|
286
|
-
...
|
|
287
|
-
? { lang }
|
|
288
|
-
: { cd1: lang })
|
|
340
|
+
...langsExtension
|
|
289
341
|
};
|
|
290
342
|
|
|
291
343
|
prevAction = a;
|
|
@@ -293,8 +345,8 @@ function onInteractionHandler (
|
|
|
293
345
|
})
|
|
294
346
|
);
|
|
295
347
|
|
|
296
|
-
|
|
297
|
-
...
|
|
348
|
+
trackEvents.push(
|
|
349
|
+
...events.map(({
|
|
298
350
|
type, category, action: eventAction, label, value
|
|
299
351
|
}) => ({
|
|
300
352
|
lastAction,
|
|
@@ -303,93 +355,88 @@ function onInteractionHandler (
|
|
|
303
355
|
action: eventAction,
|
|
304
356
|
label,
|
|
305
357
|
value,
|
|
306
|
-
...
|
|
307
|
-
? { lang }
|
|
308
|
-
: { cd1: lang })
|
|
358
|
+
...langsExtension
|
|
309
359
|
}))
|
|
310
360
|
);
|
|
311
361
|
|
|
312
362
|
if (!nonInteractive) {
|
|
313
363
|
|
|
314
364
|
if (req.isText()) {
|
|
315
|
-
|
|
316
|
-
type:
|
|
365
|
+
trackEvents.push({
|
|
366
|
+
type: TrackingType.TRAINING,
|
|
317
367
|
// @ts-ignore
|
|
318
368
|
lastAction,
|
|
319
|
-
category:
|
|
369
|
+
category: asCategory(TrackingCategory.INTENT_DETECTION),
|
|
320
370
|
intent,
|
|
321
371
|
action,
|
|
322
372
|
label: text,
|
|
323
373
|
value: score >= ai.confidence ? 0 : 1,
|
|
324
|
-
...
|
|
325
|
-
? { lang }
|
|
326
|
-
: { cd1: lang })
|
|
374
|
+
...langsExtension
|
|
327
375
|
});
|
|
328
376
|
}
|
|
329
377
|
|
|
330
378
|
const notHandled = actions.some((a) => a.match(/\*$/)) && !req.isQuickReply();
|
|
331
379
|
|
|
332
|
-
let actionCategory
|
|
333
|
-
let label =
|
|
380
|
+
let actionCategory;
|
|
381
|
+
let label = noneAction;
|
|
334
382
|
const value = notHandled ? 1 : 0;
|
|
335
383
|
|
|
336
|
-
if (
|
|
337
|
-
actionCategory
|
|
384
|
+
if (isPassThread) {
|
|
385
|
+
actionCategory = TrackingCategory.HANDOVER_TO_BOT;
|
|
386
|
+
} else if (req.isSticker()) {
|
|
387
|
+
actionCategory = TrackingCategory.STICKER;
|
|
338
388
|
label = req.attachmentUrl(0);
|
|
339
389
|
} else if (req.isImage()) {
|
|
340
|
-
actionCategory
|
|
390
|
+
actionCategory = TrackingCategory.IMAGE;
|
|
341
391
|
label = req.attachmentUrl(0);
|
|
342
392
|
} else if (req.hasLocation()) {
|
|
343
|
-
actionCategory
|
|
393
|
+
actionCategory = TrackingCategory.LOCATION;
|
|
344
394
|
const { lat, long } = req.getLocation();
|
|
345
395
|
label = `${lat}, ${long}`;
|
|
346
396
|
} else if (isAttachment) {
|
|
347
|
-
actionCategory
|
|
397
|
+
actionCategory = TrackingCategory.ATTACHMENT;
|
|
348
398
|
label = req.attachment(0).type;
|
|
349
399
|
} else if (isText) {
|
|
350
|
-
actionCategory
|
|
400
|
+
actionCategory = TrackingCategory.TEXT;
|
|
351
401
|
label = text;
|
|
352
402
|
} else if (isQuickReply) {
|
|
353
|
-
actionCategory
|
|
403
|
+
actionCategory = TrackingCategory.QUICK_REPLY;
|
|
354
404
|
label = text;
|
|
355
|
-
} else if (req.
|
|
356
|
-
actionCategory =
|
|
357
|
-
|
|
358
|
-
|
|
405
|
+
} else if (req.isOptin()) {
|
|
406
|
+
actionCategory = TrackingCategory.OPT_IN;
|
|
407
|
+
} else if (req.isReferral()) {
|
|
408
|
+
actionCategory = TrackingCategory.REFERRAL;
|
|
359
409
|
} else if (isPostback) {
|
|
360
|
-
actionCategory
|
|
410
|
+
actionCategory = TrackingCategory.POSTBACK_BUTTON;
|
|
361
411
|
label = req.data.postback.title || '(unknown)';
|
|
362
412
|
} else {
|
|
363
|
-
actionCategory
|
|
413
|
+
actionCategory = TrackingCategory.OTHER;
|
|
364
414
|
}
|
|
365
415
|
|
|
366
|
-
|
|
416
|
+
trackEvents.push({
|
|
367
417
|
...(analyticsStorage.hasExtendedEvents ? actionMeta : {}),
|
|
368
|
-
type:
|
|
418
|
+
type: TrackingType.CONVERSATION_EVENT,
|
|
369
419
|
// @ts-ignore
|
|
370
420
|
lastAction,
|
|
371
|
-
category: actionCategory,
|
|
421
|
+
category: asCategory(actionCategory),
|
|
372
422
|
action,
|
|
373
423
|
label,
|
|
374
424
|
value,
|
|
375
|
-
...
|
|
376
|
-
? { lang }
|
|
377
|
-
: { cd1: lang })
|
|
425
|
+
...langsExtension
|
|
378
426
|
});
|
|
379
427
|
}
|
|
380
428
|
|
|
381
|
-
const user = userExtractor(req.state);
|
|
382
|
-
|
|
383
429
|
await analyticsStorage.storeEvents(
|
|
384
430
|
pageId,
|
|
385
431
|
senderId,
|
|
386
432
|
sessionId,
|
|
387
433
|
// @ts-ignore
|
|
388
|
-
|
|
434
|
+
trackEvents,
|
|
389
435
|
user,
|
|
390
436
|
timestamp,
|
|
391
437
|
nonInteractive,
|
|
392
|
-
createSession
|
|
438
|
+
createSession,
|
|
439
|
+
timeZone
|
|
393
440
|
);
|
|
394
441
|
} catch (e) {
|
|
395
442
|
if (throwException) {
|
|
@@ -432,7 +479,7 @@ function onInteractionHandler (
|
|
|
432
479
|
[{
|
|
433
480
|
// @ts-ignore
|
|
434
481
|
lastAction,
|
|
435
|
-
...(
|
|
482
|
+
...(hasExtendedEvents
|
|
436
483
|
? { lang }
|
|
437
484
|
: { cd1: lang }),
|
|
438
485
|
...event
|
package/src/flags.js
CHANGED
|
@@ -18,8 +18,14 @@ const FLAG_DISAMBIGUATION_OFFERED = 'o';
|
|
|
18
18
|
*/
|
|
19
19
|
const FLAG_DO_NOT_LOG = '!';
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Handover occurred
|
|
23
|
+
*/
|
|
24
|
+
const FLAG_HANDOVER = 'h';
|
|
25
|
+
|
|
21
26
|
module.exports = {
|
|
22
27
|
FLAG_DISAMBIGUATION_SELECTED,
|
|
23
28
|
FLAG_DISAMBIGUATION_OFFERED,
|
|
24
|
-
FLAG_DO_NOT_LOG
|
|
29
|
+
FLAG_DO_NOT_LOG,
|
|
30
|
+
FLAG_HANDOVER
|
|
25
31
|
};
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
const { makeAbsolute } = require('./pathUtils');
|
|
7
7
|
const { tokenize } = require('./tokenizer');
|
|
8
|
-
const {
|
|
8
|
+
const { ResponseFlag } = require('../analytics/consts');
|
|
9
9
|
const { checkSetState } = require('./stateVariables');
|
|
10
10
|
|
|
11
11
|
/** @typedef {import('../Request')} Request */
|
|
@@ -240,7 +240,7 @@ function makeQuickReplies (replies, path = '', translate = (w) => w, quickReplyC
|
|
|
240
240
|
}
|
|
241
241
|
|
|
242
242
|
if (data._senderMeta
|
|
243
|
-
&& data._senderMeta.flag ===
|
|
243
|
+
&& data._senderMeta.flag === ResponseFlag.DISAMBIGUATION_SELECTED) {
|
|
244
244
|
|
|
245
245
|
const { likelyIntent } = data._senderMeta;
|
|
246
246
|
disambiguationIntents.push(likelyIntent);
|
|
@@ -411,7 +411,7 @@ function disambiguationQuickReply (title, likelyIntent, disambText, action, data
|
|
|
411
411
|
data: {
|
|
412
412
|
...data,
|
|
413
413
|
_senderMeta: {
|
|
414
|
-
flag:
|
|
414
|
+
flag: ResponseFlag.DISAMBIGUATION_SELECTED,
|
|
415
415
|
likelyIntent,
|
|
416
416
|
disambText
|
|
417
417
|
}
|
|
@@ -108,9 +108,12 @@ function checkSetState (setState, newState) {
|
|
|
108
108
|
* @returns {boolean}
|
|
109
109
|
*/
|
|
110
110
|
function isUserInteraction (req) {
|
|
111
|
-
return req.
|
|
112
|
-
|
|
113
|
-
|
|
111
|
+
return !req.campaign
|
|
112
|
+
&& !req.event.pass_thread_control
|
|
113
|
+
&& !req.isSetContext()
|
|
114
|
+
&& (req.isMessage() || req.isPostBack()
|
|
115
|
+
|| req.isReferral() || req.isAttachment()
|
|
116
|
+
|| req.isTextOrIntent());
|
|
114
117
|
}
|
|
115
118
|
|
|
116
119
|
/**
|