botium-core 1.15.8 → 1.15.10
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 +147 -8
- package/dist/botium-cjs.js.map +1 -1
- package/dist/botium-es.js +147 -8
- package/dist/botium-es.js.map +1 -1
- package/package.json +1 -1
- package/src/BotDriver.js +2 -2
- package/src/helpers/TranscriptUtils.js +66 -0
- package/src/scripting/Convo.js +9 -0
- package/src/scripting/ScriptingProvider.js +46 -6
- package/src/scripting/logichook/userinput/MediaInput.js +10 -2
- package/test/driver/capabilities.spec.js +9 -0
package/dist/botium-es.js
CHANGED
|
@@ -35,7 +35,7 @@ import express from 'express';
|
|
|
35
35
|
import bodyParser from 'body-parser';
|
|
36
36
|
|
|
37
37
|
var name = "botium-core";
|
|
38
|
-
var version$1 = "1.15.
|
|
38
|
+
var version$1 = "1.15.10";
|
|
39
39
|
var description = "The Selenium for Chatbots";
|
|
40
40
|
var main = "index.js";
|
|
41
41
|
var module = "dist/botium-es.js";
|
|
@@ -2997,6 +2997,7 @@ class Convo$6 {
|
|
|
2997
2997
|
}
|
|
2998
2998
|
async runConversation(container, scriptingMemory, transcript) {
|
|
2999
2999
|
const transcriptSteps = [];
|
|
3000
|
+
transcript.steps = transcriptSteps;
|
|
3000
3001
|
try {
|
|
3001
3002
|
let lastMeConvoStep = null;
|
|
3002
3003
|
let botMsg = null;
|
|
@@ -3181,6 +3182,21 @@ class Convo$6 {
|
|
|
3181
3182
|
throw failErr;
|
|
3182
3183
|
}
|
|
3183
3184
|
} else if (convoStep.sender === 'bot') {
|
|
3185
|
+
if (this.scriptingEvents.executeBotStep) {
|
|
3186
|
+
const executeBotStepResult = await this.scriptingEvents.executeBotStep({
|
|
3187
|
+
convo: this,
|
|
3188
|
+
convoStep,
|
|
3189
|
+
container,
|
|
3190
|
+
scriptingMemory,
|
|
3191
|
+
transcript,
|
|
3192
|
+
transcriptStep,
|
|
3193
|
+
transcriptSteps
|
|
3194
|
+
});
|
|
3195
|
+
if (executeBotStepResult) {
|
|
3196
|
+
skipTranscriptStep = true;
|
|
3197
|
+
continue;
|
|
3198
|
+
}
|
|
3199
|
+
}
|
|
3184
3200
|
if (waitForBotSays) {
|
|
3185
3201
|
botMsg = null;
|
|
3186
3202
|
} else {
|
|
@@ -5754,6 +5770,31 @@ var ScriptingProvider_1 = class ScriptingProvider {
|
|
|
5754
5770
|
...rest
|
|
5755
5771
|
});
|
|
5756
5772
|
},
|
|
5773
|
+
executeBotStep: ({
|
|
5774
|
+
convo,
|
|
5775
|
+
convoStep,
|
|
5776
|
+
container,
|
|
5777
|
+
scriptingMemory,
|
|
5778
|
+
...rest
|
|
5779
|
+
}) => {
|
|
5780
|
+
const logicHooks = convoStep?.logicHooks || [];
|
|
5781
|
+
const executeBotStepHooks = logicHooks.filter(l => this.logicHooks[l.name] && typeof this.logicHooks[l.name].executeBotStep === 'function');
|
|
5782
|
+
if (executeBotStepHooks.length > 1) {
|
|
5783
|
+
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.`);
|
|
5784
|
+
}
|
|
5785
|
+
if (executeBotStepHooks.length === 1) {
|
|
5786
|
+
const lh = executeBotStepHooks[0];
|
|
5787
|
+
return this.logicHooks[lh.name].executeBotStep({
|
|
5788
|
+
convo,
|
|
5789
|
+
convoStep,
|
|
5790
|
+
scriptingMemory,
|
|
5791
|
+
container,
|
|
5792
|
+
args: ScriptingMemory.applyToArgs(lh.args, scriptingMemory, container.caps),
|
|
5793
|
+
...rest
|
|
5794
|
+
});
|
|
5795
|
+
}
|
|
5796
|
+
return null;
|
|
5797
|
+
},
|
|
5757
5798
|
assertConvoBegin: ({
|
|
5758
5799
|
convo,
|
|
5759
5800
|
convoStep,
|
|
@@ -6055,12 +6096,18 @@ var ScriptingProvider_1 = class ScriptingProvider {
|
|
|
6055
6096
|
if (hookType !== 'onMeStart' && hookType !== 'onMePrepare' && hookType !== 'onMeEnd' && hookType !== 'onBotStart' && hookType !== 'onBotPrepare' && hookType !== 'onBotEnd' && hookType !== 'onConvoBegin' && hookType !== 'onConvoEnd') {
|
|
6056
6097
|
throw Error(`Unknown hookType ${hookType}`);
|
|
6057
6098
|
}
|
|
6058
|
-
|
|
6099
|
+
let localHooks = (logicHooks || []).filter(l => this.logicHooks[l.name][hookType]);
|
|
6100
|
+
// Scripting memory file are injected via SET_SCRIPTING_MEMORY in the BEGIN step
|
|
6101
|
+
// But there might be other logic hooks that need the scripting memory variables
|
|
6102
|
+
// Order is important (SET_SCRIPTING_MEMORY in begin can be because the user added it,
|
|
6103
|
+
// or because the scripting memory file added it. User one has to be the last one.
|
|
6104
|
+
localHooks = [...localHooks.filter(l => l.name === 'SET_SCRIPTING_MEMORY'), ...localHooks.filter(l => l.name !== 'SET_SCRIPTING_MEMORY')];
|
|
6059
6105
|
const convoStepPromises = localHooks.map(l => p(this.retryHelperLogicHook, () => this.logicHooks[l.name][hookType]({
|
|
6060
6106
|
convo,
|
|
6061
6107
|
convoStep,
|
|
6062
6108
|
scriptingMemory,
|
|
6063
6109
|
container,
|
|
6110
|
+
// Do this more sensitve for SET_SCRIPTING_MEMORY? It can have scripting variables in the args
|
|
6064
6111
|
args: ScriptingMemory.applyToArgs(l.args, scriptingMemory, container.caps, rest.botMsg),
|
|
6065
6112
|
isGlobal: false,
|
|
6066
6113
|
...rest
|
|
@@ -6150,6 +6197,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
|
|
|
6150
6197
|
onBotStart: this.scriptingEvents.onBotStart.bind(this),
|
|
6151
6198
|
onBotPrepare: this.scriptingEvents.onBotPrepare.bind(this),
|
|
6152
6199
|
onBotEnd: this.scriptingEvents.onBotEnd.bind(this),
|
|
6200
|
+
executeBotStep: this.scriptingEvents.executeBotStep.bind(this),
|
|
6153
6201
|
setUserInput: this.scriptingEvents.setUserInput.bind(this),
|
|
6154
6202
|
fail: this.scriptingEvents.fail && this.scriptingEvents.fail.bind(this)
|
|
6155
6203
|
}
|
|
@@ -6670,7 +6718,11 @@ var ScriptingProvider_1 = class ScriptingProvider {
|
|
|
6670
6718
|
// use skip and keep, or justHeader
|
|
6671
6719
|
justHeader: false,
|
|
6672
6720
|
// drop unwanted convos
|
|
6673
|
-
convoFilter: null
|
|
6721
|
+
convoFilter: null,
|
|
6722
|
+
mediaInput: {
|
|
6723
|
+
// MESSAGE_TEXT_FROM_FILENAME or MESSAGE_TEXT_FROM_TRANSCRIPTION or falsy
|
|
6724
|
+
messageTextMode: null
|
|
6725
|
+
}
|
|
6674
6726
|
}, options);
|
|
6675
6727
|
const expandedConvos = [];
|
|
6676
6728
|
// The globalContext is going to keep the data even if the Object.assign which happening to create the myContext in _expandConvo function
|
|
@@ -6708,7 +6760,11 @@ var ScriptingProvider_1 = class ScriptingProvider {
|
|
|
6708
6760
|
ExpandConvosIterable(options = {}) {
|
|
6709
6761
|
options = Object.assign({
|
|
6710
6762
|
// drop unwanted convos
|
|
6711
|
-
convoFilter: null
|
|
6763
|
+
convoFilter: null,
|
|
6764
|
+
mediaInput: {
|
|
6765
|
+
// MESSAGE_TEXT_FROM_FILENAME or MESSAGE_TEXT_FROM_TRANSCRIPTION or falsy
|
|
6766
|
+
messageTextMode: null
|
|
6767
|
+
}
|
|
6712
6768
|
}, options);
|
|
6713
6769
|
// The globalContext is going to keep the data even if the Object.assign which happening to create the myContext in _expandConvo function
|
|
6714
6770
|
const context = {
|
|
@@ -6855,7 +6911,8 @@ var ScriptingProvider_1 = class ScriptingProvider {
|
|
|
6855
6911
|
const expandedUserInputs = userInput.expandConvo({
|
|
6856
6912
|
convo: currentConvo,
|
|
6857
6913
|
convoStep: currentStep,
|
|
6858
|
-
args: ui.args
|
|
6914
|
+
args: ui.args,
|
|
6915
|
+
options
|
|
6859
6916
|
});
|
|
6860
6917
|
if (expandedUserInputs && expandedUserInputs.length > 0) {
|
|
6861
6918
|
// let sampleinputs = expandedUserInputs
|
|
@@ -6867,9 +6924,16 @@ var ScriptingProvider_1 = class ScriptingProvider {
|
|
|
6867
6924
|
}
|
|
6868
6925
|
};
|
|
6869
6926
|
const processSampleInput = function* (sampleinput, length, index, myContext, uiIndex) {
|
|
6927
|
+
const {
|
|
6928
|
+
messageText,
|
|
6929
|
+
...userInput
|
|
6930
|
+
} = sampleinput;
|
|
6870
6931
|
const currentStepsStack = convoStepsStack.slice();
|
|
6871
6932
|
const currentStepMod = lodash.cloneDeep(currentStep);
|
|
6872
|
-
currentStepMod.userInputs[uiIndex] =
|
|
6933
|
+
currentStepMod.userInputs[uiIndex] = userInput;
|
|
6934
|
+
if (messageText) {
|
|
6935
|
+
currentStepMod.messageText = messageText;
|
|
6936
|
+
}
|
|
6873
6937
|
currentStepsStack.push(currentStepMod);
|
|
6874
6938
|
const currentConvoLabeled = lodash.cloneDeep(currentConvo);
|
|
6875
6939
|
if (length > 1) {
|
|
@@ -9529,8 +9593,8 @@ var BotDriver_1 = class BotDriver {
|
|
|
9529
9593
|
if (lodash.isString(newCaps[capKey])) {
|
|
9530
9594
|
try {
|
|
9531
9595
|
caps[capKey] = JSON.parse(newCaps[capKey]);
|
|
9532
|
-
if (lodash.isFinite(
|
|
9533
|
-
caps[capKey] =
|
|
9596
|
+
if (lodash.isFinite(Number(newCaps[capKey]))) {
|
|
9597
|
+
caps[capKey] = newCaps[capKey].toString();
|
|
9534
9598
|
}
|
|
9535
9599
|
} catch (err) {
|
|
9536
9600
|
caps[capKey] = newCaps[capKey];
|
|
@@ -9789,6 +9853,79 @@ Plugins.PLUGIN_TYPE_LOGICHOOK;
|
|
|
9789
9853
|
Plugins.PLUGIN_TYPE_USERINPUT;
|
|
9790
9854
|
Plugins.TYPE_TO_PREFIX;
|
|
9791
9855
|
|
|
9856
|
+
const {
|
|
9857
|
+
parse: csvParseSync
|
|
9858
|
+
} = sync;
|
|
9859
|
+
|
|
9860
|
+
/**
|
|
9861
|
+
* Find transcription for an audio file: .txt same base name, or transcript.csv in parent dirs.
|
|
9862
|
+
* @param {string} baseDir - Base directory for resolving paths
|
|
9863
|
+
* @param {string} audioFile - Relative path to audio file
|
|
9864
|
+
* @param {object} [options] - Optional: { csvCache: {}, onError: (msg) => {} }
|
|
9865
|
+
* @returns {string|null} Transcription text or null
|
|
9866
|
+
*/
|
|
9867
|
+
var findTranscription = (baseDir, audioFile, options = {}) => {
|
|
9868
|
+
const {
|
|
9869
|
+
csvCache = {},
|
|
9870
|
+
onError
|
|
9871
|
+
} = options;
|
|
9872
|
+
const transcriptionFilename = `${audioFile.substring(0, audioFile.lastIndexOf('.'))}.txt`;
|
|
9873
|
+
const transcriptionFilenameAbs = path.resolve(baseDir, transcriptionFilename);
|
|
9874
|
+
try {
|
|
9875
|
+
if (fs.existsSync(transcriptionFilenameAbs)) {
|
|
9876
|
+
return fs.readFileSync(transcriptionFilenameAbs, {
|
|
9877
|
+
encoding: 'utf-8'
|
|
9878
|
+
}).trim();
|
|
9879
|
+
}
|
|
9880
|
+
} catch (err) {
|
|
9881
|
+
if (onError) onError(`Transcription File ${transcriptionFilenameAbs} not readable: ${err.message}`);
|
|
9882
|
+
throw new Error(`Reading transcription file ${transcriptionFilename} for ${audioFile} failed`);
|
|
9883
|
+
}
|
|
9884
|
+
if (csvCache[audioFile]) {
|
|
9885
|
+
return csvCache[audioFile];
|
|
9886
|
+
}
|
|
9887
|
+
const audioFileComponents = audioFile.split('/');
|
|
9888
|
+
for (let parentIndex = audioFileComponents.length - 1; parentIndex >= 0; parentIndex--) {
|
|
9889
|
+
const csvDirectory = audioFileComponents.slice(0, parentIndex);
|
|
9890
|
+
const csvFilename = path.join(...csvDirectory, 'transcript.csv');
|
|
9891
|
+
const csvFilenameAbs = path.resolve(baseDir, csvFilename);
|
|
9892
|
+
try {
|
|
9893
|
+
if (fs.existsSync(csvFilenameAbs)) {
|
|
9894
|
+
const records = csvParseSync(fs.readFileSync(csvFilenameAbs, {
|
|
9895
|
+
encoding: 'utf-8'
|
|
9896
|
+
}).trim(), {
|
|
9897
|
+
columns: ['filename', 'transcription'],
|
|
9898
|
+
delimiter: [',', ';', ':', '\t'],
|
|
9899
|
+
trim: true,
|
|
9900
|
+
skip_empty_lines: true
|
|
9901
|
+
});
|
|
9902
|
+
if (records && records.length > 0) {
|
|
9903
|
+
for (const record of records) {
|
|
9904
|
+
const fnKey = path.join(...csvDirectory, record.filename);
|
|
9905
|
+
csvCache[fnKey] = record.transcription;
|
|
9906
|
+
}
|
|
9907
|
+
}
|
|
9908
|
+
}
|
|
9909
|
+
} catch (err) {
|
|
9910
|
+
if (onError) onError(`Transcription CSV File ${csvFilenameAbs} not readable: ${err.message}`);
|
|
9911
|
+
throw new Error(`Reading transcription CSV file for ${csvFilename} failed`);
|
|
9912
|
+
}
|
|
9913
|
+
if (csvCache[audioFile]) {
|
|
9914
|
+
return csvCache[audioFile];
|
|
9915
|
+
}
|
|
9916
|
+
}
|
|
9917
|
+
return null;
|
|
9918
|
+
};
|
|
9919
|
+
|
|
9920
|
+
/**
|
|
9921
|
+
* Derive transcription text from audio filename (basename without extension, underscores/hyphens → spaces).
|
|
9922
|
+
* @param {string} audioFile - Path or filename of audio file
|
|
9923
|
+
* @returns {string}
|
|
9924
|
+
*/
|
|
9925
|
+
var transcriptionFromFilename = audioFile => {
|
|
9926
|
+
const filename = path.basename(audioFile, path.extname(audioFile));
|
|
9927
|
+
return filename.split(/[_-]+/).join(' ');
|
|
9928
|
+
};
|
|
9792
9929
|
var hasWaitForBotTimeout = transciptError => {
|
|
9793
9930
|
if (!transciptError) {
|
|
9794
9931
|
return false;
|
|
@@ -9800,6 +9937,8 @@ var hasWaitForBotTimeout = transciptError => {
|
|
|
9800
9937
|
return str.indexOf(': error waiting for bot - Bot did not respond within') > 0;
|
|
9801
9938
|
};
|
|
9802
9939
|
var TranscriptUtils = {
|
|
9940
|
+
findTranscription: findTranscription,
|
|
9941
|
+
transcriptionFromFilename: transcriptionFromFilename,
|
|
9803
9942
|
hasWaitForBotTimeout: hasWaitForBotTimeout
|
|
9804
9943
|
};
|
|
9805
9944
|
|