wingbot 3.45.2 → 3.46.0-alpha.2
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 +7 -0
- 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 +110 -0
- package/src/analytics/onInteractionHandler.js +150 -61
- 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,
|
|
@@ -202,9 +204,14 @@ class BotApp {
|
|
|
202
204
|
analyticsStorage.setDefaultLogger(log);
|
|
203
205
|
}
|
|
204
206
|
|
|
207
|
+
// @ts-ignore
|
|
208
|
+
const { snapshot = null, botId = null } = this._bot;
|
|
209
|
+
|
|
205
210
|
const { onInteraction, onEvent } = onInteractionHandler({
|
|
206
211
|
log,
|
|
207
212
|
anonymize: this._textFilter,
|
|
213
|
+
snapshot,
|
|
214
|
+
botId,
|
|
208
215
|
...options
|
|
209
216
|
}, analyticsStorage);
|
|
210
217
|
|
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,110 @@
|
|
|
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
|
+
// PAGE_VIEW: 'page_view'
|
|
46
|
+
PAGE_VIEW_FIRST: 'pf',
|
|
47
|
+
PAGE_VIEW_SUBSEQUENT: 'pp',
|
|
48
|
+
|
|
49
|
+
// CONVERSATION_EVENT: 'conversation'
|
|
50
|
+
STICKER: 'sti',
|
|
51
|
+
IMAGE: 'img',
|
|
52
|
+
LOCATION: 'loc',
|
|
53
|
+
ATTACHMENT: 'att',
|
|
54
|
+
TEXT: 'txt',
|
|
55
|
+
QUICK_REPLY: 'qr',
|
|
56
|
+
OPT_IN: 'oin',
|
|
57
|
+
REFERRAL: 'ref',
|
|
58
|
+
POSTBACK_BUTTON: 'btn',
|
|
59
|
+
URL_LINK: 'url',
|
|
60
|
+
OTHER: 'oth',
|
|
61
|
+
HANDOVER_TO_BOT: 'bot',
|
|
62
|
+
|
|
63
|
+
// TRAINING: 'train'
|
|
64
|
+
INTENT_DETECTION: 'int',
|
|
65
|
+
HANDOVER_OCCURRED: 'hum',
|
|
66
|
+
DISAMBIGUATION_SELECTED: 'dis',
|
|
67
|
+
DISAMBIGUATION_OFFERED: 'dio',
|
|
68
|
+
|
|
69
|
+
// REPORT: 'report'
|
|
70
|
+
REPORT_FEEDBACK: 'fdb'
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* @type {Object<TrackingCategory,string>}
|
|
75
|
+
*/
|
|
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
|
+
|
|
81
|
+
// CONVERSATION_EVENT: 'conversation'
|
|
82
|
+
[TrackingCategory.STICKER]: 'User: Sticker',
|
|
83
|
+
[TrackingCategory.IMAGE]: 'User: Image',
|
|
84
|
+
[TrackingCategory.LOCATION]: 'User: Location',
|
|
85
|
+
[TrackingCategory.ATTACHMENT]: 'User: Attachement', // yes, with typo
|
|
86
|
+
[TrackingCategory.TEXT]: 'User: Text',
|
|
87
|
+
[TrackingCategory.QUICK_REPLY]: 'User: Quick reply',
|
|
88
|
+
[TrackingCategory.OPT_IN]: 'Entry: Optin',
|
|
89
|
+
[TrackingCategory.REFERRAL]: 'Entry: Referral',
|
|
90
|
+
[TrackingCategory.POSTBACK_BUTTON]: 'User: Button - bot',
|
|
91
|
+
[TrackingCategory.URL_LINK]: 'User: Button - url',
|
|
92
|
+
[TrackingCategory.OTHER]: 'User: Other',
|
|
93
|
+
[TrackingCategory.HANDOVER_TO_BOT]: 'Entry: Handover in',
|
|
94
|
+
|
|
95
|
+
// TRAINING: 'train'
|
|
96
|
+
[TrackingCategory.INTENT_DETECTION]: 'Intent: Detection',
|
|
97
|
+
[TrackingCategory.HANDOVER_OCCURRED]: 'Bot: Handover out',
|
|
98
|
+
[TrackingCategory.DISAMBIGUATION_SELECTED]: 'Disambiguation: selected',
|
|
99
|
+
[TrackingCategory.DISAMBIGUATION_OFFERED]: 'Disambiguation: offered',
|
|
100
|
+
|
|
101
|
+
// REPORT: 'report'
|
|
102
|
+
[TrackingCategory.REPORT_FEEDBACK]: 'User: Feedback'
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
module.exports = {
|
|
106
|
+
CATEGORY_LABELS,
|
|
107
|
+
TrackingType,
|
|
108
|
+
TrackingCategory,
|
|
109
|
+
ResponseFlag
|
|
110
|
+
};
|
|
@@ -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,11 +26,51 @@ 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]
|
|
34
|
+
* @prop {string} [lang]
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @typedef {object} ConversationEventExtension
|
|
39
|
+
* @prop {string} [skill]
|
|
40
|
+
* @prop {string} [text]
|
|
41
|
+
* @prop {string} [expected]
|
|
42
|
+
* @prop {boolean} expectedTaken
|
|
43
|
+
* @prop {boolean} isContextUpdate
|
|
44
|
+
* @prop {boolean} isAttachment
|
|
45
|
+
* @prop {boolean} isNotification
|
|
46
|
+
* @prop {boolean} isQuickReply
|
|
47
|
+
* @prop {boolean} isPassThread
|
|
48
|
+
* @prop {boolean} isPostback
|
|
49
|
+
* @prop {boolean} isText
|
|
50
|
+
* @prop {boolean} didHandover
|
|
51
|
+
* @prop {boolean} withUser
|
|
52
|
+
* @prop {string} [userId]
|
|
53
|
+
* @prop {number} [feedback]
|
|
54
|
+
* @prop {number} sessionStart
|
|
55
|
+
* @prop {number} sessionDuration
|
|
56
|
+
* @prop {string} [winnerAction]
|
|
57
|
+
* @prop {string} [winnerIntent]
|
|
58
|
+
* @prop {string[]|string} [winnerEntities]
|
|
59
|
+
* @prop {number} [winnerScore]
|
|
60
|
+
* @prop {boolean} [winnerTaken]
|
|
61
|
+
* @prop {string} [intent]
|
|
62
|
+
* @prop {number} [intentScore]
|
|
63
|
+
* @prop {string[]|string} [entities]
|
|
64
|
+
* @prop {string[]|string} allActions
|
|
65
|
+
* @prop {boolean} nonInteractive
|
|
66
|
+
* @prop {string} [snapshot]
|
|
67
|
+
* @prop {string} [botId]
|
|
68
|
+
*
|
|
69
|
+
* @typedef {Event & ConversationEventExtension} ConversationEvent
|
|
70
|
+
*/
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @typedef {ConversationEvent | Event} TrackingEvent
|
|
31
74
|
*/
|
|
32
75
|
|
|
33
76
|
/**
|
|
@@ -35,6 +78,8 @@ const Ai = require('../Ai');
|
|
|
35
78
|
* @prop {number} [sessionCount]
|
|
36
79
|
* @prop {string} [lang]
|
|
37
80
|
* @prop {string} [action]
|
|
81
|
+
* @prop {string} [snapshot]
|
|
82
|
+
* @prop {string} [botId]
|
|
38
83
|
*/
|
|
39
84
|
|
|
40
85
|
/**
|
|
@@ -45,6 +90,7 @@ const Ai = require('../Ai');
|
|
|
45
90
|
* @param {SessionMetadata} [metadata]
|
|
46
91
|
* @param {number} [ts]
|
|
47
92
|
* @param {boolean} [nonInteractive]
|
|
93
|
+
* @param {string} [timeZone]
|
|
48
94
|
* @returns {Promise}
|
|
49
95
|
*/
|
|
50
96
|
|
|
@@ -53,11 +99,12 @@ const Ai = require('../Ai');
|
|
|
53
99
|
* @param {string} pageId
|
|
54
100
|
* @param {string} senderId
|
|
55
101
|
* @param {string} sessionId
|
|
56
|
-
* @param {
|
|
102
|
+
* @param {TrackingEvent[]} events
|
|
57
103
|
* @param {GAUser} [user]
|
|
58
104
|
* @param {number} [ts]
|
|
59
105
|
* @param {boolean} [nonInteractive]
|
|
60
106
|
* @param {boolean} [sessionStarted]
|
|
107
|
+
* @param {string} [timeZone]
|
|
61
108
|
* @returns {Promise}
|
|
62
109
|
*/
|
|
63
110
|
|
|
@@ -72,6 +119,9 @@ const Ai = require('../Ai');
|
|
|
72
119
|
* @prop {StoreEvents} storeEvents
|
|
73
120
|
* @prop {CreateUserSession} createUserSession
|
|
74
121
|
* @prop {boolean} [hasExtendedEvents]
|
|
122
|
+
* @prop {boolean} [supportsArrays]
|
|
123
|
+
* @prop {boolean} [useDescriptiveCategories]
|
|
124
|
+
* @prop {boolean} [useExtendedScalars]
|
|
75
125
|
*/
|
|
76
126
|
|
|
77
127
|
/**
|
|
@@ -88,7 +138,7 @@ const Ai = require('../Ai');
|
|
|
88
138
|
|
|
89
139
|
/**
|
|
90
140
|
* @typedef {object} TrackingEvents
|
|
91
|
-
* @prop {
|
|
141
|
+
* @prop {TrackingEvent[]} events
|
|
92
142
|
*/
|
|
93
143
|
|
|
94
144
|
/**
|
|
@@ -98,6 +148,9 @@ const Ai = require('../Ai');
|
|
|
98
148
|
|
|
99
149
|
/**
|
|
100
150
|
* @typedef {object} HandlerConfig
|
|
151
|
+
* @prop {string} [snapshot]
|
|
152
|
+
* @prop {string} [botId]
|
|
153
|
+
* @prop {string} [timeZone] - default UTC
|
|
101
154
|
* @prop {boolean} [enabled] - default true
|
|
102
155
|
* @prop {boolean} [throwException] - default false
|
|
103
156
|
* @prop {IGALogger} [log] - console like logger
|
|
@@ -134,12 +187,26 @@ function onInteractionHandler (
|
|
|
134
187
|
enabled = true,
|
|
135
188
|
throwException = false,
|
|
136
189
|
log = console,
|
|
190
|
+
snapshot,
|
|
191
|
+
botId,
|
|
192
|
+
timeZone = 'UTC',
|
|
137
193
|
anonymize = (x) => x,
|
|
138
194
|
userExtractor = (state) => null // eslint-disable-line no-unused-vars
|
|
139
195
|
},
|
|
140
196
|
analyticsStorage,
|
|
141
197
|
ai = Ai.ai
|
|
142
198
|
) {
|
|
199
|
+
const {
|
|
200
|
+
supportsArrays = false,
|
|
201
|
+
useExtendedScalars = false,
|
|
202
|
+
hasExtendedEvents = false,
|
|
203
|
+
useDescriptiveCategories = true
|
|
204
|
+
} = analyticsStorage;
|
|
205
|
+
|
|
206
|
+
const asArray = (data = []) => (supportsArrays ? data : data.join(','));
|
|
207
|
+
const asCategory = (cat) => (useDescriptiveCategories && CATEGORY_LABELS[cat]) || cat;
|
|
208
|
+
const noneAction = useExtendedScalars ? null : '(none)';
|
|
209
|
+
const noneValue = useExtendedScalars ? -1 : 0;
|
|
143
210
|
|
|
144
211
|
/**
|
|
145
212
|
* @param {InteractionEvent} params
|
|
@@ -151,13 +218,14 @@ function onInteractionHandler (
|
|
|
151
218
|
// state,
|
|
152
219
|
// data,
|
|
153
220
|
skill,
|
|
154
|
-
|
|
221
|
+
events,
|
|
222
|
+
flag,
|
|
223
|
+
nonInteractive
|
|
155
224
|
}) {
|
|
156
225
|
if (!enabled) {
|
|
157
226
|
return;
|
|
158
227
|
}
|
|
159
228
|
try {
|
|
160
|
-
const nonInteractive = !!req.campaign;
|
|
161
229
|
const {
|
|
162
230
|
pageId,
|
|
163
231
|
senderId,
|
|
@@ -168,16 +236,20 @@ function onInteractionHandler (
|
|
|
168
236
|
_snew: createSession,
|
|
169
237
|
_sct: sessionCount,
|
|
170
238
|
_sid: sessionId,
|
|
239
|
+
_sst: sessionStart,
|
|
240
|
+
_sts: sessionTs,
|
|
171
241
|
lang
|
|
172
242
|
} = req.state;
|
|
173
243
|
|
|
174
|
-
const [action =
|
|
244
|
+
const [action = noneAction, ...otherActions] = actions;
|
|
175
245
|
|
|
176
246
|
if (createSession) {
|
|
177
247
|
const metadata = {
|
|
178
248
|
sessionCount,
|
|
179
249
|
lang,
|
|
180
|
-
action
|
|
250
|
+
action,
|
|
251
|
+
snapshot,
|
|
252
|
+
botId
|
|
181
253
|
};
|
|
182
254
|
|
|
183
255
|
await analyticsStorage.createUserSession(
|
|
@@ -186,7 +258,8 @@ function onInteractionHandler (
|
|
|
186
258
|
sessionId,
|
|
187
259
|
metadata,
|
|
188
260
|
timestamp,
|
|
189
|
-
nonInteractive
|
|
261
|
+
nonInteractive,
|
|
262
|
+
timeZone
|
|
190
263
|
);
|
|
191
264
|
}
|
|
192
265
|
|
|
@@ -211,7 +284,7 @@ function onInteractionHandler (
|
|
|
211
284
|
|
|
212
285
|
if (winners.length > 0) {
|
|
213
286
|
[{
|
|
214
|
-
action: winnerAction =
|
|
287
|
+
action: winnerAction = noneAction,
|
|
215
288
|
sort: winnerScore = 0,
|
|
216
289
|
intent: { intent: winnerIntent, entities: winnerEntities = [] }
|
|
217
290
|
}] = winners;
|
|
@@ -221,6 +294,15 @@ function onInteractionHandler (
|
|
|
221
294
|
|
|
222
295
|
const expected = req.expected() ? req.expected().action : '';
|
|
223
296
|
|
|
297
|
+
const feedbackEvent = events.find((e) => e.type === TrackingType.REPORT
|
|
298
|
+
&& e.category === TrackingCategory.REPORT_FEEDBACK);
|
|
299
|
+
const feedback = feedbackEvent
|
|
300
|
+
? feedbackEvent.value
|
|
301
|
+
: noneValue;
|
|
302
|
+
const didHandover = flag === ResponseFlag.HANDOVER;
|
|
303
|
+
|
|
304
|
+
const user = userExtractor(req.state);
|
|
305
|
+
|
|
224
306
|
const isContextUpdate = req.isSetContext();
|
|
225
307
|
const isNotification = !!req.campaign;
|
|
226
308
|
const isAttachment = req.isAttachment();
|
|
@@ -229,13 +311,17 @@ function onInteractionHandler (
|
|
|
229
311
|
const isText = !isQuickReply && req.isText();
|
|
230
312
|
const isPostback = req.isPostBack();
|
|
231
313
|
|
|
232
|
-
const allActions = actions
|
|
314
|
+
const allActions = asArray(actions);
|
|
233
315
|
const requestAction = req.action();
|
|
234
316
|
|
|
235
|
-
const
|
|
317
|
+
const trackEvents = [];
|
|
318
|
+
|
|
319
|
+
const langsExtension = hasExtendedEvents
|
|
320
|
+
? { lang }
|
|
321
|
+
: { cd1: lang };
|
|
236
322
|
|
|
237
323
|
const actionMeta = {
|
|
238
|
-
requestAction: req.action() ||
|
|
324
|
+
requestAction: req.action() || noneAction,
|
|
239
325
|
expected,
|
|
240
326
|
expectedTaken: requestAction === expected,
|
|
241
327
|
isContextUpdate,
|
|
@@ -245,20 +331,29 @@ function onInteractionHandler (
|
|
|
245
331
|
isPassThread,
|
|
246
332
|
isText,
|
|
247
333
|
isPostback,
|
|
334
|
+
didHandover,
|
|
335
|
+
withUser: user !== null && !!user.id,
|
|
336
|
+
sessionStart,
|
|
337
|
+
sessionDuration: sessionTs - sessionStart,
|
|
338
|
+
feedback,
|
|
339
|
+
skill: webalize(skill),
|
|
340
|
+
snapshot,
|
|
341
|
+
botId,
|
|
248
342
|
winnerAction,
|
|
249
343
|
winnerIntent,
|
|
250
|
-
winnerEntities: winnerEntities.map((e) => e.entity)
|
|
344
|
+
winnerEntities: asArray(winnerEntities.map((e) => e.entity)),
|
|
251
345
|
winnerScore,
|
|
252
346
|
winnerTaken,
|
|
253
347
|
intent,
|
|
254
348
|
intentScore: score,
|
|
255
|
-
entities: req.entities.map((e) => e.entity)
|
|
349
|
+
entities: asArray(req.entities.map((e) => e.entity)),
|
|
256
350
|
text,
|
|
257
351
|
allActions
|
|
258
352
|
};
|
|
259
353
|
|
|
260
|
-
|
|
261
|
-
type:
|
|
354
|
+
trackEvents.push({
|
|
355
|
+
type: TrackingType.PAGE_VIEW,
|
|
356
|
+
category: asCategory(TrackingCategory.PAGE_VIEW_FIRST),
|
|
262
357
|
action,
|
|
263
358
|
allActions,
|
|
264
359
|
nonInteractive,
|
|
@@ -267,15 +362,16 @@ function onInteractionHandler (
|
|
|
267
362
|
skill,
|
|
268
363
|
lang,
|
|
269
364
|
cd1: req.state.lang,
|
|
270
|
-
...(
|
|
365
|
+
...(hasExtendedEvents ? {} : actionMeta)
|
|
271
366
|
});
|
|
272
367
|
|
|
273
368
|
let prevAction = action;
|
|
274
369
|
|
|
275
|
-
|
|
370
|
+
trackEvents.push(
|
|
276
371
|
...otherActions.map((a) => {
|
|
277
372
|
const r = {
|
|
278
|
-
type:
|
|
373
|
+
type: TrackingType.PAGE_VIEW,
|
|
374
|
+
category: asCategory(TrackingCategory.PAGE_VIEW_SUBSEQUENT),
|
|
279
375
|
action: a,
|
|
280
376
|
allActions,
|
|
281
377
|
nonInteractive: false,
|
|
@@ -283,9 +379,7 @@ function onInteractionHandler (
|
|
|
283
379
|
prevAction,
|
|
284
380
|
skill,
|
|
285
381
|
isGoto: true,
|
|
286
|
-
...
|
|
287
|
-
? { lang }
|
|
288
|
-
: { cd1: lang })
|
|
382
|
+
...langsExtension
|
|
289
383
|
};
|
|
290
384
|
|
|
291
385
|
prevAction = a;
|
|
@@ -293,8 +387,8 @@ function onInteractionHandler (
|
|
|
293
387
|
})
|
|
294
388
|
);
|
|
295
389
|
|
|
296
|
-
|
|
297
|
-
...
|
|
390
|
+
trackEvents.push(
|
|
391
|
+
...events.map(({
|
|
298
392
|
type, category, action: eventAction, label, value
|
|
299
393
|
}) => ({
|
|
300
394
|
lastAction,
|
|
@@ -303,93 +397,88 @@ function onInteractionHandler (
|
|
|
303
397
|
action: eventAction,
|
|
304
398
|
label,
|
|
305
399
|
value,
|
|
306
|
-
...
|
|
307
|
-
? { lang }
|
|
308
|
-
: { cd1: lang })
|
|
400
|
+
...langsExtension
|
|
309
401
|
}))
|
|
310
402
|
);
|
|
311
403
|
|
|
312
404
|
if (!nonInteractive) {
|
|
313
405
|
|
|
314
406
|
if (req.isText()) {
|
|
315
|
-
|
|
316
|
-
type:
|
|
407
|
+
trackEvents.push({
|
|
408
|
+
type: TrackingType.TRAINING,
|
|
317
409
|
// @ts-ignore
|
|
318
410
|
lastAction,
|
|
319
|
-
category:
|
|
411
|
+
category: asCategory(TrackingCategory.INTENT_DETECTION),
|
|
320
412
|
intent,
|
|
321
413
|
action,
|
|
322
414
|
label: text,
|
|
323
415
|
value: score >= ai.confidence ? 0 : 1,
|
|
324
|
-
...
|
|
325
|
-
? { lang }
|
|
326
|
-
: { cd1: lang })
|
|
416
|
+
...langsExtension
|
|
327
417
|
});
|
|
328
418
|
}
|
|
329
419
|
|
|
330
420
|
const notHandled = actions.some((a) => a.match(/\*$/)) && !req.isQuickReply();
|
|
331
421
|
|
|
332
|
-
let actionCategory
|
|
333
|
-
let label =
|
|
422
|
+
let actionCategory;
|
|
423
|
+
let label = noneAction;
|
|
334
424
|
const value = notHandled ? 1 : 0;
|
|
335
425
|
|
|
336
|
-
if (
|
|
337
|
-
actionCategory
|
|
426
|
+
if (isPassThread) {
|
|
427
|
+
actionCategory = TrackingCategory.HANDOVER_TO_BOT;
|
|
428
|
+
} else if (req.isSticker()) {
|
|
429
|
+
actionCategory = TrackingCategory.STICKER;
|
|
338
430
|
label = req.attachmentUrl(0);
|
|
339
431
|
} else if (req.isImage()) {
|
|
340
|
-
actionCategory
|
|
432
|
+
actionCategory = TrackingCategory.IMAGE;
|
|
341
433
|
label = req.attachmentUrl(0);
|
|
342
434
|
} else if (req.hasLocation()) {
|
|
343
|
-
actionCategory
|
|
435
|
+
actionCategory = TrackingCategory.LOCATION;
|
|
344
436
|
const { lat, long } = req.getLocation();
|
|
345
437
|
label = `${lat}, ${long}`;
|
|
346
438
|
} else if (isAttachment) {
|
|
347
|
-
actionCategory
|
|
439
|
+
actionCategory = TrackingCategory.ATTACHMENT;
|
|
348
440
|
label = req.attachment(0).type;
|
|
349
441
|
} else if (isText) {
|
|
350
|
-
actionCategory
|
|
442
|
+
actionCategory = TrackingCategory.TEXT;
|
|
351
443
|
label = text;
|
|
352
444
|
} else if (isQuickReply) {
|
|
353
|
-
actionCategory
|
|
445
|
+
actionCategory = TrackingCategory.QUICK_REPLY;
|
|
354
446
|
label = text;
|
|
355
|
-
} else if (req.
|
|
356
|
-
actionCategory =
|
|
357
|
-
|
|
358
|
-
|
|
447
|
+
} else if (req.isOptin()) {
|
|
448
|
+
actionCategory = TrackingCategory.OPT_IN;
|
|
449
|
+
} else if (req.isReferral()) {
|
|
450
|
+
actionCategory = TrackingCategory.REFERRAL;
|
|
359
451
|
} else if (isPostback) {
|
|
360
|
-
actionCategory
|
|
452
|
+
actionCategory = TrackingCategory.POSTBACK_BUTTON;
|
|
361
453
|
label = req.data.postback.title || '(unknown)';
|
|
362
454
|
} else {
|
|
363
|
-
actionCategory
|
|
455
|
+
actionCategory = TrackingCategory.OTHER;
|
|
364
456
|
}
|
|
365
457
|
|
|
366
|
-
|
|
458
|
+
trackEvents.push({
|
|
367
459
|
...(analyticsStorage.hasExtendedEvents ? actionMeta : {}),
|
|
368
|
-
type:
|
|
460
|
+
type: TrackingType.CONVERSATION_EVENT,
|
|
369
461
|
// @ts-ignore
|
|
370
462
|
lastAction,
|
|
371
|
-
category: actionCategory,
|
|
463
|
+
category: asCategory(actionCategory),
|
|
372
464
|
action,
|
|
373
465
|
label,
|
|
374
466
|
value,
|
|
375
|
-
...
|
|
376
|
-
? { lang }
|
|
377
|
-
: { cd1: lang })
|
|
467
|
+
...langsExtension
|
|
378
468
|
});
|
|
379
469
|
}
|
|
380
470
|
|
|
381
|
-
const user = userExtractor(req.state);
|
|
382
|
-
|
|
383
471
|
await analyticsStorage.storeEvents(
|
|
384
472
|
pageId,
|
|
385
473
|
senderId,
|
|
386
474
|
sessionId,
|
|
387
475
|
// @ts-ignore
|
|
388
|
-
|
|
476
|
+
trackEvents,
|
|
389
477
|
user,
|
|
390
478
|
timestamp,
|
|
391
479
|
nonInteractive,
|
|
392
|
-
createSession
|
|
480
|
+
createSession,
|
|
481
|
+
timeZone
|
|
393
482
|
);
|
|
394
483
|
} catch (e) {
|
|
395
484
|
if (throwException) {
|
|
@@ -432,7 +521,7 @@ function onInteractionHandler (
|
|
|
432
521
|
[{
|
|
433
522
|
// @ts-ignore
|
|
434
523
|
lastAction,
|
|
435
|
-
...(
|
|
524
|
+
...(hasExtendedEvents
|
|
436
525
|
? { lang }
|
|
437
526
|
: { cd1: lang }),
|
|
438
527
|
...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
|
/**
|