wingbot 3.46.0-alpha.10 → 3.46.0-alpha.11

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.10",
3
+ "version": "3.46.0-alpha.11",
4
4
  "description": "Enterprise Messaging Bot Conversation Engine",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/src/Processor.js CHANGED
@@ -62,6 +62,7 @@ const { mergeState, isUserInteraction } = require('./utils/stateVariables');
62
62
  * @prop {TrackingEvent[]} events
63
63
  * @prop {ResponseFlag|null} flag
64
64
  * @prop {boolean} nonInteractive
65
+ * @prop {string[]} responseTexts
65
66
  */
66
67
 
67
68
  /**
@@ -434,6 +435,7 @@ class Processor extends EventEmitter {
434
435
  const { events = [] } = messageSender.tracking;
435
436
 
436
437
  const event = {
438
+ responseTexts: messageSender.responseTexts,
437
439
  req,
438
440
  actions,
439
441
  lastAction,
@@ -6,6 +6,7 @@
6
6
  const ai = require('./Ai');
7
7
  const { FEATURE_PHRASES, FEATURE_TRACKING } = require('./features');
8
8
  const { ResponseFlag } = require('./analytics/consts');
9
+ const extractText = require('./transcript/extractText');
9
10
 
10
11
  /** @typedef {import('./Request')} Request */
11
12
  /** @typedef {import('./Responder')} Responder */
@@ -122,8 +123,12 @@ class ReturnSender {
122
123
  events: []
123
124
  };
124
125
 
126
+ this._responseTexts = [];
127
+
125
128
  this._intentsAndEntities = [];
126
129
 
