wingbot 3.37.2 → 3.38.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/package.json +1 -1
- package/src/Ai.js +2 -2
- package/src/AiMatching.js +32 -3
- package/src/resolvers/hbs.js +24 -0
- package/src/resolvers/index.js +3 -1
- package/src/resolvers/message.js +33 -15
- package/src/resolvers/skip.js +57 -0
- package/src/utils/customCondition.js +17 -2
- package/src/utils/getUpdate.js +2 -0
- package/src/utils/stateData.js +3 -2
package/package.json
CHANGED
package/src/Ai.js
CHANGED
|
@@ -49,7 +49,7 @@ let uq = 1;
|
|
|
49
49
|
*/
|
|
50
50
|
class Ai {
|
|
51
51
|
|
|
52
|
-
constructor (
|
|
52
|
+
constructor () {
|
|
53
53
|
this._keyworders = new Map();
|
|
54
54
|
|
|
55
55
|
/**
|
|
@@ -111,7 +111,7 @@ class Ai {
|
|
|
111
111
|
*
|
|
112
112
|
* @type {AiMatching}
|
|
113
113
|
*/
|
|
114
|
-
this.matcher =
|
|
114
|
+
this.matcher = new AiMatching(this);
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
/**
|
package/src/AiMatching.js
CHANGED
|
@@ -91,6 +91,11 @@ const COMPARE = {
|
|
|
91
91
|
* @prop {object} [state]
|
|
92
92
|
*/
|
|
93
93
|
|
|
94
|
+
/**
|
|
95
|
+
* @typedef {object} ConfidenceProvider
|
|
96
|
+
* @prop {number} confidence
|
|
97
|
+
*/
|
|
98
|
+
|
|
94
99
|
/**
|
|
95
100
|
* @class {AiMatching}
|
|
96
101
|
*
|
|
@@ -98,7 +103,11 @@ const COMPARE = {
|
|
|
98
103
|
*/
|
|
99
104
|
class AiMatching {
|
|
100
105
|
|
|
101
|
-
|
|
106
|
+
/**
|
|
107
|
+
*
|
|
108
|
+
* @param {ConfidenceProvider} ai
|
|
109
|
+
*/
|
|
110
|
+
constructor (ai = { confidence: 0.8 }) {
|
|
102
111
|
/**
|
|
103
112
|
* When the entity is optional, the final score should be little bit lower
|
|
104
113
|
* (0.001 by default)
|
|
@@ -138,6 +147,8 @@ class AiMatching {
|
|
|
138
147
|
* (1 by default)
|
|
139
148
|
*/
|
|
140
149
|
this.stateEntityScore = 1;
|
|
150
|
+
|
|
151
|
+
this._ai = ai;
|
|
141
152
|
}
|
|
142
153
|
|
|
143
154
|
get redundantHandicap () {
|
|
@@ -447,11 +458,29 @@ class AiMatching {
|
|
|
447
458
|
? score - noIntentHandicap
|
|
448
459
|
: (regexpScore + score) / 2;
|
|
449
460
|
|
|
461
|
+
const matchedEntitiesTextLength = matched.reduce((tot, entity) => (
|
|
462
|
+
typeof entity.end === 'number' && typeof entity.start === 'number' && tot !== null
|
|
463
|
+
? (tot + (entity.end - entity.start))
|
|
464
|
+
: null
|
|
465
|
+
), 0);
|
|
466
|
+
|
|
467
|
+
let finalScore = (baseScore - handicap)
|
|
468
|
+
* (this.multiMatchGain ** countOfAdditionalItems);
|
|
469
|
+
|
|
470
|
+
const textLength = req.text().length;
|
|
471
|
+
|
|
472
|
+
if (matchedEntitiesTextLength && textLength) {
|
|
473
|
+
const remainingScore = Math.max(0, Math.min(1, finalScore) - (
|
|
474
|
+
this._ai.confidence + this.redundantEntityHandicap
|
|
475
|
+
));
|
|
476
|
+
|
|
477
|
+
finalScore -= (matchedEntitiesTextLength / textLength) * remainingScore;
|
|
478
|
+
}
|
|
479
|
+
|
|
450
480
|
return {
|
|
451
481
|
intent: null,
|
|
452
482
|
entities: matched,
|
|
453
|
-
score:
|
|
454
|
-
* (this.multiMatchGain ** countOfAdditionalItems)
|
|
483
|
+
score: finalScore
|
|
455
484
|
};
|
|
456
485
|
}
|
|
457
486
|
|
package/src/resolvers/hbs.js
CHANGED
|
@@ -5,7 +5,31 @@
|
|
|
5
5
|
|
|
6
6
|
let handlebars;
|
|
7
7
|
try {
|
|
8
|
+
// @ts-ignore
|
|
8
9
|
handlebars = module.require('handlebars');
|
|
10
|
+
|
|
11
|
+
handlebars.registerHelper('lang', function langHelper (content) {
|
|
12
|
+
if (typeof content !== 'object' || !content) {
|
|
13
|
+
return content;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const { lang } = this;
|
|
17
|
+
|
|
18
|
+
if (content[lang]) {
|
|
19
|
+
return content[lang];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (Array.isArray(content)) {
|
|
23
|
+
const entry = content.find((c) => c
|
|
24
|
+
&& (!lang || c.l === lang || c.lang === lang) && (c.t || c.text));
|
|
25
|
+
|
|
26
|
+
if (entry) {
|
|
27
|
+
return entry.text || entry.t;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return content[Object.keys(content)[0]];
|
|
32
|
+
});
|
|
9
33
|
} catch (er) {
|
|
10
34
|
handlebars = { compile: (text) => () => text };
|
|
11
35
|
}
|
package/src/resolvers/index.js
CHANGED
|
@@ -16,6 +16,7 @@ const button = require('./button');
|
|
|
16
16
|
const subscribtions = require('./subscribtions');
|
|
17
17
|
const setState = require('./setState');
|
|
18
18
|
const expectedInput = require('./expectedInput');
|
|
19
|
+
const skip = require('./skip');
|
|
19
20
|
|
|
20
21
|
module.exports = {
|
|
21
22
|
path,
|
|
@@ -30,5 +31,6 @@ module.exports = {
|
|
|
30
31
|
button,
|
|
31
32
|
subscribtions,
|
|
32
33
|
setState,
|
|
33
|
-
expectedInput
|
|
34
|
+
expectedInput,
|
|
35
|
+
skip
|
|
34
36
|
};
|
package/src/resolvers/message.js
CHANGED
|
@@ -195,9 +195,6 @@ function message (params, context = {}) {
|
|
|
195
195
|
* @param {Responder} res
|
|
196
196
|
*/
|
|
197
197
|
return (req, res) => {
|
|
198
|
-
if (condition && !condition(req, res)) {
|
|
199
|
-
return ret;
|
|
200
|
-
}
|
|
201
198
|
const data = stateData(req, res, configuration);
|
|
202
199
|
|
|
203
200
|
// filter supported messages
|
|
@@ -216,30 +213,51 @@ function message (params, context = {}) {
|
|
|
216
213
|
const text = textTemplate(data)
|
|
217
214
|
.trim();
|
|
218
215
|
|
|
216
|
+
res.setData({ $this: text });
|
|
217
|
+
if (condition && !condition(req, res)) {
|
|
218
|
+
res.setData({ $this: null });
|
|
219
|
+
return ret;
|
|
220
|
+
}
|
|
221
|
+
res.setData({ $this: null });
|
|
222
|
+
|
|
219
223
|
let sendReplies;
|
|
220
224
|
if (quickReplies) {
|
|
221
|
-
|
|
222
|
-
.filter((reply) => reply.condition(req, res));
|
|
223
|
-
|
|
224
|
-
sendReplies = okQuickReplies
|
|
225
|
+
sendReplies = quickReplies
|
|
225
226
|
.filter((reply) => reply.title
|
|
226
227
|
|| reply.isLocation
|
|
227
228
|
|| reply.isEmail
|
|
228
229
|
|| reply.isPhone)
|
|
229
230
|
.map((reply) => {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
231
|
+
let $this = null;
|
|
232
|
+
let rep;
|
|
233
|
+
|
|
234
|
+
if (reply.isLocation || reply.isEmail || reply.isPhone) {
|
|
235
|
+
rep = { ...reply };
|
|
236
|
+
} else {
|
|
237
|
+
const title = reply.title(data);
|
|
238
|
+
$this = title;
|
|
239
|
+
rep = { ...reply, title };
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (typeof rep.condition !== 'function') {
|
|
243
|
+
return rep;
|
|
244
|
+
}
|
|
233
245
|
|
|
234
|
-
|
|
235
|
-
|
|
246
|
+
res.setData({ $this });
|
|
247
|
+
if (!rep.condition(req, res)) {
|
|
248
|
+
res.setData({ $this: null });
|
|
249
|
+
return null;
|
|
236
250
|
}
|
|
251
|
+
res.setData({ $this: null });
|
|
252
|
+
|
|
253
|
+
delete rep.condition;
|
|
237
254
|
|
|
238
255
|
return rep;
|
|
239
|
-
})
|
|
256
|
+
})
|
|
257
|
+
.filter((rep) => rep !== null);
|
|
240
258
|
|
|
241
|
-
|
|
242
|
-
.filter((reply) => !reply.title && reply.match)
|
|
259
|
+
quickReplies
|
|
260
|
+
.filter((reply) => !reply.title && reply.match && reply.condition(req, res))
|
|
243
261
|
.forEach(({
|
|
244
262
|
match, action, data: replyData, setState, aiTitle
|
|
245
263
|
}) => {
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @author David Menger
|
|
3
|
+
*/
|
|
4
|
+
'use strict';
|
|
5
|
+
|
|
6
|
+
const Router = require('../Router');
|
|
7
|
+
const getCondition = require('../utils/getCondition');
|
|
8
|
+
|
|
9
|
+
/** @typedef {import('../BuildRouter').BotContext} BotContext */
|
|
10
|
+
/** @typedef {import('../Router').Resolver} Resolver */
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
*
|
|
14
|
+
* @param {object} params
|
|
15
|
+
* @param {BotContext} context
|
|
16
|
+
* @returns {Resolver}
|
|
17
|
+
*/
|
|
18
|
+
function skip (params, context = {}) {
|
|
19
|
+
const { isLastIndex } = context;
|
|
20
|
+
const { type } = params;
|
|
21
|
+
|
|
22
|
+
const ret = isLastIndex ? Router.END : Router.CONTINUE;
|
|
23
|
+
|
|
24
|
+
if (['skip', 'end', 'intent'].indexOf(type) === -1) {
|
|
25
|
+
throw new Error(`Unsupported skip type: ${type}`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const condition = getCondition(params, context, 'Skip condition');
|
|
29
|
+
|
|
30
|
+
return (req, res, postBack) => {
|
|
31
|
+
if (condition && !condition(req, res)) {
|
|
32
|
+
return ret;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
switch (type) {
|
|
36
|
+
case 'end':
|
|
37
|
+
return Router.END;
|
|
38
|
+
case 'skip':
|
|
39
|
+
return Router.BREAK;
|
|
40
|
+
case 'intent': {
|
|
41
|
+
let { lastAiActionsIndex = 0 } = req.actionData();
|
|
42
|
+
const actions = req.aiActions();
|
|
43
|
+
lastAiActionsIndex++;
|
|
44
|
+
if (!actions[lastAiActionsIndex] || !actions[lastAiActionsIndex].aboveConfidence) {
|
|
45
|
+
return Router.BREAK;
|
|
46
|
+
}
|
|
47
|
+
postBack(actions[lastAiActionsIndex].action, { lastAiActionsIndex });
|
|
48
|
+
return Router.END;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
default:
|
|
52
|
+
return ret;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
module.exports = skip;
|
|
@@ -88,8 +88,23 @@ const ARRAY_LENGTH_OPERATORS = [
|
|
|
88
88
|
const compare = (variable, operator, value = undefined) => {
|
|
89
89
|
const isArrayLengthCompare = ARRAY_LENGTH_OPERATORS.includes(operator);
|
|
90
90
|
if (Array.isArray(variable) && !isArrayLengthCompare) {
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
if (operator === ConditionOperators['==']
|
|
92
|
+
&& (typeof value === 'number' || isStringNumber(value))) {
|
|
93
|
+
|
|
94
|
+
const numeric = toNumber(value);
|
|
95
|
+
return numeric === variable.length;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (operator === ConditionOperators['not contains']) {
|
|
99
|
+
return variable
|
|
100
|
+
.every((variableElement) => !compare(variableElement, ConditionOperators['=='], value));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const useOperator = operator === ConditionOperators.contains
|
|
104
|
+
? ConditionOperators['==']
|
|
105
|
+
: operator;
|
|
106
|
+
|
|
107
|
+
return variable.some((variableElement) => compare(variableElement, useOperator, value));
|
|
93
108
|
}
|
|
94
109
|
|
|
95
110
|
if (variable && typeof variable === 'object' && !isArrayLengthCompare) {
|
package/src/utils/getUpdate.js
CHANGED
|
@@ -161,6 +161,8 @@ function getSetState (setState, req, res = null, useState = null, configuration
|
|
|
161
161
|
valAsArray.shift();
|
|
162
162
|
} else if (val._$pop) {
|
|
163
163
|
valAsArray.pop();
|
|
164
|
+
} else if (val._$pushT) {
|
|
165
|
+
valAsArray.push(req.text());
|
|
164
166
|
} else {
|
|
165
167
|
const value = val._$add || val._$rem || val._$push || val._$set;
|
|
166
168
|
const [, entity, rear] = `${value}`.match(ENTITY_HBS_REGEXP) || [];
|
package/src/utils/stateData.js
CHANGED
|
@@ -17,11 +17,12 @@ module.exports = function stateData (req, res = null, configuration = null) {
|
|
|
17
17
|
const c = configuration || req.configuration;
|
|
18
18
|
|
|
19
19
|
return {
|
|
20
|
+
c,
|
|
21
|
+
configuration: c,
|
|
20
22
|
...req.state,
|
|
21
23
|
...(res ? res.newState : {}),
|
|
22
24
|
...req.actionData(),
|
|
23
25
|
...(res ? res.data : {}),
|
|
24
|
-
|
|
25
|
-
configuration: c
|
|
26
|
+
$input: req.text()
|
|
26
27
|
};
|
|
27
28
|
};
|