wingbot 3.35.0 → 3.36.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.35.0",
3
+ "version": "3.36.1",
4
4
  "description": "Enterprise Messaging Bot Conversation Engine",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -46,7 +46,7 @@
46
46
  "eslint-plugin-react": "^7.29.4",
47
47
  "graphql-markdown": "^6.0.0",
48
48
  "jsdoc-to-markdown": "^7.1.1",
49
- "mocha": "^9.2.2",
49
+ "mocha": "^10.0.0",
50
50
  "nyc": "^15.1.0",
51
51
  "rimraf": "^3.0.2",
52
52
  "sinon": "^13.0.1",
package/src/Ai.js CHANGED
@@ -40,6 +40,8 @@ let uq = 1;
40
40
 
41
41
  /** @typedef {import('./Request').IntentAction} IntentAction */
42
42
  /** @typedef {import('./Request')} Request */
43
+ /** @typedef {import('./Responder')} Responder */
44
+ /** @typedef {import('./wingbot/CachedModel').Result} Result */
43
45
  /** @typedef {import('./wingbot/CustomEntityDetectionModel').Phrases} Phrases */
44
46
 
45
47
  /**
@@ -203,6 +205,10 @@ class Ai {
203
205
  return model;
204
206
  }
205
207
 
208
+ get localEnhancement () {
209
+ return (1 - this.confidence) / 2;
210
+ }
211
+
206
212
  async processSetStateEntities (req, setState) {
207
213
  const keys = Object.keys(setState);
208
214
 
@@ -348,13 +354,13 @@ class Ai {
348
354
  const rules = this.matcher.preprocessRule(intent);
349
355
  const matcher = this._createIntentMatcher(rules, usedEntities);
350
356
 
351
- return async (req) => {
357
+ return async (req, res) => {
352
358
  if (!req.isTextOrIntent()) {
353
359
  return false;
354
360
  }
355
361
 
356
362
  if (!req.intents) {
357
- await this._loadIntents(req);
363
+ await this._loadIntents(req, res);
358
364
  }
359
365
 
360
366
  const winningIntent = matcher(req);
@@ -523,9 +529,10 @@ class Ai {
523
529
  /**
524
530
  *
525
531
  * @param {Request} req
532
+ * @param {Responder} [res]
526
533
  * @returns {Promise}
527
534
  */
528
- async preloadAi (req) {
535
+ async preloadAi (req, res = null) {
529
536
  if (req.supportsFeature(req.FEATURE_PHRASES)) {
530
537
  const model = this._getModelForRequest(req, false);
531
538
 
@@ -534,7 +541,7 @@ class Ai {
534
541
  .catch(() => {});
535
542
  }
536
543
  }
537
- return this._preloadIntent(req);
544
+ return this._preloadIntent(req, res);
538
545
  }
539
546
 
540
547
  /**
@@ -552,12 +559,43 @@ class Ai {
552
559
  return CustomEntityDetectionModel.getEmptyPhrasesObject();
553
560
  }
554
561
 
555
- async _preloadIntent (req) {
562
+ /**
563
+ *
564
+ * @param {Request} req
565
+ * @param {Responder} res
566
+ * @param {Result} result
567
+ * @returns {void}
568
+ */
569
+ _setResultToReqRes (req, res, result) {
570
+ const { text = null, intents, entities = [] } = result;
571
+ Object.assign(req, { intents, entities, _anonymizedText: text });
572
+
573
+ if (!res) {
574
+ return;
575
+ }
576
+
577
+ const entitiesObj = (entities || []).reduce((o, { entity, value }) => {
578
+ const list = o[entity] || [];
579
+ list.push(value);
580
+ return Object.assign(o, { [entity]: list });
581
+ }, {});
582
+
583
+ res.setData({
584
+ '@': entitiesObj
585
+ });
586
+ }
587
+
588
+ /**
589
+ *
590
+ * @param {Request} req
591
+ * @param {Responder} [res]
592
+ * @returns {Promise}
593
+ */
594
+ async _preloadIntent (req, res = null) {
556
595
  const mockIntent = this._getMockIntent(req);
557
596
 
558
597
  if (mockIntent) {
559
- req.intents = mockIntent.intents;
560
- req.entities = mockIntent.entities;
598
+ this._setResultToReqRes(req, res, mockIntent);
561
599
  return;
562
600
  }
563
601
 
@@ -571,15 +609,15 @@ class Ai {
571
609
  req.intents = [];
572
610
  return;
573
611
  }
574
- await this._loadIntents(req, model);
612
+ await this._loadIntents(req, res, model);
575
613
  } else {
576
614
  req.intents = [];
577
615
  }
578
616
  }