130
+ this._confidentInput = false;
131
+
127
132
  /**
128
133
  * @type {Function}
129
134
  * @private
@@ -147,6 +152,18 @@ class ReturnSender {
147
152
  return this._simulatesOptIn;
148
153
  }
149
154
 
155
+ /**
156
+ * @returns {string[]}
157
+ */
158
+ get responseTexts () {
159
+ const filter = this._confidentInput
160
+ ? this.confidentInputFilter
161
+ : this.textFilter;
162
+
163
+ return this._responseTexts
164
+ .map((t) => filter(t));
165
+ }
166
+
150
167
  _gotAnotherEvent () {
151
168
  if (this._gotAnotherEventDefer) {
152
169
  this._gotAnotherEventDefer();
@@ -379,6 +396,10 @@ class ReturnSender {
379
396
  return;
380
397
  }
381
398
 
399
+ const text = extractText(payload);
400
+ if (text) {
401
+ this._responseTexts.push(text);
402
+ }
382
403
  this._queue.push(payload);
383
404
  this._gotAnotherEvent();
384
405
 
@@ -509,7 +530,7 @@ class ReturnSender {
509
530
  async finished (req = null, res = null, err = null, reportError = console.error) {
510
531
  this._finish(req);
511
532
  const meta = this._createMeta(req, res);
512
- const confidentInput = req && req.isConfidentInput();
533
+ this._confidentInput = !!req && req.isConfidentInput();
513
534
  let error = err;
514
535
  try {
515
536
  await this._promise;
@@ -526,7 +547,7 @@ class ReturnSender {
526
547
  const processedEvent = req
527
548
  ? req.event
528
549
  : this._incommingMessage;
529
- let incomming = this._filterMessage(processedEvent, confidentInput, req);
550
+ let incomming = this._filterMessage(processedEvent, this._confidentInput, req);
530
551
 
531
552
  if (processedEvent !== this._incommingMessage) {
532
553
  incomming = {
@@ -95,6 +95,7 @@ const {
95
95
  * @prop {string} [timeZone]
96
96
  * @prop {number} [sessionStart]
97
97
  * @prop {number} [sessionDuration]
98
+ * @prop {string[]} [responseTexts]
98
99
  */
99
100
 
100
101
  /**
@@ -236,7 +237,8 @@ function onInteractionHandler (
236
237
  skill,
237
238
  events,
238
239
  flag,
239
- nonInteractive
240
+ nonInteractive,
241
+ responseTexts
240
242
  }) {
241
243
  if (!enabled) {
242
244
  return;
@@ -292,6 +294,7 @@ function onInteractionHandler (
292
294
  feedback,
293
295
  timeZone,
294
296
  sessionStart,
297
+ responseTexts,
295
298
  sessionDuration: sessionTs - sessionStart
296
299
  };
297
300
 
@@ -0,0 +1,70 @@
1
+ /**
2
+ * @author David Menger
3
+ */
4
+ 'use strict';
5
+
6
+ /**
7
+ * @class MemoryChatLogStorage
8
+ */
9
+ class MemoryChatLogStorage {
10
+
11
+ constructor () {
12
+ this._logs = new Map();
13
+ }
14
+
15
+ /**
16
+ * Interate history
17
+ * all limits are inclusive
18
+ *
19
+ * @param {string} senderId
20
+ * @param {string} pageId
21
+ * @param {number} [limit]
22
+ * @param {number} [endAt] - iterate backwards to history
23
+ * @param {number} [startAt] - iterate forward to last interaction
24
+ * @returns {Promise<object[]>}
25
+ */
26
+ async getInteractions (senderId, pageId, limit = 10, endAt = null, startAt = null) { // eslint-disable-line max-len,no-unused-vars
27
+ const events = this._getEvents(senderId);
28
+ return events.slice(-limit);
29
+ }
30
+
31
+ /**
32
+ *
33
+ * @param {string} senderId
34
+ * @returns {object[]}
35
+ */
36
+ _getEvents (senderId) {
37
+ let events = this._logs.get(senderId);
38
+ if (!events) {
39
+ events = [];
40
+ this._logs.set(senderId, events);
41
+ }
42
+ return events;
43
+ }
44
+
45
+ /**
46
+ * Log single event
47
+ *
48
+ * @param {string} senderId
49
+ * @param {object[]} responses - list of sent responses
50
+ * @param {object} request - event request
51
+ * @param {object} [metadata] - request metadata
52
+ * @returns {void}
53
+ */
54
+ log (senderId, responses = [], request = {}, metadata = {}) {
55
+ const events = this._getEvents(senderId);
56
+ events.push({
57
+ senderId,
58
+ request,
59
+ responses,
60
+ ...metadata
61
+ });
62
+ }
63
+
64
+ error (error, senderId, sent, incomming, meta) {
65
+ return this.log(senderId, sent, incomming, { ...meta, error });
66
+ }
67
+
68
+ }
69
+
70
+ module.exports = MemoryChatLogStorage;
@@ -0,0 +1,54 @@
1
+ /**
2
+ * @author David Menger
3
+ */
4
+ 'use strict';
5
+
6
+ /**
7
+ * Extracts text from conversational event
8
+ *
9
+ * @param {object} payload
10
+ * @returns {string|null}
11
+ */
12
+ function extractText (payload) {
13
+
14
+ // text message
15
+ if (payload.message && payload.message.text) {
16
+ return payload.message.text;
17
+ }
18
+
19
+ // button message
20
+ if (payload.message && payload.message.attachment
21
+ && payload.message.attachment.type === 'template'
22
+ && payload.message.attachment.payload
23
+ && payload.message.attachment.payload.text) {
24
+
25
+ return payload.message.attachment.payload.text;
26
+ }
27
+
28
+ if (!payload.postback) {
29
+ return null;
30
+ }
31
+
32
+ // postback with title
33
+ if (payload.postback.title) {
34
+ return payload.postback.title;
35
+ }
36
+
37
+ if (payload.postback.payload && payload.postback.payload.action) {
38
+ return payload.postback.payload.action;
39
+ }
40
+
41
+ if (typeof payload.postback.payload !== 'string') {
42
+ return null;
43
+ }
44
+
45
+ if (payload.postback.payload[0] === '{') {
46
+ const pl = JSON.parse(payload.postback.payload);
47
+
48
+ return pl.action;
49
+ }
50
+
51
+ return payload.postback.payload;
52
+ }
53
+
54
+ module.exports = extractText;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @author David Menger
3
+ */
4
+ 'use strict';
5
+
6
+ /** @typedef {import('./transcriptFromHistory').Transcript} Transcript */
7
+
8
+ /**
9
+ * @param {Transcript[]} transcript
10
+ * @param {string} [userSide]
11
+ * @param {string} [botSide]
12
+ * @returns {string}
13
+ */
14
+ function htmlBodyFromTranscript (transcript, userSide = 'User', botSide = 'Bot') {
15
+
16
+ return transcript
17
+ .map((msg) => `<b>${msg.fromBot ? botSide : userSide}:</b> ${msg.text}`)
18
+ .join('<br />');
19
+ }
20
+
21
+ module.exports = htmlBodyFromTranscript;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @author David Menger
3
+ */
4
+ 'use strict';
5
+
6
+ /** @typedef {import('./transcriptFromHistory').Transcript} Transcript */
7
+
8
+ /**
9
+ * @param {Transcript[]} transcript
10
+ * @param {string} [userSide]
11
+ * @param {string} [botSide]
12
+ * @returns {string}
13
+ */
14
+ function textBodyFromTranscript (transcript, userSide = 'User', botSide = 'Bot') {
15
+
16
+ return transcript
17
+ .map((msg, i) => `${msg.fromBot ? ' <' : `${i > 0 ? '\n' : ''}# >`} ${msg.fromBot ? botSide : userSide}: ${msg.text}`)
18
+ .join('\n');
19
+ }
20
+
21
+ module.exports = textBodyFromTranscript;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * @author David Menger
3
+ */
4
+ 'use strict';
5
+
6
+ const extractText = require('./extractText');
7
+
8
+ /**
9
+ * @callback GetInteractions
10
+ * @param {string} senderId
11
+ * @param {string} pageId
12
+ * @param {number} limit
13
+ * @returns {Promise<object[]>}
14
+ */
15
+
16
+ /**
17
+ * @typedef {object} IChatStorage
18
+ * @prop {GetInteractions} getInteractions
19
+ */
20
+
21
+ /**
22
+ * @typedef {object} Transcript
23
+ * @prop {string} text
24
+ * @prop {boolean} fromBot
25
+ */
26
+
27
+ /**
28
+ *
29
+ * @param {IChatStorage} chatLogStorage
30
+ * @param {string} senderId
31
+ * @param {string} pageId
32
+ * @param {number} limit
33
+ * @returns {Promise<Transcript[]>}
34
+ */
35
+ async function transcriptFromHistory (chatLogStorage, senderId, pageId, limit = 20) {
36
+ const data = await chatLogStorage.getInteractions(senderId, pageId, limit);
37
+
38
+ return data
39
+ .map((turn) => {
40
+ const { request, responses = [] } = turn;
41
+
42
+ return [
43
+ { fromBot: false, text: extractText(request) },
44
+ ...responses
45
+ .map((response) => ({ fromBot: true, text: extractText(response) }))
46
+ ];
47
+ })
48
+ .reduce((ret, arr) => [...ret, ...arr], [])
49
+ .filter((ret) => !!ret.text);
50
+ }
51
+
52
+ module.exports = transcriptFromHistory;