botium-core 1.15.9 → 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.9";
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,
@@ -6156,6 +6197,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
6156
6197
  onBotStart: this.scriptingEvents.onBotStart.bind(this),
6157
6198
  onBotPrepare: this.scriptingEvents.onBotPrepare.bind(this),
6158
6199
  onBotEnd: this.scriptingEvents.onBotEnd.bind(this),
6200
+ executeBotStep: this.scriptingEvents.executeBotStep.bind(this),
6159
6201
  setUserInput: this.scriptingEvents.setUserInput.bind(this),
6160
6202
  fail: this.scriptingEvents.fail && this.scriptingEvents.fail.bind(this)
6161
6203
  }
@@ -6676,7 +6718,11 @@ var ScriptingProvider_1 = class ScriptingProvider {
6676
6718
  // use skip and keep, or justHeader
6677
6719
  justHeader: false,
6678
6720
  // drop unwanted convos
6679
- convoFilter: null
6721
+ convoFilter: null,
6722
+ mediaInput: {
6723
+ // MESSAGE_TEXT_FROM_FILENAME or MESSAGE_TEXT_FROM_TRANSCRIPTION or falsy
6724
+ messageTextMode: null
6725
+ }
6680
6726
  }, options);
6681
6727
  const expandedConvos = [];
6682
6728
  // The globalContext is going to keep the data even if the Object.assign which happening to create the myContext in _expandConvo function
@@ -6714,7 +6760,11 @@ var ScriptingProvider_1 = class ScriptingProvider {
6714
6760
  ExpandConvosIterable(options = {}) {
6715
6761
  options = Object.assign({
6716
6762
  // drop unwanted convos
6717
- convoFilter: null
6763
+ convoFilter: null,
6764
+ mediaInput: {
6765
+ // MESSAGE_TEXT_FROM_FILENAME or MESSAGE_TEXT_FROM_TRANSCRIPTION or falsy
6766
+ messageTextMode: null
6767
+ }
6718
6768
  }, options);
6719
6769
  // The globalContext is going to keep the data even if the Object.assign which happening to create the myContext in _expandConvo function
6720
6770
  const context = {
@@ -6861,7 +6911,8 @@ var ScriptingProvider_1 = class ScriptingProvider {
6861
6911
  const expandedUserInputs = userInput.expandConvo({
6862
6912
  convo: currentConvo,
6863
6913
  convoStep: currentStep,
6864
- args: ui.args
6914
+ args: ui.args,
6915
+ options
6865
6916
  });
6866
6917
  if (expandedUserInputs && expandedUserInputs.length > 0) {
6867
6918
  // let sampleinputs = expandedUserInputs
@@ -6873,9 +6924,16 @@ var ScriptingProvider_1 = class ScriptingProvider {
6873
6924
  }
6874
6925
  };
6875
6926
  const processSampleInput = function* (sampleinput, length, index, myContext, uiIndex) {
6927
+ const {
6928
+ messageText,
6929
+ ...userInput
6930
+ } = sampleinput;
6876
6931
  const currentStepsStack = convoStepsStack.slice();
6877
6932
  const currentStepMod = lodash.cloneDeep(currentStep);
6878
- currentStepMod.userInputs[uiIndex] = sampleinput;
6933
+ currentStepMod.userInputs[uiIndex] = userInput;
6934
+ if (messageText) {
6935
+ currentStepMod.messageText = messageText;
6936
+ }
6879
6937
  currentStepsStack.push(currentStepMod);
6880
6938
  const currentConvoLabeled = lodash.cloneDeep(currentConvo);
6881
6939
  if (length > 1) {
@@ -9795,6 +9853,79 @@ Plugins.PLUGIN_TYPE_LOGICHOOK;
9795
9853
  Plugins.PLUGIN_TYPE_USERINPUT;
9796
9854
  Plugins.TYPE_TO_PREFIX;
9797
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
+ };
9798
9929
  var hasWaitForBotTimeout = transciptError => {
9799
9930
  if (!transciptError) {
9800
9931
  return false;
@@ -9806,6 +9937,8 @@ var hasWaitForBotTimeout = transciptError => {
9806
9937
  return str.indexOf(': error waiting for bot - Bot did not respond within') > 0;
9807
9938
  };
9808
9939
  var TranscriptUtils = {
9940
+ findTranscription: findTranscription,
9941
+ transcriptionFromFilename: transcriptionFromFilename,
9809
9942
  hasWaitForBotTimeout: hasWaitForBotTimeout
9810
9943
  };
9811
9944