botium-core 1.13.7 → 1.13.9
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/dist/botium-cjs.js +214 -1497
- package/dist/botium-cjs.js.map +1 -1
- package/dist/botium-es.js +214 -1497
- package/dist/botium-es.js.map +1 -1
- package/package.json +24 -24
- package/src/scripting/Convo.js +42 -15
- package/src/scripting/MatchFunctions.js +3 -4
- package/src/scripting/ScriptingProvider.js +11 -15
- package/src/scripting/helper.js +61 -2
- package/src/scripting/logichook/asserter/JsonPathAsserter.js +7 -3
- package/src/scripting/logichook/asserter/WerAsserter.js +3 -2
- package/src/scripting/logichook/logichooks/SetScriptingMemoryLogicHook.js +1 -1
- package/test/convo/convos/applyscriptingmemoryinbegin.convo.txt +14 -0
- package/test/convo/fillAndApplyScriptingMemory.spec.js +20 -0
- package/test/scripting/asserters/convos/wer_threshold_wildcard_nok_float.yml +7 -0
- package/test/scripting/asserters/convos/wer_threshold_wildcard_nok_percentage.yml +7 -0
- package/test/scripting/asserters/convos/wer_threshold_wildcard_ok_float.yml +7 -0
- package/test/scripting/asserters/convos/wer_threshold_wildcard_ok_percentage.yml +7 -0
- package/test/scripting/asserters/jsonpathAsserter.spec.js +90 -3
- package/test/scripting/asserters/werAsserter.spec.js +41 -0
- package/test/scripting/matching/matchingmode.spec.js +82 -0
- package/test/scripting/scriptingModificator.spec.js +2 -0
- package/test/scripting/scriptingmemory/convosPartial/buy.convo.txt +7 -0
- package/test/scripting/scriptingmemory/convosPartial/product.scriptingmemory.txt +2 -0
- package/test/scripting/scriptingmemory/convosPartial/sub1.pconvo.txt +7 -0
- package/test/scripting/scriptingmemory/convosPartial/sub2.pconvo.txt +7 -0
- package/test/scripting/scriptingmemory/fillScriptingMemoryFromFile.spec.js +10 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "botium-core",
|
|
3
|
-
"version": "1.13.
|
|
3
|
+
"version": "1.13.9",
|
|
4
4
|
"description": "The Selenium for Chatbots",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"module": "dist/botium-es.js",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"test": "cross-env NODE_PATH=\"./test/plugins/plugindir/fromfolder:./test/plugins/plugindir/fromfile:./test/security/resources\" mocha \"./test/**/*.spec.js\"",
|
|
20
20
|
"coverage:report": "nyc report --reporter=lcov npm test",
|
|
21
21
|
"license-checker": "license-checker > LICENSES-3RDPARTY.txt",
|
|
22
|
-
"update-dependencies": "npm-check-updates --reject globby -u --timeout 120000"
|
|
22
|
+
"update-dependencies": "npm-check-updates --reject globby,rollup -u --timeout 120000"
|
|
23
23
|
},
|
|
24
24
|
"repository": {
|
|
25
25
|
"type": "git",
|
|
@@ -32,17 +32,17 @@
|
|
|
32
32
|
},
|
|
33
33
|
"homepage": "https://www.botium.ai",
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@babel/runtime": "^7.
|
|
35
|
+
"@babel/runtime": "^7.20.6",
|
|
36
36
|
"async": "^3.2.4",
|
|
37
|
-
"body-parser": "^1.20.
|
|
37
|
+
"body-parser": "^1.20.1",
|
|
38
38
|
"boolean": "^3.2.0",
|
|
39
39
|
"bottleneck": "^2.19.5",
|
|
40
|
-
"csv-parse": "^5.3.
|
|
40
|
+
"csv-parse": "^5.3.3",
|
|
41
41
|
"debug": "^4.3.4",
|
|
42
42
|
"esprima": "^4.0.1",
|
|
43
|
-
"express": "^4.18.
|
|
43
|
+
"express": "^4.18.2",
|
|
44
44
|
"globby": "11.0.4",
|
|
45
|
-
"ioredis": "^5.2.
|
|
45
|
+
"ioredis": "^5.2.4",
|
|
46
46
|
"is-class": "^0.0.9",
|
|
47
47
|
"is-json": "^2.0.1",
|
|
48
48
|
"jsonpath": "^1.1.1",
|
|
@@ -53,47 +53,47 @@
|
|
|
53
53
|
"moment": "^2.29.4",
|
|
54
54
|
"mustache": "^4.2.0",
|
|
55
55
|
"promise-retry": "^2.0.1",
|
|
56
|
-
"promise.allsettled": "^1.0.
|
|
56
|
+
"promise.allsettled": "^1.0.6",
|
|
57
57
|
"randomatic": "^3.1.1",
|
|
58
58
|
"request": "^2.88.2",
|
|
59
59
|
"rimraf": "^3.0.2",
|
|
60
60
|
"sanitize-filename": "^1.6.3",
|
|
61
61
|
"slugify": "^1.6.5",
|
|
62
|
-
"socket.io": "^4.5.
|
|
63
|
-
"socket.io-client": "^4.5.
|
|
62
|
+
"socket.io": "^4.5.4",
|
|
63
|
+
"socket.io-client": "^4.5.4",
|
|
64
64
|
"socketio-auth": "^0.1.1",
|
|
65
65
|
"swagger-jsdoc": "^6.2.5",
|
|
66
|
-
"swagger-ui-express": "^4.
|
|
66
|
+
"swagger-ui-express": "^4.6.0",
|
|
67
67
|
"uuid": "^9.0.0",
|
|
68
|
-
"vm2": "^3.9.
|
|
68
|
+
"vm2": "^3.9.13",
|
|
69
69
|
"word-error-rate": "0.0.7",
|
|
70
70
|
"write-yaml": "^1.0.0",
|
|
71
71
|
"xlsx": "^0.18.5",
|
|
72
72
|
"xregexp": "^5.1.1",
|
|
73
|
-
"yaml": "^2.1.
|
|
73
|
+
"yaml": "^2.1.3"
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|
|
76
|
-
"@babel/core": "^7.
|
|
77
|
-
"@babel/node": "^7.
|
|
78
|
-
"@babel/plugin-transform-runtime": "^7.19.
|
|
79
|
-
"@babel/preset-env": "^7.
|
|
80
|
-
"chai": "^4.3.
|
|
76
|
+
"@babel/core": "^7.20.5",
|
|
77
|
+
"@babel/node": "^7.20.5",
|
|
78
|
+
"@babel/plugin-transform-runtime": "^7.19.6",
|
|
79
|
+
"@babel/preset-env": "^7.20.2",
|
|
80
|
+
"chai": "^4.3.7",
|
|
81
81
|
"chai-as-promised": "^7.1.1",
|
|
82
82
|
"cross-env": "^7.0.3",
|
|
83
|
-
"eslint": "^8.
|
|
83
|
+
"eslint": "^8.29.0",
|
|
84
84
|
"eslint-config-standard": "^17.0.0",
|
|
85
85
|
"eslint-plugin-import": "^2.26.0",
|
|
86
86
|
"eslint-plugin-mocha": "^10.1.0",
|
|
87
|
-
"eslint-plugin-n": "^15.
|
|
88
|
-
"eslint-plugin-promise": "^6.
|
|
87
|
+
"eslint-plugin-n": "^15.6.0",
|
|
88
|
+
"eslint-plugin-promise": "^6.1.1",
|
|
89
89
|
"eslint-plugin-standard": "^4.1.0",
|
|
90
90
|
"license-checker": "^25.0.1",
|
|
91
91
|
"license-compatibility-checker": "^0.3.5",
|
|
92
|
-
"mocha": "^10.
|
|
92
|
+
"mocha": "^10.2.0",
|
|
93
93
|
"nock": "^13.2.9",
|
|
94
|
-
"npm-check-updates": "^16.
|
|
94
|
+
"npm-check-updates": "^16.5.6",
|
|
95
95
|
"nyc": "^15.1.0",
|
|
96
|
-
"rollup": "
|
|
96
|
+
"rollup": "2.79.1",
|
|
97
97
|
"rollup-plugin-babel": "^4.4.0",
|
|
98
98
|
"rollup-plugin-commonjs": "^10.1.0",
|
|
99
99
|
"rollup-plugin-json": "^4.0.0",
|
package/src/scripting/Convo.js
CHANGED
|
@@ -591,26 +591,53 @@ class Convo {
|
|
|
591
591
|
}
|
|
592
592
|
|
|
593
593
|
GetScriptingMemoryAllVariables (container) {
|
|
594
|
-
const
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
594
|
+
const partialConvos = this.context.GetPartialConvos()
|
|
595
|
+
|
|
596
|
+
const variableNames = this.conversation.reduce((acc, convoStep) => {
|
|
597
|
+
if (convoStep.sender === 'include') {
|
|
598
|
+
if (convoStep.channel) {
|
|
599
|
+
const partialConvo = partialConvos[convoStep.channel]
|
|
600
|
+
if (partialConvo) {
|
|
601
|
+
acc = [...acc, ...partialConvo.GetScriptingMemoryAllVariables(container)]
|
|
602
602
|
}
|
|
603
603
|
}
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
604
|
+
if (convoStep.messageText) {
|
|
605
|
+
for (const partialConvoName of splitStringInNonEmptyLines(convoStep.messageText)) {
|
|
606
|
+
const partialConvo = partialConvos[partialConvoName]
|
|
607
|
+
if (partialConvo) {
|
|
608
|
+
acc = [...acc, ...partialConvo.GetScriptingMemoryAllVariables(container)]
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
} else {
|
|
613
|
+
acc = [...acc, ...this.GetScriptingMemoryVariables(container, convoStep.messageText)]
|
|
609
614
|
|
|
610
|
-
|
|
615
|
+
const __extractFromArgs = (convoStepItems) => {
|
|
616
|
+
let resultInner = []
|
|
617
|
+
for (const item of (convoStepItems || [])) {
|
|
618
|
+
for (const arg of (item.args || [])) {
|
|
619
|
+
resultInner = resultInner.concat(this.GetScriptingMemoryVariables(container, arg))
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
return resultInner
|
|
623
|
+
}
|
|
624
|
+
acc = [...acc, ...__extractFromArgs(convoStep.asserters)]
|
|
625
|
+
acc = [...acc, ...__extractFromArgs(convoStep.logicHooks)]
|
|
626
|
+
acc = [...acc, ...__extractFromArgs(convoStep.userInputs)]
|
|
627
|
+
|
|
628
|
+
convoStep.logicHooks.forEach((logicHook) => {
|
|
629
|
+
if (logicHook.name === LOGIC_HOOK_INCLUDE) {
|
|
630
|
+
const partialConvo = partialConvos[logicHook.args[0]]
|
|
631
|
+
if (partialConvo) {
|
|
632
|
+
acc = [...acc, ...partialConvo.GetScriptingMemoryAllVariables(container)]
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
})
|
|
636
|
+
}
|
|
637
|
+
return acc
|
|
611
638
|
}, [])
|
|
612
639
|
|
|
613
|
-
return
|
|
640
|
+
return _.uniq(variableNames)
|
|
614
641
|
}
|
|
615
642
|
|
|
616
643
|
GetScriptingMemoryVariables (container, utterance) {
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
const _ = require('lodash')
|
|
2
|
-
const speechScorer = require('word-error-rate')
|
|
3
2
|
|
|
4
|
-
const { toString, quoteRegexpString } = require('./helper')
|
|
3
|
+
const { toString, quoteRegexpString, calculateWer } = require('./helper')
|
|
5
4
|
|
|
6
5
|
const _normalize = (botresponse) => {
|
|
7
|
-
if (_.isUndefined(botresponse)) return ''
|
|
6
|
+
if (_.isUndefined(botresponse) || _.isNil(botresponse)) return ''
|
|
8
7
|
if (_.isObject(botresponse) && _.has(botresponse, 'messageText')) {
|
|
9
8
|
return toString(botresponse.messageText) || ''
|
|
10
9
|
}
|
|
@@ -85,7 +84,7 @@ const wer = () => (botresponse, utterance, args) => {
|
|
|
85
84
|
utterance = toString(utterance || '')
|
|
86
85
|
|
|
87
86
|
const threshold = ([',', '.'].find(p => `${args[0]}`.includes(p)) ? parseFloat(args[0]) : parseInt(args[0]) / 100)
|
|
88
|
-
return
|
|
87
|
+
return calculateWer(botresponse, utterance) <= threshold
|
|
89
88
|
}
|
|
90
89
|
|
|
91
90
|
const getMatchFunction = (matchingMode) => {
|
|
@@ -209,7 +209,7 @@ module.exports = class ScriptingProvider {
|
|
|
209
209
|
this.retryHelperUserInput = new RetryHelper(this.caps, 'USERINPUT')
|
|
210
210
|
}
|
|
211
211
|
|
|
212
|
-
_createAsserterPromises ({ asserterType, asserters, convo, convoStep, scriptingMemory, ...rest }) {
|
|
212
|
+
_createAsserterPromises ({ asserterType, asserters, convo, convoStep, scriptingMemory, container, ...rest }) {
|
|
213
213
|
if (!this._isValidAsserterType(asserterType)) {
|
|
214
214
|
throw Error(`Unknown asserterType ${asserterType}`)
|
|
215
215
|
}
|
|
@@ -254,7 +254,8 @@ module.exports = class ScriptingProvider {
|
|
|
254
254
|
convo,
|
|
255
255
|
convoStep,
|
|
256
256
|
scriptingMemory,
|
|
257
|
-
|
|
257
|
+
container,
|
|
258
|
+
args: ScriptingMemory.applyToArgs(a.args, scriptingMemory, container.caps, rest.botMsg),
|
|
258
259
|
isGlobal: false,
|
|
259
260
|
...rest
|
|
260
261
|
}))
|
|
@@ -276,7 +277,7 @@ module.exports = class ScriptingProvider {
|
|
|
276
277
|
return Promise.resolve(false)
|
|
277
278
|
}
|
|
278
279
|
|
|
279
|
-
_createLogicHookPromises ({ hookType, logicHooks, convo, convoStep, scriptingMemory, ...rest }) {
|
|
280
|
+
_createLogicHookPromises ({ hookType, logicHooks, convo, convoStep, scriptingMemory, container, ...rest }) {
|
|
280
281
|
if (hookType !== 'onMeStart' && hookType !== 'onMePrepare' && hookType !== 'onMeEnd' && hookType !== 'onBotStart' && hookType !== 'onBotPrepare' && hookType !== 'onBotEnd' &&
|
|
281
282
|
hookType !== 'onConvoBegin' && hookType !== 'onConvoEnd'
|
|
282
283
|
) {
|
|
@@ -289,7 +290,8 @@ module.exports = class ScriptingProvider {
|
|
|
289
290
|
convo,
|
|
290
291
|
convoStep,
|
|
291
292
|
scriptingMemory,
|
|
292
|
-
|
|
293
|
+
container,
|
|
294
|
+
args: ScriptingMemory.applyToArgs(l.args, scriptingMemory, container.caps, rest.botMsg),
|
|
293
295
|
isGlobal: false,
|
|
294
296
|
...rest
|
|
295
297
|
})))
|
|
@@ -303,14 +305,15 @@ module.exports = class ScriptingProvider {
|
|
|
303
305
|
return Promise.resolve(false)
|
|
304
306
|
}
|
|
305
307
|
|
|
306
|
-
_createUserInputPromises ({ convo, convoStep, scriptingMemory, ...rest }) {
|
|
308
|
+
_createUserInputPromises ({ convo, convoStep, scriptingMemory, container, ...rest }) {
|
|
307
309
|
const convoStepPromises = (convoStep.userInputs || [])
|
|
308
310
|
.filter(ui => this.userInputs[ui.name])
|
|
309
311
|
.map(ui => p(this.retryHelperUserInput, () => this.userInputs[ui.name].setUserInput({
|
|
310
312
|
convo,
|
|
311
313
|
convoStep,
|
|
312
314
|
scriptingMemory,
|
|
313
|
-
|
|
315
|
+
container,
|
|
316
|
+
args: ScriptingMemory.applyToArgs(ui.args, scriptingMemory, container.caps, rest.meMsg),
|
|
314
317
|
...rest
|
|
315
318
|
})))
|
|
316
319
|
|
|
@@ -885,12 +888,11 @@ module.exports = class ScriptingProvider {
|
|
|
885
888
|
// drop unwanted convos
|
|
886
889
|
convoFilter: null
|
|
887
890
|
}, options)
|
|
888
|
-
const context = { count: 0 }
|
|
889
891
|
const expandedConvos = []
|
|
890
892
|
debug(`ExpandConvos - Using utterances expansion mode: ${this.caps[Capabilities.SCRIPTING_UTTEXPANSION_MODE]}`)
|
|
891
893
|
this.convos.forEach((convo) => {
|
|
892
894
|
convo.expandPartialConvos()
|
|
893
|
-
for (const expanded of this._expandConvo(convo, options,
|
|
895
|
+
for (const expanded of this._expandConvo(convo, options, {})) {
|
|
894
896
|
expanded.header.assertionCount = this.GetAssertionCount(expanded)
|
|
895
897
|
if (options.justHeader) {
|
|
896
898
|
const ConvoWithOnlyHeader = {
|
|
@@ -922,10 +924,9 @@ module.exports = class ScriptingProvider {
|
|
|
922
924
|
// creating a nested generator, calling the other.
|
|
923
925
|
// We hope this.convos does not changes while this iterator is used
|
|
924
926
|
const _convosIterable = function * (options) {
|
|
925
|
-
const context = { count: 0 }
|
|
926
927
|
for (const convo of this.convos) {
|
|
927
928
|
convo.expandPartialConvos()
|
|
928
|
-
yield * this._expandConvo(convo, options,
|
|
929
|
+
yield * this._expandConvo(convo, options, {})
|
|
929
930
|
}
|
|
930
931
|
}.bind(this)
|
|
931
932
|
|
|
@@ -1122,11 +1123,6 @@ module.exports = class ScriptingProvider {
|
|
|
1122
1123
|
} else {
|
|
1123
1124
|
const expanded = Object.assign(_.cloneDeep(currentConvo), { conversation: _.cloneDeep(convoStepsStack) })
|
|
1124
1125
|
if (!options.convoFilter || options.convoFilter(expanded)) {
|
|
1125
|
-
context.count++
|
|
1126
|
-
const logPerEntry = context.count < 10 ? 1 : context.count < 100 ? 10 : context.count < 1000 ? 100 : context.count < 10000 ? 1000 : 10000
|
|
1127
|
-
if (context.count % logPerEntry === 0) {
|
|
1128
|
-
debug(`Convo #${context.count} expanded (${expanded.header.name})`)
|
|
1129
|
-
}
|
|
1130
1126
|
yield expanded
|
|
1131
1127
|
}
|
|
1132
1128
|
}
|
package/src/scripting/helper.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const _ = require('lodash')
|
|
2
2
|
const isJSON = require('is-json')
|
|
3
|
+
const speechScorer = require('word-error-rate')
|
|
3
4
|
|
|
4
5
|
const { E_SCRIPTING_MEMORY_COLUMN_MODE } = require('../Enums')
|
|
5
6
|
|
|
@@ -61,7 +62,7 @@ const removeBuffers = obj => {
|
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
const toString = (value) => {
|
|
64
|
-
if (_.isUndefined(value)) return
|
|
65
|
+
if (_.isUndefined(value) || _.isNil(value)) return ''
|
|
65
66
|
if (_.isString(value)) return value
|
|
66
67
|
if (_.isNumber(value)) return value.toString()
|
|
67
68
|
if (_.isArray(value)) return value.map(v => toString(v)).join(',')
|
|
@@ -524,6 +525,63 @@ const linesToScriptingMemories = (lines, columnMode = null) => {
|
|
|
524
525
|
return scriptingMemories
|
|
525
526
|
}
|
|
526
527
|
|
|
528
|
+
const calculateWer = (str, pattern) => {
|
|
529
|
+
const _prepareString = (str, remWildcard = false) => {
|
|
530
|
+
if (remWildcard) return str.replace(/[.,/#!$%^&;:*{}=\-_`~()]/g, '').toLowerCase()
|
|
531
|
+
return str.replace(/[.,/#!$%^&;:{}=\-_`~()]/g, '').toLowerCase()
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
const _getSubsets = (array, size) => {
|
|
535
|
+
const subsets = []
|
|
536
|
+
for (const index in array) {
|
|
537
|
+
const end = parseInt(index) + size
|
|
538
|
+
if (end <= array.length) { subsets.push(array.slice(index, end)) }
|
|
539
|
+
}
|
|
540
|
+
return subsets
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
const _getWords = str => str.split(' ').map(w => w.trim())
|
|
544
|
+
|
|
545
|
+
const _getErrors = (words1, words2) => words1.map((w, i) => {
|
|
546
|
+
return w !== words2[i]
|
|
547
|
+
})
|
|
548
|
+
|
|
549
|
+
const utterance = pattern
|
|
550
|
+
|
|
551
|
+
const botMessage = _prepareString(str)
|
|
552
|
+
const botMessageWords = botMessage.split(' ').map(bm => bm.trim())
|
|
553
|
+
const utt = _prepareString(utterance)
|
|
554
|
+
|
|
555
|
+
const errors = []
|
|
556
|
+
for (let wildcardPart of utt.split('*')) {
|
|
557
|
+
let wer = 1
|
|
558
|
+
wildcardPart = wildcardPart.trim()
|
|
559
|
+
if (wildcardPart.length === 0) {
|
|
560
|
+
errors.push([false])
|
|
561
|
+
continue
|
|
562
|
+
}
|
|
563
|
+
const wordCount = wildcardPart.split(' ').length
|
|
564
|
+
const subsetPhrases = _getSubsets(botMessageWords, wordCount).map(subset => subset.join(' ')) // botMessageWordsSubsets.filter(subset => subset.length === wordCount).map(subset => subset.reverse().join(' '))
|
|
565
|
+
let subsetPhraseFound = null
|
|
566
|
+
for (const subsetPhrase of subsetPhrases) {
|
|
567
|
+
const localWer = speechScorer.wordErrorRate(subsetPhrase, wildcardPart).toFixed(2)
|
|
568
|
+
if (localWer <= wer) {
|
|
569
|
+
subsetPhraseFound = subsetPhrase
|
|
570
|
+
wer = localWer
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
console.log('lala', subsetPhraseFound)
|
|
574
|
+
errors.push(_getErrors(_getWords(wildcardPart), _getWords(subsetPhraseFound)))
|
|
575
|
+
}
|
|
576
|
+
let errCount = 0
|
|
577
|
+
let allCount = 0
|
|
578
|
+
for (const err of errors) {
|
|
579
|
+
errCount += err.filter(err => err === true).length
|
|
580
|
+
allCount += err.length
|
|
581
|
+
}
|
|
582
|
+
return (errCount / allCount).toFixed(2)
|
|
583
|
+
}
|
|
584
|
+
|
|
527
585
|
module.exports = {
|
|
528
586
|
normalizeText,
|
|
529
587
|
splitStringInNonEmptyLines,
|
|
@@ -537,5 +595,6 @@ module.exports = {
|
|
|
537
595
|
validSenders,
|
|
538
596
|
validateSender,
|
|
539
597
|
validateConvo,
|
|
540
|
-
linesToScriptingMemories
|
|
598
|
+
linesToScriptingMemories,
|
|
599
|
+
calculateWer
|
|
541
600
|
}
|
|
@@ -127,6 +127,10 @@ module.exports = class JsonPathAsserter {
|
|
|
127
127
|
}
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
+
if (this.globalArgs && this.globalArgs.checkExistanceOnEmptyAssert) {
|
|
131
|
+
if (!assert) return Promise.resolve()
|
|
132
|
+
}
|
|
133
|
+
|
|
130
134
|
if (!_.isNil(assert)) {
|
|
131
135
|
const actual = (_.isArray(jsonPathValues) && jsonPathValues.length === 1) ? jsonPathValues[0] : jsonPathValues
|
|
132
136
|
|
|
@@ -135,10 +139,10 @@ module.exports = class JsonPathAsserter {
|
|
|
135
139
|
matchFn = getMatchFunction(this.globalArgs.matchingMode)
|
|
136
140
|
}
|
|
137
141
|
|
|
138
|
-
const match = jsonPathValues.
|
|
142
|
+
const match = jsonPathValues.findIndex(a => matchFn(a, assert)) >= 0
|
|
139
143
|
|
|
140
144
|
if (not && match) {
|
|
141
|
-
return Promise.reject(new BotiumError(`${convoStep.stepTag}: Not expected: "${toString(actual)}" in jsonPath ${path}"`,
|
|
145
|
+
return Promise.reject(new BotiumError(`${convoStep.stepTag}: Not expected: "${actual === '' ? '<empty>' : toString(actual)}" in jsonPath ${path}"`,
|
|
142
146
|
{
|
|
143
147
|
type: 'asserter',
|
|
144
148
|
source: this.name,
|
|
@@ -159,7 +163,7 @@ module.exports = class JsonPathAsserter {
|
|
|
159
163
|
))
|
|
160
164
|
}
|
|
161
165
|
if (!not && !match) {
|
|
162
|
-
return Promise.reject(new BotiumError(`${convoStep.stepTag}: Expected: "${assert}" in jsonPath ${path}, actual: ${toString(actual)}`,
|
|
166
|
+
return Promise.reject(new BotiumError(`${convoStep.stepTag}: Expected: "${assert === '' ? '<empty>' : assert}" in jsonPath ${path}, actual: ${actual === '' ? '<empty>' : toString(actual)}`,
|
|
163
167
|
{
|
|
164
168
|
type: 'asserter',
|
|
165
169
|
source: this.name,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// const _ = require('lodash')
|
|
2
|
-
const speechScorer = require('word-error-rate')
|
|
3
2
|
const { BotiumError } = require('../../BotiumError')
|
|
3
|
+
const { calculateWer } = require('../../helper')
|
|
4
4
|
|
|
5
5
|
module.exports = class WerAsserter {
|
|
6
6
|
constructor (context, caps = {}) {
|
|
@@ -34,7 +34,8 @@ module.exports = class WerAsserter {
|
|
|
34
34
|
const utterance = args[0]
|
|
35
35
|
const threshold = ([',', '.'].find(p => `${args[1]}`.includes(p)) ? parseFloat(args[1]) : parseInt(args[1]) / 100).toFixed(2)
|
|
36
36
|
|
|
37
|
-
const wer =
|
|
37
|
+
const wer = calculateWer(botMsg.messageText, utterance)
|
|
38
|
+
|
|
38
39
|
if (wer > threshold) {
|
|
39
40
|
const _toPercent = (s) => `${(s * 100).toFixed(0)}%`
|
|
40
41
|
|
|
@@ -44,7 +44,7 @@ module.exports = class SetScriptingMemoryLogicHook {
|
|
|
44
44
|
// args[0] cant have the whole name of the variable, because the variable names are replaced
|
|
45
45
|
const name = '$' + params.name
|
|
46
46
|
const value = params.value
|
|
47
|
-
debug(`Set scripting memory variable "${name}" from "${scriptingMemory[name]}" to "${value}, isGlobal: ${isGlobal}, type: ${type}"`)
|
|
47
|
+
debug(`Set scripting memory variable "${name}" from "${scriptingMemory[name]}" to "${value}", isGlobal: ${isGlobal}, type: ${type}"`)
|
|
48
48
|
scriptingMemory[name] = value
|
|
49
49
|
|
|
50
50
|
return Promise.resolve()
|
|
@@ -163,6 +163,26 @@ describe('convo.fillAndApplyScriptingMemory', function () {
|
|
|
163
163
|
const transcript = await compiler.convos[0].Run(container)
|
|
164
164
|
assert.isObject(transcript.scriptingMemory)
|
|
165
165
|
})
|
|
166
|
+
it('should apply scripting memory in begin args', async function () {
|
|
167
|
+
const myCaps = {
|
|
168
|
+
[Capabilities.PROJECTNAME]: 'convo.scriptingmemory',
|
|
169
|
+
[Capabilities.CONTAINERMODE]: echoConnector,
|
|
170
|
+
[Capabilities.SCRIPTING_ENABLE_MEMORY]: true,
|
|
171
|
+
[Capabilities.CUSTOMHOOK_ONBUILD]: 'module.exports = ({ container }) => { console.log("customhooks called"); container.caps.MYTOKEN = "test1234" }'
|
|
172
|
+
}
|
|
173
|
+
const driver = new BotDriver(myCaps)
|
|
174
|
+
const compiler = driver.BuildCompiler()
|
|
175
|
+
const container = await driver.Build()
|
|
176
|
+
|
|
177
|
+
compiler.ReadScript(path.resolve(__dirname, 'convos'), 'applyscriptingmemoryinbegin.convo.txt')
|
|
178
|
+
assert.equal(compiler.convos.length, 1)
|
|
179
|
+
|
|
180
|
+
const transcript = await compiler.convos[0].Run(container)
|
|
181
|
+
assert.isObject(transcript.scriptingMemory)
|
|
182
|
+
assert.equal(transcript.scriptingMemory.$access_token, 'test1234')
|
|
183
|
+
assert.equal(transcript.steps[0].actual.messageText, 'access token: test1234')
|
|
184
|
+
assert.equal(transcript.steps[2].actual.messageText, 'access token: test1234')
|
|
185
|
+
})
|
|
166
186
|
})
|
|
167
187
|
|
|
168
188
|
describe('api', function () {
|
|
@@ -7,16 +7,89 @@ describe('scripting.asserters.jsonPathAsserter', function () {
|
|
|
7
7
|
describe('jsonPathAsserter', function () {
|
|
8
8
|
beforeEach(async function () {
|
|
9
9
|
this.jsonPathAsserter = new JsonPathAsserter({
|
|
10
|
-
Match: (botresponse, utterance) =>
|
|
10
|
+
Match: (botresponse, utterance) => {
|
|
11
|
+
return botresponse.toLowerCase().indexOf(utterance.toLowerCase()) >= 0
|
|
12
|
+
}
|
|
11
13
|
}, {})
|
|
12
14
|
this.jsonPathAsserterWildcard = new JsonPathAsserter({
|
|
13
15
|
Match: getMatchFunction('wildcardIgnoreCase')
|
|
14
16
|
}, {})
|
|
17
|
+
this.jsonPathAsserterEquals = new JsonPathAsserter({
|
|
18
|
+
Match: getMatchFunction('equals')
|
|
19
|
+
}, {})
|
|
15
20
|
this.jsonPathAsserterGlobalArgs = new JsonPathAsserter({
|
|
16
21
|
Match: (botresponse, utterance) => botresponse.toLowerCase().indexOf(utterance.toLowerCase()) >= 0
|
|
17
22
|
}, {}, { path: '$.test' })
|
|
18
23
|
})
|
|
19
24
|
|
|
25
|
+
describe('empty string', function () {
|
|
26
|
+
it('should succeed if both is empty', async function () {
|
|
27
|
+
await this.jsonPathAsserterWildcard.assertConvoStep({
|
|
28
|
+
convoStep: { stepTag: 'test' },
|
|
29
|
+
args: ['$.test', ''],
|
|
30
|
+
botMsg: {
|
|
31
|
+
sourceData: {
|
|
32
|
+
test: ''
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
})
|
|
37
|
+
it('should succeed if null', async function () {
|
|
38
|
+
await this.jsonPathAsserterEquals.assertConvoStep({
|
|
39
|
+
convoStep: { stepTag: 'test' },
|
|
40
|
+
args: ['$.test', ''],
|
|
41
|
+
botMsg: {
|
|
42
|
+
sourceData: {
|
|
43
|
+
test: null
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
})
|
|
48
|
+
it('should succeed if expected is empty, and asserter is negated', async function () {
|
|
49
|
+
await this.jsonPathAsserterEquals.assertNotConvoStep({
|
|
50
|
+
convoStep: { stepTag: 'test' },
|
|
51
|
+
args: ['$.test', ''],
|
|
52
|
+
botMsg: {
|
|
53
|
+
sourceData: {
|
|
54
|
+
test: 'something but not empty string'
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
})
|
|
59
|
+
it('should fail if expected is not empty', async function () {
|
|
60
|
+
try {
|
|
61
|
+
await this.jsonPathAsserterWildcard.assertConvoStep({
|
|
62
|
+
convoStep: { stepTag: 'test' },
|
|
63
|
+
args: ['$.test', 'something but not empty string'],
|
|
64
|
+
botMsg: {
|
|
65
|
+
sourceData: {
|
|
66
|
+
test: ''
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
assert.fail('expected jsonPathAsserter to fail')
|
|
71
|
+
} catch (err) {
|
|
72
|
+
assert.isTrue(err.message.includes('Expected: "something but not empty string" in jsonPath $.test, actual: <empty>'))
|
|
73
|
+
}
|
|
74
|
+
})
|
|
75
|
+
it('should fail if real is not empty', async function () {
|
|
76
|
+
try {
|
|
77
|
+
await this.jsonPathAsserterEquals.assertConvoStep({
|
|
78
|
+
convoStep: { stepTag: 'test' },
|
|
79
|
+
args: ['$.test', ''],
|
|
80
|
+
botMsg: {
|
|
81
|
+
sourceData: {
|
|
82
|
+
test: 'something but not empty string'
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
})
|
|
86
|
+
assert.fail('expected jsonPathAsserter to fail')
|
|
87
|
+
} catch (err) {
|
|
88
|
+
assert.isTrue(err.message.includes('Expected: "<empty>" in jsonPath $.test, actual: something but not empty string'))
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
})
|
|
92
|
+
|
|
20
93
|
it('should do nothing on no arg', async function () {
|
|
21
94
|
await this.jsonPathAsserter.assertConvoStep({})
|
|
22
95
|
})
|
|
@@ -62,7 +135,6 @@ describe('scripting.asserters.jsonPathAsserter', function () {
|
|
|
62
135
|
}
|
|
63
136
|
})
|
|
64
137
|
} catch (err) {
|
|
65
|
-
console.log(err.message)
|
|
66
138
|
assert.isTrue(err.message.includes('Expected: "message4" in jsonPath $.messages[*].label, actual: message1,message2,message3'))
|
|
67
139
|
}
|
|
68
140
|
})
|
|
@@ -216,7 +288,7 @@ describe('scripting.asserters.jsonPathAsserter', function () {
|
|
|
216
288
|
})
|
|
217
289
|
})
|
|
218
290
|
it('should succeed on matching jsonpath from globalArgs', async function () {
|
|
219
|
-
await this.
|
|
291
|
+
await this.jsonPathAsserterGlobalArgs.assertConvoStep({
|
|
220
292
|
convoStep: { stepTag: 'test' },
|
|
221
293
|
args: ['test'],
|
|
222
294
|
botMsg: {
|
|
@@ -376,6 +448,21 @@ describe('scripting.asserters.jsonPathAsserter', function () {
|
|
|
376
448
|
assert.isTrue(err.message.indexOf('Expected: "value1" in jsonPath $.test') > 0)
|
|
377
449
|
}
|
|
378
450
|
})
|
|
451
|
+
|
|
452
|
+
it('should succeed on empty string if checkExistanceOnEmptyAssert is on in globalArgs', async function () {
|
|
453
|
+
this.jsonPathAsserterEquals.globalArgs = {
|
|
454
|
+
checkExistanceOnEmptyAssert: true
|
|
455
|
+
}
|
|
456
|
+
await this.jsonPathAsserterEquals.assertConvoStep({
|
|
457
|
+
convoStep: { stepTag: 'test' },
|
|
458
|
+
args: ['test', ''],
|
|
459
|
+
botMsg: {
|
|
460
|
+
sourceData: {
|
|
461
|
+
test: 'asdf'
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
})
|
|
465
|
+
})
|
|
379
466
|
})
|
|
380
467
|
|
|
381
468
|
describe('jsonPathCountAsserter', function () {
|