wingbot 3.26.3 → 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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wingbot",
3
- "version": "3.26.3",
3
+ "version": "3.27.0-alpha.1",
4
4
  "description": "Enterprise Messaging Bot Conversation Engine",
5
5
  "main": "index.js",
6
6
  "scripts": {
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 _detectEntities (entity, text, entities) {
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
- const dependentEntities = entities.filter((e) => dependencies.includes(`@${e.entity.toUpperCase()}`));
169
- const res = await Promise.resolve(entityDetector(t, dependentEntities));
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[]} expectedEntities
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, expectedEntities = [], entities = []) {
297
- const resolved = new Set();
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
+
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._detectEntities(entity, text, entities))
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, expectedEntities);
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
  }