wingbot 3.42.1 → 3.43.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/plugins/ai.wingbot.slotsContinue/plugin.js +8 -2
- package/plugins/plugins.json +13 -1
- package/src/Ai.js +79 -3
- package/src/resolvers/message.js +7 -0
- package/src/systemEntities/email.js +6 -1
- package/src/systemEntities/phone.js +5 -0
- package/src/wingbot/CachedModel.js +34 -6
- package/src/wingbot/CustomEntityDetectionModel.js +16 -9
- package/src/wingbot/WingbotModel.js +1 -7
package/package.json
CHANGED
|
@@ -11,10 +11,12 @@ const { vars } = require('../../src/utils/stateVariables');
|
|
|
11
11
|
/**
|
|
12
12
|
* @param {object} params
|
|
13
13
|
* @param {string} [params.skip]
|
|
14
|
+
* @param {string} [params.fill]
|
|
14
15
|
* @returns {SlotsResolver}
|
|
15
16
|
*/
|
|
16
17
|
function slotsContinue ({
|
|
17
|
-
skip
|
|
18
|
+
skip,
|
|
19
|
+
fill
|
|
18
20
|
}) {
|
|
19
21
|
|
|
20
22
|
/**
|
|
@@ -39,6 +41,10 @@ function slotsContinue ({
|
|
|
39
41
|
.split(',')
|
|
40
42
|
.map((e) => e.trim());
|
|
41
43
|
|
|
44
|
+
const fillEntities = compileWithState(req, res, fill)
|
|
45
|
+
.split(',')
|
|
46
|
+
.map((e) => e.trim());
|
|
47
|
+
|
|
42
48
|
const clear = {};
|
|
43
49
|
|
|
44
50
|
slotState = slotState.map((s) => {
|
|
@@ -52,7 +58,7 @@ function slotsContinue ({
|
|
|
52
58
|
return { ...s, s: StepState.INITIALIZED };
|
|
53
59
|
}
|
|
54
60
|
|
|
55
|
-
return s.e === step.entity
|
|
61
|
+
return s.e === step.entity || fillEntities.includes(s.e)
|
|
56
62
|
? { ...s, s: StepState.FILLED }
|
|
57
63
|
: s;
|
|
58
64
|
});
|
package/plugins/plugins.json
CHANGED
|
@@ -415,7 +415,7 @@
|
|
|
415
415
|
{
|
|
416
416
|
"type": "select",
|
|
417
417
|
"name": "type",
|
|
418
|
-
"label": "
|
|
418
|
+
"label": "Type",
|
|
419
419
|
"options": [
|
|
420
420
|
{ "label": "Required", "value": "req" },
|
|
421
421
|
{ "label": "Multi value", "value": "mul" },
|
|
@@ -454,6 +454,18 @@
|
|
|
454
454
|
"validations": [
|
|
455
455
|
{ "type": "regexp", "value": "^\\s*@[a-zA-Z0-9-]+\\s*(,\\s*@[a-zA-Z0-9-]+\\s*)*$", "message": "the entity for the slot filling should be valid" }
|
|
456
456
|
]
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
"name": "fill",
|
|
460
|
+
"label": "Skip entity (mark as filled)",
|
|
461
|
+
"type": "text",
|
|
462
|
+
"validations": [
|
|
463
|
+
{
|
|
464
|
+
"type": "regexp",
|
|
465
|
+
"value": "^(\\s*@[a-zA-Z0-9-]+\\s*,?)*$",
|
|
466
|
+
"message": "the entity to skip should be valid"
|
|
467
|
+
}
|
|
468
|
+
]
|
|
457
469
|
}
|
|
458
470
|
],
|
|
459
471
|
"items": [
|
package/src/Ai.js
CHANGED
|
@@ -7,12 +7,15 @@ const { WingbotModel } = require('./wingbot');
|
|
|
7
7
|
const AiMatching = require('./AiMatching');
|
|
8
8
|
const { vars } = require('./utils/stateVariables');
|
|
9
9
|
const { deepEqual } = require('./utils/deepMapTools');
|
|
10
|
+
const systemEntities = require('./systemEntities');
|
|
10
11
|
const CustomEntityDetectionModel = require('./wingbot/CustomEntityDetectionModel');
|
|
11
12
|
|
|
12
13
|
const DEFAULT_PREFIX = 'default';
|
|
13
14
|
|
|
14
15
|
let uq = 1;
|
|
15
16
|
|
|
17
|
+
/** @typedef {import('./AiMatching').Compare} Compare */
|
|
18
|
+
|
|
16
19
|
/**
|
|
17
20
|
* @typedef {object} EntityExpression
|
|
18
21
|
* @prop {string} entity - the requested entity
|
|
@@ -43,6 +46,10 @@ let uq = 1;
|
|
|
43
46
|
/** @typedef {import('./Responder')} Responder */
|
|
44
47
|
/** @typedef {import('./wingbot/CachedModel').Result} Result */
|
|
45
48
|
/** @typedef {import('./wingbot/CustomEntityDetectionModel').Phrases} Phrases */
|
|
49
|
+
/** @typedef {import('./wingbot/CustomEntityDetectionModel').EntityDetector} EntityDetector */
|
|
50
|
+
/** @typedef {import('./wingbot/CustomEntityDetectionModel').DetectorOptions} DetectorOptions */
|
|
51
|
+
|
|
52
|
+
/** @typedef {[string,EntityDetector|RegExp,DetectorOptions]} DetectorArgs */
|
|
46
53
|
|
|
47
54
|
/**
|
|
48
55
|
* @class Ai
|
|
@@ -50,8 +57,20 @@ let uq = 1;
|
|
|
50
57
|
class Ai {
|
|
51
58
|
|
|
52
59
|
constructor () {
|
|
60
|
+
/**
|
|
61
|
+
* @private
|
|
62
|
+
* @type {Map<string,CustomEntityDetectionModel>}
|
|
63
|
+
*/
|
|
53
64
|
this._keyworders = new Map();
|
|
54
65
|
|
|
66
|
+
/**
|
|
67
|
+
* @private
|
|
68
|
+
* @type {Map<string,DetectorArgs>}
|
|
69
|
+
*/
|
|
70
|
+
this._detectors = new Map(
|
|
71
|
+
systemEntities.map((a) => [a[0], a])
|
|
72
|
+
);
|
|
73
|
+
|
|
55
74
|
/**
|
|
56
75
|
* Upper threshold - for match method and for navigate method
|
|
57
76
|
*
|
|
@@ -157,29 +176,86 @@ class Ai {
|
|
|
157
176
|
/**
|
|
158
177
|
* Registers Wingbot AI model
|
|
159
178
|
*
|
|
160
|
-
* @template T
|
|
179
|
+
* @template {CustomEntityDetectionModel} T
|
|
161
180
|
* @param {string|WingbotModel|T} model - wingbot model name or AI plugin
|
|
162
181
|
* @param {string} prefix - model prefix
|
|
163
182
|
*
|
|
164
|
-
* @returns {
|
|
183
|
+
* @returns {T}
|
|
165
184
|
* @memberOf Ai
|
|
166
185
|
*/
|
|
167
186
|
register (model, prefix = 'default') {
|
|
187
|
+
/** @type {T} */
|
|
168
188
|
let modelObj;
|
|
169
189
|
|
|
170
190
|
if (typeof model === 'string') {
|
|
191
|
+
// @ts-ignore
|
|
171
192
|
modelObj = new WingbotModel({
|
|
172
193
|
model
|
|
173
194
|
}, this.logger);
|
|
174
195
|
} else {
|
|
196
|
+
// @ts-ignore
|
|
175
197
|
modelObj = model;
|
|
176
198
|
}
|
|
177
199
|
|
|
178
200
|
this._keyworders.set(prefix, modelObj);
|
|
179
201
|
|
|
202
|
+
for (const entityArgs of this._detectors.values()) {
|
|
203
|
+
modelObj.setEntityDetector(...entityArgs);
|
|
204
|
+
}
|
|
205
|
+
|
|
180
206
|
return modelObj;
|
|
181
207
|
}
|
|
182
208
|
|
|
209
|
+
/**
|
|
210
|
+
*
|
|
211
|
+
* @param {string} name
|
|
212
|
+
* @param {EntityDetector|RegExp} detector
|
|
213
|
+
* @param {object} [options]
|
|
214
|
+
* @param {boolean} [options.anonymize] - if true, value will not be sent to NLP
|
|
215
|
+
* @param {Function|string} [options.extractValue] - entity extractor
|
|
216
|
+
* @param {boolean} [options.matchWholeWords] - match whole words at regular expression
|
|
217
|
+
* @param {boolean} [options.replaceDiacritics] - keep diacritics when matching regexp
|
|
218
|
+
* @param {string[]} [options.dependencies] - array of dependent entities
|
|
219
|
+
* @param {boolean} [options.clearOverlaps] - let longer entities from NLP to replace entity
|
|
220
|
+
* @returns {this}
|
|
221
|
+
*/
|
|
222
|
+
registerEntityDetector (name, detector, options = {}) {
|
|
223
|
+
const useOptions = { clearOverlaps: true, ...options };
|
|
224
|
+
|
|
225
|
+
this._detectors.set(name, [name, detector, useOptions]);
|
|
226
|
+
|
|
227
|
+
for (const model of this._keyworders.values()) {
|
|
228
|
+
model.setEntityDetector(name, detector, useOptions);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return this;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Sets options to entity detector.
|
|
236
|
+
* Useful for disabling anonymization of local system entities.
|
|
237
|
+
*
|
|
238
|
+
* @param {string} name
|
|
239
|
+
* @param {object} options
|
|
240
|
+
* @param {boolean} [options.anonymize]
|
|
241
|
+
* @returns {this}
|
|
242
|
+
* @example
|
|
243
|
+
*
|
|
244
|
+
* ai.register('wingbot-model-name')
|
|
245
|
+
* .setDetectorOptions('phone', { anonymize: false })
|
|
246
|
+
* .setDetectorOptions('email', { anonymize: false })
|
|
247
|
+
*/
|
|
248
|
+
configureEntityDetector (name, options) {
|
|
249
|
+
if (!this._detectors.has(name)) {
|
|
250
|
+
throw new Error(`Can't set entity detector options. Entity "${name}" does not exist.`);
|
|
251
|
+
}
|
|
252
|
+
Object.assign(this._detectors.get(name)[2], options);
|
|
253
|
+
for (const model of this._keyworders.values()) {
|
|
254
|
+
model.setDetectorOptions(name, options);
|
|
255
|
+
}
|
|
256
|
+
return this;
|
|
257
|
+
}
|
|
258
|
+
|
|
183
259
|
/**
|
|
184
260
|
* Remove registered model
|
|
185
261
|
*
|
|
@@ -194,7 +270,7 @@ class Ai {
|
|
|
194
270
|
*
|
|
195
271
|
* @param {string} prefix - model prefix
|
|
196
272
|
*
|
|
197
|
-
* @returns {
|
|
273
|
+
* @returns {CustomEntityDetectionModel}
|
|
198
274
|
* @memberOf Ai
|
|
199
275
|
*/
|
|
200
276
|
getModel (prefix = 'default') {
|
package/src/resolvers/message.js
CHANGED
|
@@ -40,6 +40,13 @@ function getVoiceControlFromParams (params, lang = null) {
|
|
|
40
40
|
}
|
|
41
41
|
});
|
|
42
42
|
|
|
43
|
+
// remove empty values ("")
|
|
44
|
+
Object.keys(voiceControl).forEach((key) => {
|
|
45
|
+
if (voiceControl[key] === '') {
|
|
46
|
+
delete voiceControl[key];
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
43
50
|
// if voiceControl is empty, return null
|
|
44
51
|
return Object.keys(voiceControl).length > 0 ? voiceControl : null;
|
|
45
52
|
}
|
|
@@ -3,6 +3,11 @@
|
|
|
3
3
|
*/
|
|
4
4
|
'use strict';
|
|
5
5
|
|
|
6
|
+
/** @typedef {import('../wingbot/CustomEntityDetectionModel').EntityDetector} EntityDetector */
|
|
7
|
+
/** @typedef {import('../wingbot/CustomEntityDetectionModel').DetectorOptions} DetectorOptions */
|
|
8
|
+
|
|
9
|
+
/** @type {[string,EntityDetector|RegExp,DetectorOptions]} */
|
|
6
10
|
module.exports = ['email', /(?<=(\s|^|:))[a-zA-Z0-9!#$%&'*+\-=?^_`{|}~"][^@:\s]*@[^.@\s]+\.[^@\s,]+/, {
|
|
7
|
-
anonymize: true
|
|
11
|
+
anonymize: true,
|
|
12
|
+
clearOverlaps: true
|
|
8
13
|
}];
|
|
@@ -3,11 +3,16 @@
|
|
|
3
3
|
*/
|
|
4
4
|
'use strict';
|
|
5
5
|
|
|
6
|
+
/** @typedef {import('../wingbot/CustomEntityDetectionModel').EntityDetector} EntityDetector */
|
|
7
|
+
/** @typedef {import('../wingbot/CustomEntityDetectionModel').DetectorOptions} DetectorOptions */
|
|
8
|
+
|
|
9
|
+
/** @type {[string,EntityDetector|RegExp,DetectorOptions]} */
|
|
6
10
|
module.exports = [
|
|
7
11
|
'phone',
|
|
8
12
|
/((00|\+)[\s-]?[0-9]{1,4}[\s-]?)?([0-9]{3,4}[\s-]?([0-9]{2,3}[\s-]?[0-9]{2}[\s-]?[0-9]{2,3}|[0-9]{3,4}[\s-]?[0-9]{3,4}))(?=(\s|$|[,!.?\-:]))/,
|
|
9
13
|
{
|
|
10
14
|
anonymize: true,
|
|
15
|
+
clearOverlaps: true,
|
|
11
16
|
extractValue: (match) => {
|
|
12
17
|
let [, internat,, number] = match;
|
|
13
18
|
|
|
@@ -35,7 +35,7 @@ class CachedModel extends CustomEntityDetectionModel {
|
|
|
35
35
|
* @param {object} options
|
|
36
36
|
* @param {number} [options.cacheSize]
|
|
37
37
|
* @param {number} [options.cachePhrasesTime]
|
|
38
|
-
* @param {{ warn: Function, error: Function }} [log]
|
|
38
|
+
* @param {{ warn: Function, error: Function, log: Function }} [log]
|
|
39
39
|
*/
|
|
40
40
|
constructor (options, log = console) {
|
|
41
41
|
super(options, log);
|
|
@@ -88,11 +88,19 @@ class CachedModel extends CustomEntityDetectionModel {
|
|
|
88
88
|
const res = await promise;
|
|
89
89
|
let { intents = [], entities = [] } = Array.isArray(res) ? { intents: res } : res;
|
|
90
90
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
91
|
+
const expectedEntities = req ? req.expectedEntities() : [];
|
|
92
|
+
|
|
93
|
+
const before = local.entities
|
|
94
|
+
.filter((e) => this._entityDetectors.has(e.entity)
|
|
95
|
+
&& this._entityDetectors.get(e.entity).clearOverlaps);
|
|
96
|
+
|
|
97
|
+
[intents, entities] = this._attachEntities(intents, entities, before, expectedEntities);
|
|
98
|
+
|
|
99
|
+
const after = local.entities
|
|
100
|
+
.filter((e) => !this._entityDetectors.has(e.entity)
|
|
101
|
+
|| !this._entityDetectors.get(e.entity).clearOverlaps);
|
|
102
|
+
|
|
103
|
+
[intents, entities] = this._attachEntities(intents, entities, after);
|
|
96
104
|
|
|
97
105
|
return {
|
|
98
106
|
text: local.text,
|
|
@@ -101,6 +109,26 @@ class CachedModel extends CustomEntityDetectionModel {
|
|
|
101
109
|
};
|
|
102
110
|
}
|
|
103
111
|
|
|
112
|
+
_attachEntities (intents, entities, attachEntities, expectedEntities = null) {
|
|
113
|
+
const retEntities = [...entities, ...attachEntities];
|
|
114
|
+
const retIntents = intents
|
|
115
|
+
.map((i) => {
|
|
116
|
+
const ents = [...(i.entities || []), ...attachEntities];
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
...i,
|
|
120
|
+
entities: expectedEntities
|
|
121
|
+
? this.nonOverlapping(ents, expectedEntities)
|
|
122
|
+
: ents
|
|
123
|
+
};
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
return [
|
|
127
|
+
retIntents,
|
|
128
|
+
expectedEntities ? this.nonOverlapping(retEntities, expectedEntities) : retEntities
|
|
129
|
+
];
|
|
130
|
+
}
|
|
131
|
+
|
|
104
132
|
async getPhrases () {
|
|
105
133
|
if (this._phrasesCachedAt > (Date.now() - this.phrasesCacheTime)) {
|
|
106
134
|
return this._phrasesCache;
|
|
@@ -51,6 +51,16 @@ const { replaceDiacritics } = require('../utils');
|
|
|
51
51
|
* @prop {Intent[]} intents
|
|
52
52
|
*/
|
|
53
53
|
|
|
54
|
+
/**
|
|
55
|
+
* @typedef {object} DetectorOptions
|
|
56
|
+
* @prop {boolean} [anonymize] - if true, value will not be sent to NLP
|
|
57
|
+
* @prop {Function|string} [extractValue] - entity extractor
|
|
58
|
+
* @prop {boolean} [matchWholeWords] - match whole words at regular expression
|
|
59
|
+
* @prop {boolean} [replaceDiacritics] - keep diacritics when matching regexp
|
|
60
|
+
* @prop {string[]} [dependencies] - array of dependent entities
|
|
61
|
+
* @prop {boolean} [clearOverlaps] - let longer entities from NLP to replace entity
|
|
62
|
+
*/
|
|
63
|
+
|
|
54
64
|
/**
|
|
55
65
|
* @typedef {object} Phrases
|
|
56
66
|
* @prop {Map<string,string[]>} phrases
|
|
@@ -70,7 +80,7 @@ class CustomEntityDetectionModel {
|
|
|
70
80
|
|
|
71
81
|
/**
|
|
72
82
|
* @param {object} options
|
|
73
|
-
* @param {{ warn: Function, error: Function }} [log]
|
|
83
|
+
* @param {{ warn: Function, error: Function, log: Function }} [log]
|
|
74
84
|
*/
|
|
75
85
|
constructor (options, log = console) {
|
|
76
86
|
this._options = options;
|
|
@@ -582,12 +592,7 @@ class CustomEntityDetectionModel {
|
|
|
582
592
|
*
|
|
583
593
|
* @param {string} name
|
|
584
594
|
* @param {EntityDetector|RegExp} detector
|
|
585
|
-
* @param {
|
|
586
|
-
* @param {boolean} [options.anonymize] - if true, value will not be sent to NLP
|
|
587
|
-
* @param {Function|string} [options.extractValue] - entity extractor
|
|
588
|
-
* @param {boolean} [options.matchWholeWords] - match whole words at regular expression
|
|
589
|
-
* @param {boolean} [options.replaceDiacritics] - keep diacritics when matching regexp
|
|
590
|
-
* @param {string[]} [options.dependencies] - array of dependent entities
|
|
595
|
+
* @param {DetectorOptions} [options]
|
|
591
596
|
* @returns {this}
|
|
592
597
|
*/
|
|
593
598
|
setEntityDetector (name, detector, options = {}) {
|
|
@@ -610,7 +615,8 @@ class CustomEntityDetectionModel {
|
|
|
610
615
|
entityDetector,
|
|
611
616
|
detector,
|
|
612
617
|
dependencies,
|
|
613
|
-
anonymize: !!options.anonymize
|
|
618
|
+
anonymize: !!options.anonymize,
|
|
619
|
+
clearOverlaps: !!options.clearOverlaps
|
|
614
620
|
});
|
|
615
621
|
|
|
616
622
|
return this;
|
|
@@ -623,6 +629,7 @@ class CustomEntityDetectionModel {
|
|
|
623
629
|
* @param {string} name
|
|
624
630
|
* @param {object} options
|
|
625
631
|
* @param {boolean} [options.anonymize]
|
|
632
|
+
* @param {boolean} [options.clearOverlaps]
|
|
626
633
|
* @returns {this}
|
|
627
634
|
* @example
|
|
628
635
|
*
|
|
@@ -632,7 +639,7 @@ class CustomEntityDetectionModel {
|
|
|
632
639
|
*/
|
|
633
640
|
setDetectorOptions (name, options) {
|
|
634
641
|
if (!this._entityDetectors.has(name)) {
|
|
635
|
-
throw new Error(
|
|
642
|
+
throw new Error(`Can't set entity detector options. Entity "${name}" does not exist.`);
|
|
636
643
|
}
|
|
637
644
|
Object.assign(this._entityDetectors.get(name), options);
|
|
638
645
|
return this;
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
const { default: fetch } = require('node-fetch');
|
|
4
4
|
const assert = require('assert');
|
|
5
5
|
const CachedModel = require('./CachedModel');
|
|
6
|
-
const systemEntities = require('../systemEntities');
|
|
7
6
|
|
|
8
7
|
const DEFAULT_MATCHES = 3;
|
|
9
8
|
const SERVICE_URL = 'https://model.wingbot.ai';
|
|
@@ -42,7 +41,7 @@ class WingbotModel extends CachedModel {
|
|
|
42
41
|
* @param {number} [options.cacheSize]
|
|
43
42
|
* @param {number} [options.matches]
|
|
44
43
|
* @param {Function} [options.fetch]
|
|
45
|
-
* @param {{ warn: Function, log: Function }} [log]
|
|
44
|
+
* @param {{ warn: Function, log: Function, error: Function }} [log]
|
|
46
45
|
*/
|
|
47
46
|
constructor (options, log = console) {
|
|
48
47
|
super(options, log);
|
|
@@ -60,11 +59,6 @@ class WingbotModel extends CachedModel {
|
|
|
60
59
|
this._serviceUrl = options.serviceUrl || SERVICE_URL;
|
|
61
60
|
this._trainingUrl = options.trainingUrl || TRAINING_URL;
|
|
62
61
|
this._model = options.model;
|
|
63
|
-
|
|
64
|
-
// apply default entities
|
|
65
|
-
systemEntities
|
|
66
|
-
// @ts-ignore
|
|
67
|
-
.forEach(([name, d, opts = {}]) => this.setEntityDetector(name, d, opts));
|
|
68
62
|
}
|
|
69
63
|
|
|
70
64
|
async _getPhrases () {
|