wingbot 3.26.0 → 3.27.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/AiMatching.js +15 -3
- package/src/Processor.js +12 -9
- package/src/wingbot/CustomEntityDetectionModel.js +92 -14
package/package.json
CHANGED
package/src/AiMatching.js
CHANGED
|
@@ -403,13 +403,25 @@ class AiMatching {
|
|
|
403
403
|
score: regexpScore - handicap
|
|
404
404
|
};
|
|
405
405
|
}
|
|
406
|
+
|
|
407
|
+
let useState;
|
|
408
|
+
if (stateless || intents.length === 0) {
|
|
409
|
+
useState = Object.entries(req.state)
|
|
410
|
+
.reduce((o, [k, v]) => {
|
|
411
|
+
if (k.startsWith('@')) {
|
|
412
|
+
return o;
|
|
413
|
+
}
|
|
414
|
+
return Object.assign(o, { [k]: v });
|
|
415
|
+
}, {});
|
|
416
|
+
} else {
|
|
417
|
+
useState = req.state;
|
|
418
|
+
}
|
|
419
|
+
|
|
406
420
|
const { score, handicap, matched } = this
|
|
407
421
|
._entityMatching(
|
|
408
422
|
entities,
|
|
409
423
|
reqEntities,
|
|
410
|
-
|
|
411
|
-
? {}
|
|
412
|
-
: req.state
|
|
424
|
+
useState
|
|
413
425
|
);
|
|
414
426
|
|
|
415
427
|
const allOptional = entities.every((e) => e.optional);
|
package/src/Processor.js
CHANGED
|
@@ -179,7 +179,7 @@ class Processor extends EventEmitter {
|
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
-
_createPostBack (postbackAcumulator, req, res) {
|
|
182
|
+
_createPostBack (postbackAcumulator, req, res, features) {
|
|
183
183
|
const postBack = (action, inputData = {}, dontWaitTillEndOfLoop = false) => {
|
|
184
184
|
let data = inputData;
|
|
185
185
|
if (typeof data === 'function') {
|
|
@@ -214,11 +214,12 @@ class Processor extends EventEmitter {
|
|
|
214
214
|
postbackAcumulator.push(data
|
|
215
215
|
.then((result) => ({
|
|
216
216
|
action,
|
|
217
|
-
data: Object.assign(result || {}, { _localpostback: true })
|
|
217
|
+
data: Object.assign(result || {}, { _localpostback: true }),
|
|
218
|
+
features
|
|
218
219
|
})));
|
|
219
220
|
} else {
|
|
220
221
|
Object.assign(data, { _localpostback: true });
|
|
221
|
-
postbackAcumulator.push({ action, data });
|
|
222
|
+
postbackAcumulator.push({ action, data, features });
|
|
222
223
|
}
|
|
223
224
|
|
|
224
225
|
return Promise.resolve();
|
|
@@ -512,16 +513,17 @@ class Processor extends EventEmitter {
|
|
|
512
513
|
}
|
|
513
514
|
);
|
|
514
515
|
|
|
516
|
+
const features = [
|
|
517
|
+
...(this.options.features || []),
|
|
518
|
+
...req.features
|
|
519
|
+
];
|
|
515
520
|
const options = {
|
|
516
521
|
...this.options,
|
|
517
|
-
features
|
|
518
|
-
...(this.options.features || []),
|
|
519
|
-
...req.features
|
|
520
|
-
]
|
|
522
|
+
features
|
|
521
523
|
};
|
|
522
524
|
|
|
523
525
|
res = new Responder(senderId, messageSender, token, options, responderData);
|
|
524
|
-
const postBack = this._createPostBack(postbackAcumulator, req, res);
|
|
526
|
+
const postBack = this._createPostBack(postbackAcumulator, req, res, features);
|
|
525
527
|
|
|
526
528
|
let continueDispatching = true;
|
|
527
529
|
|
|
@@ -729,13 +731,14 @@ class Processor extends EventEmitter {
|
|
|
729
731
|
_processPostbacks (postbackAcumulator, senderId, pageId, messageSender, responderData) {
|
|
730
732
|
return postbackAcumulator.reduce((promise, postback) => promise
|
|
731
733
|
.then(() => postback)
|
|
732
|
-
.then(({ action, data = {} }) => {
|
|
734
|
+
.then(({ action, data = {}, features }) => {
|
|
733
735
|
let request;
|
|
734
736
|
if (typeof action === 'object') {
|
|
735
737
|
request = action;
|
|
736
738
|
} else {
|
|
737
739
|
request = Request.postBack(senderId, action, data);
|
|
738
740
|
}
|
|
741
|
+
Object.assign(request, { features });
|
|
739
742
|
return this._processMessage(request, pageId, messageSender, responderData);
|
|
740
743
|
}), Promise.resolve({}));
|
|
741
744
|
}
|
|
@@ -19,6 +19,7 @@ const { replaceDiacritics } = require('../utils');
|
|
|
19
19
|
* @callback EntityDetector
|
|
20
20
|
* @param {string} text - part of text
|
|
21
21
|
* @param {DetectedEntity[]} entities - dependent entities
|
|
22
|
+
* @param {boolean} [searchWithinWords] - optional ability to search within words
|
|
22
23
|
* @returns {DetectedEntity[]|DetectedEntity|Promise<DetectedEntity>|Promise<DetectedEntity[]>}
|
|
23
24
|
*/
|
|
24
25
|
|
|
@@ -154,19 +155,52 @@ class CustomEntityDetectionModel {
|
|
|
154
155
|
* @param {string} entity
|
|
155
156
|
* @param {string} text
|
|
156
157
|
* @param {DetectedEntity[]} entities
|
|
158
|
+
* @param {DetectedEntity[]} subWord
|
|
157
159
|
* @returns {Promise<DetectedEntity[]>}
|
|
158
160
|
*/
|
|
159
|
-
async
|
|
161
|
+
async _detectAllEntities (entity, text, entities, subWord) {
|
|
162
|
+
const [regularResults, subWordResults] = await Promise.all([
|
|
163
|
+
this._detectEntities(entity, text, entities, subWord, false),
|
|
164
|
+
this._detectEntities(entity, text, entities, subWord, true)
|
|
165
|
+
]);
|
|
166
|
+
|
|
167
|
+
const cleanSubWordResults = subWordResults
|
|
168
|
+
.filter((regular) => regularResults
|
|
169
|
+
.some((e) => e.start < regular.end && e.end > regular.start));
|
|
170
|
+
|
|
171
|
+
subWord.push(...cleanSubWordResults);
|
|
172
|
+
|
|
173
|
+
return regularResults;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
*
|
|
178
|
+
* @param {string} entity
|
|
179
|
+
* @param {string} text
|
|
180
|
+
* @param {DetectedEntity[]} entities
|
|
181
|
+
* @param {DetectedEntity[]} subWord
|
|
182
|
+
* @param {boolean} detectSubWords
|
|
183
|
+
* @returns {Promise<DetectedEntity[]>}
|
|
184
|
+
*/
|
|
185
|
+
async _detectEntities (entity, text, entities, subWord, detectSubWords) {
|
|
160
186
|
const { entityDetector, dependencies } = this._entityDetectors.get(entity);
|
|
161
187
|
|
|
188
|
+
if (detectSubWords && entityDetector.length < 3) {
|
|
189
|
+
return [];
|
|
190
|
+
}
|
|
191
|
+
|
|
162
192
|
const collected = [];
|
|
163
193
|
let o = 0;
|
|
164
194
|
let t = text;
|
|
165
195
|
try {
|
|
166
196
|
for (let i = 0; i < text.length; i++) {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
197
|
+
const dependentEntities = [
|
|
198
|
+
...subWord.filter((e) => dependencies.includes(`@${e.entity.toUpperCase()}`)),
|
|
199
|
+
...entities.filter((e) => dependencies.includes(`@${e.entity.toUpperCase()}`))
|
|
200
|
+
];
|
|
201
|
+
const res = await Promise.resolve(
|
|
202
|
+
entityDetector(t, dependentEntities, detectSubWords)
|
|
203
|
+
);
|
|
170
204
|
|
|
171
205
|
const resWasArray = Array.isArray(res);
|
|
172
206
|
const resArray = resWasArray ? res : [res];
|
|
@@ -194,8 +228,14 @@ class CustomEntityDetectionModel {
|
|
|
194
228
|
}
|
|
195
229
|
}
|
|
196
230
|
|
|
197
|
-
_escapeRegex (string) {
|
|
198
|
-
|
|
231
|
+
_escapeRegex (string, shouldReplaceDiacritics) {
|
|
232
|
+
const ret = string.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
|
|
233
|
+
|
|
234
|
+
if (!shouldReplaceDiacritics) {
|
|
235
|
+
return ret;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return replaceDiacritics(ret);
|
|
199
239
|
}
|
|
200
240
|
|
|
201
241
|
/**
|
|
@@ -279,16 +319,50 @@ class CustomEntityDetectionModel {
|
|
|
279
319
|
return res;
|
|
280
320
|
}
|
|
281
321
|
|
|
322
|
+
/**
|
|
323
|
+
*
|
|
324
|
+
* @param {boolean} [known]
|
|
325
|
+
* @returns {string[]} -
|
|
326
|
+
*/
|
|
327
|
+
getDependentEntities (known = null) {
|
|
328
|
+
const entities = new Set();
|
|
329
|
+
const knownEntities = new Map(
|
|
330
|
+
Array.from(this._entityDetectors.keys())
|
|
331
|
+
.map((key) => [key.toLowerCase(), key])
|
|
332
|
+
);
|
|
333
|
+
|
|
334
|
+
for (const { dependencies } of this._entityDetectors.values()) {
|
|
335
|
+
for (const entity of dependencies) {
|
|
336
|
+
const lowerCase = entity.replace(/^@/, '').toLowerCase();
|
|
337
|
+
const isKnown = knownEntities.has(lowerCase);
|
|
338
|
+
|
|
339
|
+
if (isKnown && known !== false) {
|
|
340
|
+
entities.add(knownEntities.get(lowerCase));
|
|
341
|
+
} else if (!isKnown && known !== true) {
|
|
342
|
+
entities.add(lowerCase);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return Array.from(entities.values());
|
|
348
|
+
}
|
|
349
|
+
|
|
282
350
|
/**
|
|
283
351
|
*
|
|
284
352
|
* @param {string} text
|
|
285
353
|
* @param {string} [singleEntity]
|
|
286
|
-
* @param {string[]}
|
|
354
|
+
* @param {string[]} [expected]
|
|
287
355
|
* @param {DetectedEntity[]} [entities] - previously detected entities to include
|
|
356
|
+
* @param {DetectedEntity[]} [subWord] - previously detected entities within words
|
|
288
357
|
* @returns {Promise<DetectedEntity[]>}
|
|
289
358
|
*/
|
|
290
|
-
async resolveEntities (text, singleEntity = null,
|
|
291
|
-
|
|
359
|
+
async resolveEntities (text, singleEntity = null, expected = [], entities = [], subWord = []) {
|
|
360
|
+
// mark unknown dependencies as resolved
|
|
361
|
+
const resolved = new Set(
|
|
362
|
+
this.getDependentEntities(false)
|
|
363
|
+
.map((entity) => resolved.add(`@${entity.toUpperCase()}`))
|
|
364
|
+
);
|
|
365
|
+
|
|
292
366
|
let missing = Array.from(this._entityDetectors.keys());
|
|
293
367
|
|
|
294
368
|
while (missing.length !== 0) {
|
|
@@ -315,7 +389,7 @@ class CustomEntityDetectionModel {
|
|
|
315
389
|
}
|
|
316
390
|
|
|
317
391
|
const results = await Promise.all(
|
|
318
|
-
detect.map((entity) => this.
|
|
392
|
+
detect.map((entity) => this._detectAllEntities(entity, text, entities, subWord))
|
|
319
393
|
);
|
|
320
394
|
|
|
321
395
|
detect.forEach((entity) => resolved.add(`@${entity.toUpperCase()}`));
|
|
@@ -323,7 +397,7 @@ class CustomEntityDetectionModel {
|
|
|
323
397
|
results.forEach((res) => entities.push(...res));
|
|
324
398
|
}
|
|
325
399
|
|
|
326
|
-
const clean = this.nonOverlapping(entities,
|
|
400
|
+
const clean = this.nonOverlapping(entities, expected);
|
|
327
401
|
|
|
328
402
|
if (!singleEntity) {
|
|
329
403
|
return clean;
|
|
@@ -415,8 +489,9 @@ class CustomEntityDetectionModel {
|
|
|
415
489
|
/**
|
|
416
490
|
* @param {string} text
|
|
417
491
|
* @param {DetectedEntity[]} entities
|
|
492
|
+
* @param {boolean} searchWithinWords
|
|
418
493
|
*/
|
|
419
|
-
return (text, entities) => {
|
|
494
|
+
return (text, entities, searchWithinWords) => {
|
|
420
495
|
if (typeof extractValue === 'string'
|
|
421
496
|
&& !this._entityByDependency(entities, extractValue)) {
|
|
422
497
|
|
|
@@ -426,15 +501,16 @@ class CustomEntityDetectionModel {
|
|
|
426
501
|
let replaced = source.replace(/@[A-Z0-9-]+/g, (value) => {
|
|
427
502
|
const matchingEntities = entities
|
|
428
503
|
.filter((e) => `@${e.entity.toUpperCase()}` === value)
|
|
429
|
-
.map((e) => this._escapeRegex(e.text));
|
|
504
|
+
.map((e) => this._escapeRegex(e.text, options.replaceDiacritics));
|
|
430
505
|
|
|
431
506
|
if (matchingEntities.length === 0) {
|
|
432
507
|
return value;
|
|
433
508
|
}
|
|
509
|
+
matchingEntities.sort((a, z) => z.length - a.length);
|
|
434
510
|
return `(${matchingEntities.join('|')})`;
|
|
435
511
|
});
|
|
436
512
|
|
|
437
|
-
if (options.matchWholeWords) {
|
|
513
|
+
if (options.matchWholeWords && !searchWithinWords) {
|
|
438
514
|
replaced = `(?<=(^|[^a-z0-9\u00C0-\u017F]))${replaced}(?=([^a-z0-9\u00C0-\u017F]|$))`;
|
|
439
515
|
}
|
|
440
516
|
|
|
@@ -446,6 +522,8 @@ class CustomEntityDetectionModel {
|
|
|
446
522
|
}
|
|
447
523
|
const match = matchText.match(r);
|
|
448
524
|
|
|
525
|
+
// console.log({ matchText, replaced, match: match && match[0], searchWithinWords });
|
|
526
|
+
|
|
449
527
|
if (!match) {
|
|
450
528
|
return null;
|
|
451
529
|
}
|