botium-core 1.15.9 → 1.15.12
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 +215 -55
- package/dist/botium-cjs.js.map +1 -1
- package/dist/botium-es.js +215 -54
- package/dist/botium-es.js.map +1 -1
- package/package.json +35 -40
- package/src/BotDriver.js +1 -1
- package/src/Events.js +1 -3
- package/src/containers/GridContainer.js +0 -4
- package/src/helpers/TranscriptUtils.js +66 -0
- package/src/scripting/Convo.js +9 -0
- package/src/scripting/ScriptingProvider.js +36 -5
- package/src/scripting/logichook/userinput/MediaInput.js +10 -2
- package/src/utils/boolean.js +39 -0
- package/test/compiler/compilercsv.spec.js +34 -0
- package/test/compiler/compilermarkdown.spec.js +11 -0
- package/test/compiler/compilertxt.spec.js +21 -0
- package/test/compiler/compilerxlsx.spec.js +27 -0
- package/test/compiler/precompilerjson.spec.js +1 -0
- package/test/compiler/precompilermarkdownrasa.spec.js +1 -0
- package/test/connectors/pluginconnectorcontainer.spec.js +1 -0
- package/test/connectors/simplerest.spec.js +3 -1
- package/test/convo/failure.spec.js +1 -0
- package/test/convo/fillAndApplyScriptingMemory.spec.js +56 -0
- package/test/convo/partialconvo.spec.js +3 -0
- package/test/convo/retry.spec.js +9 -0
- package/test/convo/retryasserter.spec.js +9 -0
- package/test/convo/transcript.spec.js +33 -0
- package/test/convo/tree.spec.js +5 -0
- package/test/driver/capabilities.spec.js +16 -0
- package/test/helpers/capabilitiesutils.spec.js +8 -0
- package/test/helpers/transcriptutils.spec.js +1 -0
- package/test/hooks/customhooks.spec.js +3 -0
- package/test/logichooks/hookfromsrc.spec.js +3 -0
- package/test/logichooks/textfromhook.spec.js +1 -0
- package/test/plugins/plugins.spec.js +3 -0
- package/test/scripting/asserters/buttonsAsserter.spec.js +15 -0
- package/test/scripting/asserters/cardsAsserter.spec.js +12 -0
- package/test/scripting/asserters/convoStepParameters.spec.js +11 -0
- package/test/scripting/asserters/entitiesAsserter.spec.js +1 -0
- package/test/scripting/asserters/entityValuesAsserter.spec.js +7 -0
- package/test/scripting/asserters/formsAsserter.spec.js +10 -0
- package/test/scripting/asserters/intentAsserter.spec.js +4 -0
- package/test/scripting/asserters/intentUniqueAsserter.spec.js +2 -0
- package/test/scripting/asserters/jsonpathAsserter.spec.js +25 -0
- package/test/scripting/asserters/mediaAsserter.spec.js +20 -0
- package/test/scripting/asserters/responseLengthAsserter.spec.js +4 -0
- package/test/scripting/asserters/textAsserter.spec.js +1 -0
- package/test/scripting/asserters/textContainsAllAsserter.spec.js +1 -0
- package/test/scripting/asserters/textContainsAnyAsserter.spec.js +1 -0
- package/test/scripting/asserters/textEqualsAsserter.spec.js +1 -0
- package/test/scripting/asserters/textRegexpAllAsserter.spec.js +1 -0
- package/test/scripting/asserters/textRegexpAnyAsserter.spec.js +1 -0
- package/test/scripting/asserters/textWildcardAllAsserter.spec.js +1 -0
- package/test/scripting/asserters/textWildcardAnyAsserter.spec.js +1 -0
- package/test/scripting/asserters/textWildcardExactAllAsserter.spec.js +1 -0
- package/test/scripting/asserters/textWildcardExactAnyAsserter.spec.js +1 -0
- package/test/scripting/asserters/werAsserter.spec.js +6 -0
- package/test/scripting/logichooks/customConditionalStepLogicHook.spec.js +2 -0
- package/test/scripting/logichooks/localvsglobal.spec.js +1 -0
- package/test/scripting/logichooks/pauseLogic.spec.js +4 -0
- package/test/scripting/logichooks/setClearScriptingMemory.spec.js +3 -0
- package/test/scripting/logichooks/updateCustom.spec.js +2 -0
- package/test/scripting/matching/matchingmode.spec.js +48 -0
- package/test/scripting/scriptingModificator.spec.js +1 -0
- package/test/scripting/scriptingmemory/fillScriptingMemoryFromFile.spec.js +4 -0
- package/test/scripting/scriptingmemory/regexp.spec.js +1 -0
- package/test/scripting/scriptingmemory/useScriptingMemoryForAssertion.spec.js +3 -0
- package/test/scripting/txt/decompile.spec.js +20 -0
- package/test/scripting/userinputs/buttonInputConvos.spec.js +1 -0
- package/test/scripting/userinputs/defaultUserInputs.spec.js +13 -0
- package/test/scripting/userinputs/mediaInputConvos.spec.js +10 -0
- package/test/scripting/utteranceexpansion/associateByIndex.spec.js +2 -0
- package/test/security/allowUnsafe.spec.js +5 -0
- package/test/utils.spec.js +2 -0
- package/samples/postman/Botium Agent Sample.postman_collection.json +0 -834
- package/samples/postman/README.md +0 -5
- package/samples/postman/botiumFluent.js +0 -37
- package/src/grid/agent/AgentWorker.js +0 -204
- package/src/grid/agent/agent.js +0 -96
- package/src/grid/agent/agentworkerpool.js +0 -58
- package/src/grid/agent/routes.js +0 -353
- package/src/grid/agent/swagger.json +0 -327
- package/src/grid/agent/swaggerDef.json +0 -8
- package/src/grid/agent/views/index.html +0 -39
- package/test/grid/agent/client.js +0 -65
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "botium-core",
|
|
3
|
-
"version": "1.15.
|
|
3
|
+
"version": "1.15.12",
|
|
4
4
|
"description": "The Selenium for Chatbots",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"module": "dist/botium-es.js",
|
|
@@ -13,8 +13,6 @@
|
|
|
13
13
|
"eslint": "eslint \"./src/**/*.js\" \"./test/**/*.js\"",
|
|
14
14
|
"eslint-fix": "eslint --fix \"./src/**/*.js\" \"./test/**/*.js\"",
|
|
15
15
|
"newpatch": "npm version patch",
|
|
16
|
-
"agent": "node ./src/grid/agent/agent.js",
|
|
17
|
-
"agent-jsdoc": "swagger-jsdoc -d ./src/grid/agent/swaggerDef.json -o ./src/grid/agent/swagger.json ./src/grid/agent/routes.js",
|
|
18
16
|
"link": "npm link botium-connector-dialogflow botium-connector-webdriverio botium-connector-directline3 botium-connector-watson botium-connector-alexa-smapi botium-connector-echo",
|
|
19
17
|
"test": "cross-env NODE_PATH=\"./test/plugins/plugindir/fromfolder:./test/plugins/plugindir/fromfile:./test/security/resources\" mocha \"./test/**/*.spec.js\"",
|
|
20
18
|
"coverage:report": "nyc report --reporter=lcov npm test",
|
|
@@ -31,66 +29,63 @@
|
|
|
31
29
|
},
|
|
32
30
|
"homepage": "https://www.botium.ai",
|
|
33
31
|
"dependencies": {
|
|
34
|
-
"@babel/runtime": "^7.
|
|
35
|
-
"async": "^3.2.
|
|
36
|
-
"body-parser": "^
|
|
37
|
-
"boolean": "^3.2.0",
|
|
32
|
+
"@babel/runtime": "^7.28.6",
|
|
33
|
+
"async": "^3.2.6",
|
|
34
|
+
"body-parser": "^2.2.2",
|
|
38
35
|
"bottleneck": "^2.19.5",
|
|
39
|
-
"csv-parse": "^
|
|
40
|
-
"debug": "^4.3
|
|
41
|
-
"express": "^
|
|
36
|
+
"csv-parse": "^6.1.0",
|
|
37
|
+
"debug": "^4.4.3",
|
|
38
|
+
"express": "^5.2.1",
|
|
42
39
|
"globby": "11.0.4",
|
|
43
|
-
"ioredis": "^5.
|
|
40
|
+
"ioredis": "^5.10.0",
|
|
44
41
|
"is-class": "^0.0.9",
|
|
45
42
|
"is-json": "^2.0.1",
|
|
46
|
-
"jsonpath": "^1.
|
|
47
|
-
"lodash": "^4.17.
|
|
48
|
-
"markdown-it": "^14.
|
|
49
|
-
"mime-types": "^
|
|
43
|
+
"jsonpath": "^1.3.0",
|
|
44
|
+
"lodash": "^4.17.23",
|
|
45
|
+
"markdown-it": "^14.1.1",
|
|
46
|
+
"mime-types": "^3.0.2",
|
|
50
47
|
"mkdirp": "^3.0.1",
|
|
51
48
|
"moment": "^2.30.1",
|
|
52
|
-
"moment-timezone": "^0.
|
|
49
|
+
"moment-timezone": "^0.6.0",
|
|
53
50
|
"mustache": "^4.2.0",
|
|
54
51
|
"promise-retry": "^2.0.1",
|
|
55
52
|
"promise.allsettled": "^1.0.7",
|
|
56
53
|
"randomatic": "^3.1.1",
|
|
57
|
-
"rimraf": "^
|
|
54
|
+
"rimraf": "^6.1.3",
|
|
58
55
|
"sanitize-filename": "^1.6.3",
|
|
59
56
|
"slugify": "^1.6.6",
|
|
60
|
-
"socket.io": "^4.
|
|
61
|
-
"socket.io-client": "^4.
|
|
57
|
+
"socket.io": "^4.8.3",
|
|
58
|
+
"socket.io-client": "^4.8.3",
|
|
62
59
|
"socketio-auth": "^0.1.1",
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"tinyglobby": "^0.2.10",
|
|
66
|
-
"undici": "^6.21.0",
|
|
60
|
+
"tinyglobby": "^0.2.15",
|
|
61
|
+
"undici": "^7.22.0",
|
|
67
62
|
"uuid": "^9.0.1",
|
|
68
63
|
"word-error-rate": "0.0.7",
|
|
69
64
|
"write-yaml": "^1.0.0",
|
|
70
65
|
"xlsx": "^0.18.5",
|
|
71
|
-
"xregexp": "^5.1.
|
|
72
|
-
"yaml": "^2.
|
|
66
|
+
"xregexp": "^5.1.2",
|
|
67
|
+
"yaml": "^2.8.2"
|
|
73
68
|
},
|
|
74
69
|
"devDependencies": {
|
|
75
|
-
"@babel/core": "^7.
|
|
76
|
-
"@babel/node": "^7.
|
|
77
|
-
"@babel/plugin-transform-runtime": "^7.
|
|
78
|
-
"@babel/preset-env": "^7.
|
|
70
|
+
"@babel/core": "^7.29.0",
|
|
71
|
+
"@babel/node": "^7.29.0",
|
|
72
|
+
"@babel/plugin-transform-runtime": "^7.29.0",
|
|
73
|
+
"@babel/preset-env": "^7.29.0",
|
|
79
74
|
"chai": "4.3.10",
|
|
80
|
-
"chai-as-promised": "^7.1.
|
|
81
|
-
"cross-env": "^
|
|
82
|
-
"eslint": "^8.
|
|
75
|
+
"chai-as-promised": "^7.1.2",
|
|
76
|
+
"cross-env": "^10.1.0",
|
|
77
|
+
"eslint": "^8.57.1",
|
|
83
78
|
"eslint-config-standard": "^17.1.0",
|
|
84
|
-
"eslint-plugin-import": "^2.
|
|
85
|
-
"eslint-plugin-mocha": "^10.
|
|
79
|
+
"eslint-plugin-import": "^2.32.0",
|
|
80
|
+
"eslint-plugin-mocha": "^10.5.0",
|
|
86
81
|
"eslint-plugin-n": "^16.6.2",
|
|
87
|
-
"eslint-plugin-promise": "^6.
|
|
82
|
+
"eslint-plugin-promise": "^6.6.0",
|
|
88
83
|
"eslint-plugin-standard": "^4.1.0",
|
|
89
|
-
"mocha": "^
|
|
90
|
-
"nock": "^14.0.
|
|
91
|
-
"npm-check-updates": "^
|
|
92
|
-
"nyc": "^
|
|
93
|
-
"rollup": "2.
|
|
84
|
+
"mocha": "^11.7.5",
|
|
85
|
+
"nock": "^14.0.11",
|
|
86
|
+
"npm-check-updates": "^19.6.3",
|
|
87
|
+
"nyc": "^18.0.0",
|
|
88
|
+
"rollup": "2.80.0",
|
|
94
89
|
"rollup-plugin-babel": "^4.4.0",
|
|
95
90
|
"rollup-plugin-commonjs": "^10.1.0",
|
|
96
91
|
"rollup-plugin-json": "^4.0.0",
|
package/src/BotDriver.js
CHANGED
|
@@ -8,7 +8,7 @@ const sanitize = require('sanitize-filename')
|
|
|
8
8
|
const moment = require('moment')
|
|
9
9
|
const randomize = require('randomatic')
|
|
10
10
|
const _ = require('lodash')
|
|
11
|
-
const { boolean } = require('boolean')
|
|
11
|
+
const { boolean } = require('./utils/boolean')
|
|
12
12
|
const EventEmitter = require('events')
|
|
13
13
|
const debug = require('debug')('botium-core-BotDriver')
|
|
14
14
|
|
package/src/Events.js
CHANGED
|
@@ -20,7 +20,5 @@ module.exports = {
|
|
|
20
20
|
MESSAGE_RECEIVEDFROMBOT: 'MESSAGE_RECEIVEDFROMBOT',
|
|
21
21
|
MESSAGE_RECEIVEFROMBOT_ERROR: 'MESSAGE_RECEIVEFROMBOT_ERROR',
|
|
22
22
|
MESSAGE_ATTACHMENT: 'MESSAGE_ATTACHMENT',
|
|
23
|
-
MESSAGE_TRANSCRIPT: 'MESSAGE_TRANSCRIPT'
|
|
24
|
-
// Botium Agent Events
|
|
25
|
-
TOOMUCHWORKERS_ERROR: 'TOOMUCHWORKERS_ERROR'
|
|
23
|
+
MESSAGE_TRANSCRIPT: 'MESSAGE_TRANSCRIPT'
|
|
26
24
|
}
|
|
@@ -49,10 +49,6 @@ module.exports = class GridContainer extends BaseContainer {
|
|
|
49
49
|
debug(`unauthorized ${err.message}`)
|
|
50
50
|
socketComplete(`Grid Access not authorized: ${err.message}`)
|
|
51
51
|
})
|
|
52
|
-
this.socket.on(Events.TOOMUCHWORKERS_ERROR, (err) => {
|
|
53
|
-
debug(`TOOMUCHWORKERS_ERROR ${err.message}`)
|
|
54
|
-
socketComplete(`Grid Access not possible: ${err.message}`)
|
|
55
|
-
})
|
|
56
52
|
this.socket.on(Events.CONTAINER_BUILT, () => {
|
|
57
53
|
debug(Events.CONTAINER_BUILT)
|
|
58
54
|
socketComplete()
|
|
@@ -1,4 +1,70 @@
|
|
|
1
|
+
const path = require('path')
|
|
2
|
+
const fs = require('fs')
|
|
1
3
|
const _ = require('lodash')
|
|
4
|
+
const { parse: csvParseSync } = require('csv-parse/sync')
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Find transcription for an audio file: .txt same base name, or transcript.csv in parent dirs.
|
|
8
|
+
* @param {string} baseDir - Base directory for resolving paths
|
|
9
|
+
* @param {string} audioFile - Relative path to audio file
|
|
10
|
+
* @param {object} [options] - Optional: { csvCache: {}, onError: (msg) => {} }
|
|
11
|
+
* @returns {string|null} Transcription text or null
|
|
12
|
+
*/
|
|
13
|
+
module.exports.findTranscription = (baseDir, audioFile, options = {}) => {
|
|
14
|
+
const { csvCache = {}, onError } = options
|
|
15
|
+
const transcriptionFilename = `${audioFile.substring(0, audioFile.lastIndexOf('.'))}.txt`
|
|
16
|
+
const transcriptionFilenameAbs = path.resolve(baseDir, transcriptionFilename)
|
|
17
|
+
try {
|
|
18
|
+
if (fs.existsSync(transcriptionFilenameAbs)) {
|
|
19
|
+
return fs.readFileSync(transcriptionFilenameAbs, { encoding: 'utf-8' }).trim()
|
|
20
|
+
}
|
|
21
|
+
} catch (err) {
|
|
22
|
+
if (onError) onError(`Transcription File ${transcriptionFilenameAbs} not readable: ${err.message}`)
|
|
23
|
+
throw new Error(`Reading transcription file ${transcriptionFilename} for ${audioFile} failed`)
|
|
24
|
+
}
|
|
25
|
+
if (csvCache[audioFile]) {
|
|
26
|
+
return csvCache[audioFile]
|
|
27
|
+
}
|
|
28
|
+
const audioFileComponents = audioFile.split('/')
|
|
29
|
+
for (let parentIndex = audioFileComponents.length - 1; parentIndex >= 0; parentIndex--) {
|
|
30
|
+
const csvDirectory = audioFileComponents.slice(0, parentIndex)
|
|
31
|
+
const csvFilename = path.join(...csvDirectory, 'transcript.csv')
|
|
32
|
+
const csvFilenameAbs = path.resolve(baseDir, csvFilename)
|
|
33
|
+
try {
|
|
34
|
+
if (fs.existsSync(csvFilenameAbs)) {
|
|
35
|
+
const records = csvParseSync(fs.readFileSync(csvFilenameAbs, { encoding: 'utf-8' }).trim(), {
|
|
36
|
+
columns: ['filename', 'transcription'],
|
|
37
|
+
delimiter: [',', ';', ':', '\t'],
|
|
38
|
+
trim: true,
|
|
39
|
+
skip_empty_lines: true
|
|
40
|
+
})
|
|
41
|
+
if (records && records.length > 0) {
|
|
42
|
+
for (const record of records) {
|
|
43
|
+
const fnKey = path.join(...csvDirectory, record.filename)
|
|
44
|
+
csvCache[fnKey] = record.transcription
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
} catch (err) {
|
|
49
|
+
if (onError) onError(`Transcription CSV File ${csvFilenameAbs} not readable: ${err.message}`)
|
|
50
|
+
throw new Error(`Reading transcription CSV file for ${csvFilename} failed`)
|
|
51
|
+
}
|
|
52
|
+
if (csvCache[audioFile]) {
|
|
53
|
+
return csvCache[audioFile]
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return null
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Derive transcription text from audio filename (basename without extension, underscores/hyphens → spaces).
|
|
61
|
+
* @param {string} audioFile - Path or filename of audio file
|
|
62
|
+
* @returns {string}
|
|
63
|
+
*/
|
|
64
|
+
module.exports.transcriptionFromFilename = (audioFile) => {
|
|
65
|
+
const filename = path.basename(audioFile, path.extname(audioFile))
|
|
66
|
+
return filename.split(/[_-]+/).join(' ')
|
|
67
|
+
}
|
|
2
68
|
|
|
3
69
|
module.exports.hasWaitForBotTimeout = (transciptError) => {
|
|
4
70
|
if (!transciptError) {
|
package/src/scripting/Convo.js
CHANGED
|
@@ -270,6 +270,7 @@ class Convo {
|
|
|
270
270
|
|
|
271
271
|
async runConversation (container, scriptingMemory, transcript) {
|
|
272
272
|
const transcriptSteps = []
|
|
273
|
+
transcript.steps = transcriptSteps
|
|
273
274
|
try {
|
|
274
275
|
let lastMeConvoStep = null
|
|
275
276
|
let botMsg = null
|
|
@@ -416,6 +417,14 @@ class Convo {
|
|
|
416
417
|
throw failErr
|
|
417
418
|
}
|
|
418
419
|
} else if (convoStep.sender === 'bot') {
|
|
420
|
+
if (this.scriptingEvents.executeBotStep) {
|
|
421
|
+
const executeBotStepResult = await this.scriptingEvents.executeBotStep({ convo: this, convoStep, container, scriptingMemory, transcript, transcriptStep, transcriptSteps })
|
|
422
|
+
if (executeBotStepResult) {
|
|
423
|
+
skipTranscriptStep = true
|
|
424
|
+
continue
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
419
428
|
if (waitForBotSays) {
|
|
420
429
|
botMsg = null
|
|
421
430
|
} else {
|
|
@@ -115,6 +115,25 @@ module.exports = class ScriptingProvider {
|
|
|
115
115
|
onBotEnd: ({ convo, convoStep, scriptingMemory, ...rest }) => {
|
|
116
116
|
return this._createLogicHookPromises({ hookType: 'onBotEnd', logicHooks: (convoStep?.logicHooks || []), convo, convoStep, scriptingMemory, ...rest })
|
|
117
117
|
},
|
|
118
|
+
executeBotStep: ({ convo, convoStep, container, scriptingMemory, ...rest }) => {
|
|
119
|
+
const logicHooks = (convoStep?.logicHooks || [])
|
|
120
|
+
const executeBotStepHooks = logicHooks.filter(l => this.logicHooks[l.name] && typeof this.logicHooks[l.name].executeBotStep === 'function')
|
|
121
|
+
if (executeBotStepHooks.length > 1) {
|
|
122
|
+
throw new Error(`${convo?.header?.name}/${convoStep?.stepTag}: Multiple logic hooks implement executeBotStep: ${executeBotStepHooks.map(l => l.name).join(', ')}. Only one is allowed per step.`)
|
|
123
|
+
}
|
|
124
|
+
if (executeBotStepHooks.length === 1) {
|
|
125
|
+
const lh = executeBotStepHooks[0]
|
|
126
|
+
return this.logicHooks[lh.name].executeBotStep({
|
|
127
|
+
convo,
|
|
128
|
+
convoStep,
|
|
129
|
+
scriptingMemory,
|
|
130
|
+
container,
|
|
131
|
+
args: ScriptingMemory.applyToArgs(lh.args, scriptingMemory, container.caps),
|
|
132
|
+
...rest
|
|
133
|
+
})
|
|
134
|
+
}
|
|
135
|
+
return null
|
|
136
|
+
},
|
|
118
137
|
assertConvoBegin: ({ convo, convoStep, scriptingMemory, ...rest }) => {
|
|
119
138
|
return this._createAsserterPromises({ asserterType: 'assertConvoBegin', asserters: (convo?.beginAsserter || []), convo, convoStep, scriptingMemory, ...rest })
|
|
120
139
|
},
|
|
@@ -480,6 +499,7 @@ module.exports = class ScriptingProvider {
|
|
|
480
499
|
onBotStart: this.scriptingEvents.onBotStart.bind(this),
|
|
481
500
|
onBotPrepare: this.scriptingEvents.onBotPrepare.bind(this),
|
|
482
501
|
onBotEnd: this.scriptingEvents.onBotEnd.bind(this),
|
|
502
|
+
executeBotStep: this.scriptingEvents.executeBotStep.bind(this),
|
|
483
503
|
setUserInput: this.scriptingEvents.setUserInput.bind(this),
|
|
484
504
|
fail: this.scriptingEvents.fail && this.scriptingEvents.fail.bind(this)
|
|
485
505
|
}
|
|
@@ -1004,7 +1024,11 @@ module.exports = class ScriptingProvider {
|
|
|
1004
1024
|
// use skip and keep, or justHeader
|
|
1005
1025
|
justHeader: false,
|
|
1006
1026
|
// drop unwanted convos
|
|
1007
|
-
convoFilter: null
|
|
1027
|
+
convoFilter: null,
|
|
1028
|
+
mediaInput: {
|
|
1029
|
+
// MESSAGE_TEXT_FROM_FILENAME or MESSAGE_TEXT_FROM_TRANSCRIPTION or falsy
|
|
1030
|
+
messageTextMode: null
|
|
1031
|
+
}
|
|
1008
1032
|
}, options)
|
|
1009
1033
|
const expandedConvos = []
|
|
1010
1034
|
// The globalContext is going to keep the data even if the Object.assign which happening to create the myContext in _expandConvo function
|
|
@@ -1043,7 +1067,11 @@ module.exports = class ScriptingProvider {
|
|
|
1043
1067
|
ExpandConvosIterable (options = {}) {
|
|
1044
1068
|
options = Object.assign({
|
|
1045
1069
|
// drop unwanted convos
|
|
1046
|
-
convoFilter: null
|
|
1070
|
+
convoFilter: null,
|
|
1071
|
+
mediaInput: {
|
|
1072
|
+
// MESSAGE_TEXT_FROM_FILENAME or MESSAGE_TEXT_FROM_TRANSCRIPTION or falsy
|
|
1073
|
+
messageTextMode: null
|
|
1074
|
+
}
|
|
1047
1075
|
}, options)
|
|
1048
1076
|
// The globalContext is going to keep the data even if the Object.assign which happening to create the myContext in _expandConvo function
|
|
1049
1077
|
const context = {
|
|
@@ -1176,7 +1204,7 @@ module.exports = class ScriptingProvider {
|
|
|
1176
1204
|
const ui = currentStep.userInputs[uiIndex]
|
|
1177
1205
|
const userInput = this.userInputs[ui.name]
|
|
1178
1206
|
if (userInput && userInput.expandConvo) {
|
|
1179
|
-
const expandedUserInputs = userInput.expandConvo({ convo: currentConvo, convoStep: currentStep, args: ui.args })
|
|
1207
|
+
const expandedUserInputs = userInput.expandConvo({ convo: currentConvo, convoStep: currentStep, args: ui.args, options })
|
|
1180
1208
|
if (expandedUserInputs && expandedUserInputs.length > 0) {
|
|
1181
1209
|
// let sampleinputs = expandedUserInputs
|
|
1182
1210
|
const processSampleInputs = function * (sampleinputs, myContext, uiIndex) {
|
|
@@ -1185,10 +1213,13 @@ module.exports = class ScriptingProvider {
|
|
|
1185
1213
|
}
|
|
1186
1214
|
}
|
|
1187
1215
|
const processSampleInput = function * (sampleinput, length, index, myContext, uiIndex) {
|
|
1216
|
+
const { messageText, ...userInput } = sampleinput
|
|
1188
1217
|
const currentStepsStack = convoStepsStack.slice()
|
|
1189
1218
|
const currentStepMod = _.cloneDeep(currentStep)
|
|
1190
|
-
currentStepMod.userInputs[uiIndex] =
|
|
1191
|
-
|
|
1219
|
+
currentStepMod.userInputs[uiIndex] = userInput
|
|
1220
|
+
if (messageText) {
|
|
1221
|
+
currentStepMod.messageText = messageText
|
|
1222
|
+
}
|
|
1192
1223
|
currentStepsStack.push(currentStepMod)
|
|
1193
1224
|
const currentConvoLabeled = _.cloneDeep(currentConvo)
|
|
1194
1225
|
if (length > 1) {
|
|
@@ -8,6 +8,7 @@ const _ = require('lodash')
|
|
|
8
8
|
const { BotiumMockMedia } = require('../../../../src/mocks/BotiumMockRichMessageTypes')
|
|
9
9
|
const { BotiumError } = require('../../../../src/scripting/BotiumError')
|
|
10
10
|
const Capabilities = require('../../../../src/Capabilities')
|
|
11
|
+
const TranscriptUtils = require('../../../helpers/TranscriptUtils')
|
|
11
12
|
|
|
12
13
|
const DEFAULT_BASE_SELECTOR = 'sourceTag.testSetId'
|
|
13
14
|
|
|
@@ -151,7 +152,7 @@ module.exports = class MediaInput {
|
|
|
151
152
|
return mime.lookup(arg)
|
|
152
153
|
}
|
|
153
154
|
|
|
154
|
-
expandConvo ({ convo, convoStep, args }) {
|
|
155
|
+
expandConvo ({ convo, convoStep, args, options }) {
|
|
155
156
|
const hasWildcard = args.findIndex(a => this._isWildcard(a)) >= 0
|
|
156
157
|
|
|
157
158
|
if (args && (args.length > 1 || hasWildcard)) {
|
|
@@ -161,10 +162,17 @@ module.exports = class MediaInput {
|
|
|
161
162
|
// we need to escape brackets to find files
|
|
162
163
|
const mediaFiles = globSync(arg.replace(/[()[\]{}]/g, '\\$&'), { cwd: baseDir })
|
|
163
164
|
mediaFiles.forEach(mf => {
|
|
165
|
+
let messageText = null
|
|
166
|
+
if (options.mediaInput.messageTextMode === 'MESSAGE_TEXT_FROM_FILENAME') {
|
|
167
|
+
messageText = TranscriptUtils.transcriptionFromFilename(mf)
|
|
168
|
+
} else if (options.mediaInput.messageTextMode === 'MESSAGE_TEXT_FROM_TRANSCRIPTION') {
|
|
169
|
+
messageText = TranscriptUtils.findTranscription(baseDir, mf)
|
|
170
|
+
}
|
|
164
171
|
e.push({
|
|
165
172
|
name: 'MEDIA',
|
|
166
173
|
args: [mf],
|
|
167
|
-
convoPostfix: _.last(mf.split('/'))
|
|
174
|
+
convoPostfix: _.last(mf.split('/')),
|
|
175
|
+
...messageText ? { messageText } : {}
|
|
168
176
|
})
|
|
169
177
|
})
|
|
170
178
|
} else {
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts a value to a boolean.
|
|
3
|
+
* Similar to the 'boolean' npm package implementation.
|
|
4
|
+
*
|
|
5
|
+
* @param {*} value - The value to convert to boolean
|
|
6
|
+
* @returns {boolean} The boolean representation of the value
|
|
7
|
+
*/
|
|
8
|
+
function boolean (value) {
|
|
9
|
+
// Handle null and undefined
|
|
10
|
+
if (value == null) {
|
|
11
|
+
return false
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Handle boolean values
|
|
15
|
+
if (typeof value === 'boolean') {
|
|
16
|
+
return value
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Handle numbers
|
|
20
|
+
if (typeof value === 'number') {
|
|
21
|
+
return value !== 0 && !isNaN(value)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Handle strings
|
|
25
|
+
if (typeof value === 'string') {
|
|
26
|
+
const normalized = value.trim().toLowerCase()
|
|
27
|
+
if (normalized === 'true' || normalized === 'yes' || normalized === 'on' || normalized === '1') {
|
|
28
|
+
return true
|
|
29
|
+
}
|
|
30
|
+
if (normalized === 'false' || normalized === 'no' || normalized === 'off' || normalized === '0' || normalized === '') {
|
|
31
|
+
return false
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// For all other values, use JavaScript's truthiness
|
|
36
|
+
return Boolean(value)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
module.exports = { boolean }
|