579
617
 
580
- async _loadIntents (req, model = null) {
581
- const { text = null, intents, entities = [] } = await this._queryModel(req, model);
582
- Object.assign(req, { intents, entities, _anonymizedText: text });
618
+ async _loadIntents (req, res = null, model = null) {
619
+ const result = await this._queryModel(req, model);
620
+ this._setResultToReqRes(req, res, result);
583
621
  }
584
622
 
585
623
  async _queryModel (req, useModel = null) {
package/src/AiMatching.js CHANGED
@@ -132,6 +132,12 @@ class AiMatching {
132
132
  * @type {number}
133
133
  */
134
134
  this.multiMatchGain = 1.2;
135
+
136
+ /**
137
+ * Score of a context entity within a conversation state
138
+ * (1 by default)
139
+ */
140
+ this.stateEntityScore = 1;
135
141
  }
136
142
 
137
143
  get redundantHandicap () {
@@ -480,6 +486,10 @@ class AiMatching {
480
486
  return winningIntent;
481
487
  }
482
488
 
489
+ _getMultiMatchGain (entitiesScore, matchedCount, fromState = 0) {
490
+ return (this.multiMatchGain * entitiesScore) ** (matchedCount - fromState);
491
+ }
492
+
483
493
  /**
484
494
  *
485
495
  * @private
@@ -505,7 +515,7 @@ class AiMatching {
505
515
  }
506
516
 
507
517
  const {
508
- score: entitiesScore, handicap, matched, minScore
518
+ score: entitiesScore, handicap, matched, minScore, fromState
509
519
  } = this
510
520
  ._entityMatching(
511
521
  wantedEntities,
@@ -516,13 +526,20 @@ class AiMatching {
516
526
  : (x) => x
517
527
  );
518
528
 
529
+ // console.log({ entitiesScore, handicap, matched, minScore, requestIntent })
530
+
519
531
  const allOptional = wantedEntities.every((e) => e.optional);
520
532
  if (entitiesScore === 0 && !allOptional) {
521
533
  return { score: 0, entities: [] };
522
534
  }
523
535
 
524
- const score = (Math.min(minScore + (handicap / 2), requestIntent.score) - handicap)
525
- * ((this.multiMatchGain * entitiesScore) ** matched.length);
536
+ const normalizedScore = Math.min(minScore + (handicap / 2), requestIntent.score);
537
+ const scoreWithHandicap = normalizedScore - handicap;
538
+ const multiMatchGain = this._getMultiMatchGain(entitiesScore, matched.length, fromState);
539
+
540
+ const score = scoreWithHandicap * multiMatchGain;
541
+
542
+ // console.log({ IMS: score, normalizedScore, scoreWithHandicap, multiMatchGain });
526
543
 
527
544
  return {
528
545
  score,
@@ -537,7 +554,7 @@ class AiMatching {
537
554
  * @param {Entity[]} requestEntities
538
555
  * @param {object} [requestState]
539
556
  * @param {Function} [scoreFn]
540
- * @returns {{score: number, handicap: number, matched: Entity[], minScore: number }}
557
+ * @returns {{score:number,handicap:number, matched:Entity[],minScore:number,fromState:number}}
541
558
  */
542
559
  _entityMatching (wantedEntities, requestEntities = [], requestState = {}, scoreFn = (x) => x) {
543
560
  const occurences = new Map();
@@ -546,6 +563,7 @@ class AiMatching {
546
563
  let handicap = 0;
547
564
  let sum = 0;
548
565
  let minScore = 1;
566
+ let fromState = 0;
549
567
 
550
568
  for (const wanted of wantedEntities) {
551
569
  const usedIndexes = occurences.has(wanted.entity)
@@ -579,9 +597,11 @@ class AiMatching {
579
597
  requestEntity = {
580
598
  value: requestState[`@${wanted.entity}`],
581
599
  entity: wanted.entity,
582
- score: 1
600
+ score: this.stateEntityScore
583
601
  };
584
602
 
603
+ fromState += 1;
604
+
585
605
  matching = this._entityIsMatching(
586
606
  wanted.op,
587
607
  wanted.compare,
@@ -596,7 +616,7 @@ class AiMatching {
596
616
 
597
617
  if (!matching && !wanted.optional) {
598
618
  return {
599
- score: 0, handicap: 0, matched: [], minScore
619
+ score: 0, handicap: 0, matched: [], minScore, fromState
600
620
  };
601
621
  }
602
622
 
@@ -636,11 +656,15 @@ class AiMatching {
636
656
  }
637
657
  }
638
658
 
639
- handicap += (requestEntities.length - matched.length) * this.redundantEntityHandicap;
659
+ // console.log({ sum, handicap, rl: requestEntities.length, ml: matched.length });
660
+
661
+ // @todo - neni mozne, by doslo k negativnimu handicapu
662
+ handicap += (requestEntities.length + fromState - matched.length)
663
+ * this.redundantEntityHandicap;
640
664
  const score = matched.length === 0 ? 0 : sum / matched.length;
641
665
 
642
666
  return {
643
- score, handicap, matched, minScore
667
+ score, handicap, matched, minScore, fromState
644
668
  };
645
669
  }
646
670
 
package/src/BotApp.js CHANGED
@@ -248,7 +248,7 @@ class BotApp {
248
248
  };
249
249
  }
250
250
 
251
- const sender = await this.createSender(senderId, pageId, message);
251
+ const sender = await this.createSender(senderId, pageId, message, secret, appId);
252
252
  const res = await this._processor.processMessage(message, pageId, sender, { appId });
253
253
  await this._processSenderResponses(sender, senderId, pageId, headers);
254
254
 
@@ -266,13 +266,15 @@ class BotApp {
266
266
  * @param {string} pageId
267
267
  * @param {object} [message]
268
268
  * @param {string|Promise<string>} [secret]
269
+ * @param {string} appId
269
270
  * @returns {Promise<BotAppSender>}
270
271
  */
271
272
  async createSender (
272
273
  senderId,
273
274
  pageId,
274
275
  message = defaultMsg(senderId, pageId),
275
- secret = this._secret
276
+ secret = this._secret,
277
+ appId = this._appId
276
278
  ) {
277
279
  const useSecret = await Promise.resolve(secret);
278
280
 
@@ -282,7 +284,7 @@ class BotApp {
282
284
  ...this._returnSenderOptions,
283
285
  apiUrl: this._apiUrl,
284
286
  pageId,
285
- appId: this._appId,
287
+ appId,
286
288
  secret: useSecret,
287
289
  mid: setResponseToMid,
288
290
  fetch: this._fetch,
package/src/Processor.js CHANGED
@@ -541,7 +541,7 @@ class Processor extends EventEmitter {
541
541
  }
542
542
  }
543
543
 
544
- await Ai.ai.preloadAi(req);
544
+ await Ai.ai.preloadAi(req, res);
545
545
 
546
546
  // @deprecated backward compatibility
547
547
  const aByAi = req.actionByAi();
package/src/Request.js CHANGED
@@ -1227,7 +1227,6 @@ class Request {
1227
1227
  // to match the local context intent
1228
1228
  const localRegexToMatch = this._getLocalPathRegexp();
1229
1229
 
1230
- const localEnhancement = (1 - Ai.ai.confidence) / 2;
1231
1230
  for (const gi of this.globalIntents.values()) {
1232
1231
  const pathMatches = localRegexToMatch && localRegexToMatch.exec(gi.action);
1233
1232
  if (gi.local && !pathMatches) {
@@ -1235,7 +1234,9 @@ class Request {
1235
1234
  }
1236
1235
  const intent = gi.matcher(this, null, true);
1237
1236
  if (intent !== null) {
1238
- const sort = intent.score + (pathMatches ? localEnhancement : 0);
1237
+ const sort = intent.score + (pathMatches
1238
+ ? Ai.ai.localEnhancement
1239
+ : 0);
1239
1240
  // console.log(sort, wi.intent);
1240
1241
  aiActions.push({
1241
1242
  ...gi,
@@ -3,8 +3,19 @@
3
3
  */
4
4
  'use strict';
5
5
 
6
+ /** @typedef {import('../Request')} Request */
7
+ /** @typedef {import('../Responder')} Responder */
8
+
9
+ /**
10
+ *
11
+ * @param {Request} req
12
+ * @param {Responder} res
13
+ * @param {object} configuration
14
+ * @returns {object}
15
+ */
6
16
  module.exports = function stateData (req, res = null, configuration = null) {
7
17
  const c = configuration || req.configuration;
18
+
8
19
  return {
9
20
  ...req.state,
10
21
  ...(res ? res.newState : {}),