wingbot 3.26.2 → 3.27.0-alpha.3
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 +1 -3
- package/src/Processor.js +12 -9
- package/src/wingbot/CustomEntityDetectionModel.js +85 -17
package/package.json
CHANGED
package/src/AiMatching.js
CHANGED
|
@@ -405,9 +405,7 @@ class AiMatching {
|
|
|
405
405
|
}
|
|
406
406
|
|
|
407
407
|
let useState;
|
|
408
|
-
if (stateless) {
|
|
409
|
-
useState = {};
|
|
410
|
-
} else if (intents.length === 0) {
|
|
408
|
+
if (stateless || intents.length === 0) {
|
|
411
409
|
useState = Object.entries(req.state)
|
|
412
410
|
.reduce((o, [k, v]) => {
|
|
413
411
|
if (k.startsWith('@')) {
|
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];
|
|
@@ -285,16 +319,50 @@ class CustomEntityDetectionModel {
|
|
|
285
319
|
return res;
|
|
286
320
|
}
|
|
287
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
|
+
|
|
288
350
|
/**
|
|
289
351
|
*
|
|
290
352
|
* @param {string} text
|
|
291
353
|
* @param {string} [singleEntity]
|
|
292
|
-
* @param {string[]}
|
|
354
|
+
* @param {string[]} [expected]
|
|
293
355
|
* @param {DetectedEntity[]} [entities] - previously detected entities to include
|
|
356
|
+
* @param {DetectedEntity[]} [subWord] - previously detected entities within words
|
|
294
357
|
* @returns {Promise<DetectedEntity[]>}
|
|
295
358
|
*/
|
|
296
|
-
async resolveEntities (text, singleEntity = null,
|
|
297
|
-
|
|
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) => `@${entity.toUpperCase()}`)
|
|
364
|
+
);
|
|
365
|
+
|
|
298
366
|
let missing = Array.from(this._entityDetectors.keys());
|
|
299
367
|
|
|
300
368
|
while (missing.length !== 0) {
|
|
@@ -321,7 +389,7 @@ class CustomEntityDetectionModel {
|
|
|
321
389
|
}
|
|
322
390
|
|
|
323
391
|
const results = await Promise.all(
|
|
324
|
-
detect.map((entity) => this.
|
|
392
|
+
detect.map((entity) => this._detectAllEntities(entity, text, entities, subWord))
|
|
325
393
|
);
|
|
326
394
|
|
|
327
395
|
detect.forEach((entity) => resolved.add(`@${entity.toUpperCase()}`));
|
|
@@ -329,7 +397,7 @@ class CustomEntityDetectionModel {
|
|
|
329
397
|
results.forEach((res) => entities.push(...res));
|
|
330
398
|
}
|
|
331
399
|
|
|
332
|
-
const clean = this.nonOverlapping(entities,
|
|
400
|
+
const clean = this.nonOverlapping(entities, expected);
|
|
333
401
|
|
|
334
402
|
if (!singleEntity) {
|
|
335
403
|
return clean;
|
|
@@ -421,8 +489,9 @@ class CustomEntityDetectionModel {
|
|
|
421
489
|
/**
|
|
422
490
|
* @param {string} text
|
|
423
491
|
* @param {DetectedEntity[]} entities
|
|
492
|
+
* @param {boolean} searchWithinWords
|
|
424
493
|
*/
|
|
425
|
-
return (text, entities) => {
|
|
494
|
+
return (text, entities, searchWithinWords) => {
|
|
426
495
|
if (typeof extractValue === 'string'
|
|
427
496
|
&& !this._entityByDependency(entities, extractValue)) {
|
|
428
497
|
|
|
@@ -437,10 +506,11 @@ class CustomEntityDetectionModel {
|
|
|
437
506
|
if (matchingEntities.length === 0) {
|
|
438
507
|
return value;
|
|
439
508
|
}
|
|
509
|
+
matchingEntities.sort((a, z) => z.length - a.length);
|
|
440
510
|
return `(${matchingEntities.join('|')})`;
|
|
441
511
|
});
|
|
442
512
|
|
|
443
|
-
if (options.matchWholeWords) {
|
|
513
|
+
if (options.matchWholeWords && !searchWithinWords) {
|
|
444
514
|
replaced = `(?<=(^|[^a-z0-9\u00C0-\u017F]))${replaced}(?=([^a-z0-9\u00C0-\u017F]|$))`;
|
|
445
515
|
}
|
|
446
516
|
|
|
@@ -452,6 +522,8 @@ class CustomEntityDetectionModel {
|
|
|
452
522
|
}
|
|
453
523
|
const match = matchText.match(r);
|
|
454
524
|
|
|
525
|
+
// console.log({ matchText, replaced, match: match && match[0], searchWithinWords });
|
|
526
|
+
|
|
455
527
|
if (!match) {
|
|
456
528
|
return null;
|
|
457
529
|
}
|
|
@@ -467,19 +539,15 @@ class CustomEntityDetectionModel {
|
|
|
467
539
|
|
|
468
540
|
if (typeof extractValue === 'function') {
|
|
469
541
|
value = extractValue(match, useEntities);
|
|
470
|
-
} else if (typeof extractValue === 'string' || dependencies.length
|
|
542
|
+
} else if (typeof extractValue === 'string' || dependencies.length > 0) {
|
|
471
543
|
const entityName = typeof extractValue === 'string'
|
|
472
544
|
? extractValue
|
|
473
545
|
: dependencies[0];
|
|
474
546
|
|
|
475
547
|
const entity = this._entityByDependency(useEntities, entityName);
|
|
476
548
|
value = entity ? entity.value : null;
|
|
477
|
-
} else if (entities.length === 0) {
|
|
478
|
-
[value] = match;
|
|
479
549
|
} else {
|
|
480
|
-
value =
|
|
481
|
-
[e.entity]: e.value
|
|
482
|
-
}), {});
|
|
550
|
+
[value] = match;
|
|
483
551
|
}
|
|
484
552
|
|
|
485
553
|
return {
|