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-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.8";
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
- const localHooks = (logicHooks || []).filter(l => this.logicHooks[l.name][hookType]);
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] = sampleinput;
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(caps[capKey])) {
9533
- caps[capKey] = caps[capKey].toString();
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