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.
@@ -77,7 +77,7 @@ var express__default = /*#__PURE__*/_interopDefaultLegacy(express);
77
77
  var bodyParser__default = /*#__PURE__*/_interopDefaultLegacy(bodyParser);
78
78
 
79
79
  var name = "botium-core";
80
- var version$1 = "1.15.9";
80
+ var version$1 = "1.15.10";
81
81
  var description = "The Selenium for Chatbots";
82
82
  var main = "index.js";
83
83
  var module$1 = "dist/botium-es.js";
@@ -3039,6 +3039,7 @@ class Convo$6 {
3039
3039
  }
3040
3040
  async runConversation(container, scriptingMemory, transcript) {
3041
3041
  const transcriptSteps = [];
3042
+ transcript.steps = transcriptSteps;
3042
3043
  try {
3043
3044
  let lastMeConvoStep = null;
3044
3045
  let botMsg = null;
@@ -3223,6 +3224,21 @@ class Convo$6 {
3223
3224
  throw failErr;
3224
3225
  }
3225
3226
  } else if (convoStep.sender === 'bot') {
3227
+ if (this.scriptingEvents.executeBotStep) {
3228
+ const executeBotStepResult = await this.scriptingEvents.executeBotStep({
3229
+ convo: this,
3230
+ convoStep,
3231
+ container,
3232
+ scriptingMemory,
3233
+ transcript,
3234
+ transcriptStep,
3235
+ transcriptSteps
3236
+ });
3237
+ if (executeBotStepResult) {
3238
+ skipTranscriptStep = true;
3239
+ continue;
3240
+ }
3241
+ }
3226
3242
  if (waitForBotSays) {
3227
3243
  botMsg = null;
3228
3244
  } else {
@@ -5796,6 +5812,31 @@ var ScriptingProvider_1 = class ScriptingProvider {
5796
5812
  ...rest
5797
5813
  });
5798
5814
  },
5815
+ executeBotStep: ({
5816
+ convo,
5817
+ convoStep,
5818
+ container,
5819
+ scriptingMemory,
5820
+ ...rest
5821
+ }) => {
5822
+ const logicHooks = convoStep?.logicHooks || [];
5823
+ const executeBotStepHooks = logicHooks.filter(l => this.logicHooks[l.name] && typeof this.logicHooks[l.name].executeBotStep === 'function');
5824
+ if (executeBotStepHooks.length > 1) {
5825
+ 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.`);
5826
+ }
5827
+ if (executeBotStepHooks.length === 1) {
5828
+ const lh = executeBotStepHooks[0];
5829
+ return this.logicHooks[lh.name].executeBotStep({
5830
+ convo,
5831
+ convoStep,
5832
+ scriptingMemory,
5833
+ container,
5834
+ args: ScriptingMemory.applyToArgs(lh.args, scriptingMemory, container.caps),
5835
+ ...rest
5836
+ });
5837
+ }
5838
+ return null;
5839
+ },
5799
5840
  assertConvoBegin: ({
5800
5841
  convo,
5801
5842
  convoStep,
@@ -6198,6 +6239,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
6198
6239
  onBotStart: this.scriptingEvents.onBotStart.bind(this),
6199
6240
  onBotPrepare: this.scriptingEvents.onBotPrepare.bind(this),
6200
6241
  onBotEnd: this.scriptingEvents.onBotEnd.bind(this),
6242
+ executeBotStep: this.scriptingEvents.executeBotStep.bind(this),
6201
6243
  setUserInput: this.scriptingEvents.setUserInput.bind(this),
6202
6244
  fail: this.scriptingEvents.fail && this.scriptingEvents.fail.bind(this)
6203
6245
  }
@@ -6718,7 +6760,11 @@ var ScriptingProvider_1 = class ScriptingProvider {
6718
6760
  // use skip and keep, or justHeader
6719
6761
  justHeader: false,
6720
6762
  // drop unwanted convos
6721
- convoFilter: null
6763
+ convoFilter: null,
6764
+ mediaInput: {
6765
+ // MESSAGE_TEXT_FROM_FILENAME or MESSAGE_TEXT_FROM_TRANSCRIPTION or falsy
6766
+ messageTextMode: null
6767
+ }
6722
6768
  }, options);
6723
6769
  const expandedConvos = [];
6724
6770
  // The globalContext is going to keep the data even if the Object.assign which happening to create the myContext in _expandConvo function
@@ -6756,7 +6802,11 @@ var ScriptingProvider_1 = class ScriptingProvider {
6756
6802
  ExpandConvosIterable(options = {}) {
6757
6803
  options = Object.assign({
6758
6804
  // drop unwanted convos
6759
- convoFilter: null
6805
+ convoFilter: null,
6806
+ mediaInput: {
6807
+ // MESSAGE_TEXT_FROM_FILENAME or MESSAGE_TEXT_FROM_TRANSCRIPTION or falsy
6808
+ messageTextMode: null
6809
+ }
6760
6810
  }, options);
6761
6811
  // The globalContext is going to keep the data even if the Object.assign which happening to create the myContext in _expandConvo function
6762
6812
  const context = {
@@ -6903,7 +6953,8 @@ var ScriptingProvider_1 = class ScriptingProvider {
6903
6953
  const expandedUserInputs = userInput.expandConvo({
6904
6954
  convo: currentConvo,
6905
6955
  convoStep: currentStep,
6906
- args: ui.args
6956
+ args: ui.args,
6957
+ options
6907
6958
  });
6908
6959
  if (expandedUserInputs && expandedUserInputs.length > 0) {
6909
6960
  // let sampleinputs = expandedUserInputs
@@ -6915,9 +6966,16 @@ var ScriptingProvider_1 = class ScriptingProvider {
6915
6966
  }
6916
6967
  };
6917
6968
  const processSampleInput = function* (sampleinput, length, index, myContext, uiIndex) {
6969
+ const {
6970
+ messageText,
6971
+ ...userInput
6972
+ } = sampleinput;
6918
6973
  const currentStepsStack = convoStepsStack.slice();
6919
6974
  const currentStepMod = lodash__default["default"].cloneDeep(currentStep);
6920
- currentStepMod.userInputs[uiIndex] = sampleinput;
6975
+ currentStepMod.userInputs[uiIndex] = userInput;
6976
+ if (messageText) {
6977
+ currentStepMod.messageText = messageText;
6978
+ }
6921
6979
  currentStepsStack.push(currentStepMod);
6922
6980
  const currentConvoLabeled = lodash__default["default"].cloneDeep(currentConvo);
6923
6981
  if (length > 1) {
@@ -9837,6 +9895,79 @@ Plugins.PLUGIN_TYPE_LOGICHOOK;
9837
9895
  Plugins.PLUGIN_TYPE_USERINPUT;
9838
9896
  Plugins.TYPE_TO_PREFIX;
9839
9897
 
9898
+ const {
9899
+ parse: csvParseSync
9900
+ } = sync__default["default"];
9901
+
9902
+ /**
9903
+ * Find transcription for an audio file: .txt same base name, or transcript.csv in parent dirs.
9904
+ * @param {string} baseDir - Base directory for resolving paths
9905
+ * @param {string} audioFile - Relative path to audio file
9906
+ * @param {object} [options] - Optional: { csvCache: {}, onError: (msg) => {} }
9907
+ * @returns {string|null} Transcription text or null
9908
+ */
9909
+ var findTranscription = (baseDir, audioFile, options = {}) => {
9910
+ const {
9911
+ csvCache = {},
9912
+ onError
9913
+ } = options;
9914
+ const transcriptionFilename = `${audioFile.substring(0, audioFile.lastIndexOf('.'))}.txt`;
9915
+ const transcriptionFilenameAbs = path__default["default"].resolve(baseDir, transcriptionFilename);
9916
+ try {
9917
+ if (fs__default["default"].existsSync(transcriptionFilenameAbs)) {
9918
+ return fs__default["default"].readFileSync(transcriptionFilenameAbs, {
9919
+ encoding: 'utf-8'
9920
+ }).trim();
9921
+ }
9922
+ } catch (err) {
9923
+ if (onError) onError(`Transcription File ${transcriptionFilenameAbs} not readable: ${err.message}`);
9924
+ throw new Error(`Reading transcription file ${transcriptionFilename} for ${audioFile} failed`);
9925
+ }
9926
+ if (csvCache[audioFile]) {
9927
+ return csvCache[audioFile];
9928
+ }
9929
+ const audioFileComponents = audioFile.split('/');
9930
+ for (let parentIndex = audioFileComponents.length - 1; parentIndex >= 0; parentIndex--) {
9931
+ const csvDirectory = audioFileComponents.slice(0, parentIndex);
9932
+ const csvFilename = path__default["default"].join(...csvDirectory, 'transcript.csv');
9933
+ const csvFilenameAbs = path__default["default"].resolve(baseDir, csvFilename);
9934
+ try {
9935
+ if (fs__default["default"].existsSync(csvFilenameAbs)) {
9936
+ const records = csvParseSync(fs__default["default"].readFileSync(csvFilenameAbs, {
9937
+ encoding: 'utf-8'
9938
+ }).trim(), {
9939
+ columns: ['filename', 'transcription'],
9940
+ delimiter: [',', ';', ':', '\t'],
9941
+ trim: true,
9942
+ skip_empty_lines: true
9943
+ });
9944
+ if (records && records.length > 0) {
9945
+ for (const record of records) {
9946
+ const fnKey = path__default["default"].join(...csvDirectory, record.filename);
9947
+ csvCache[fnKey] = record.transcription;
9948
+ }
9949
+ }
9950
+ }
9951
+ } catch (err) {
9952
+ if (onError) onError(`Transcription CSV File ${csvFilenameAbs} not readable: ${err.message}`);
9953
+ throw new Error(`Reading transcription CSV file for ${csvFilename} failed`);
9954
+ }
9955
+ if (csvCache[audioFile]) {
9956
+ return csvCache[audioFile];
9957
+ }
9958
+ }
9959
+ return null;
9960
+ };
9961
+
9962
+ /**
9963
+ * Derive transcription text from audio filename (basename without extension, underscores/hyphens → spaces).
9964
+ * @param {string} audioFile - Path or filename of audio file
9965
+ * @returns {string}
9966
+ */
9967
+ var transcriptionFromFilename = audioFile => {
9968
+ const filename = path__default["default"].basename(audioFile, path__default["default"].extname(audioFile));
9969
+ return filename.split(/[_-]+/).join(' ');
9970
+ };
9840
9971
  var hasWaitForBotTimeout = transciptError => {
9841
9972
  if (!transciptError) {
9842
9973
  return false;
@@ -9848,6 +9979,8 @@ var hasWaitForBotTimeout = transciptError => {
9848
9979
  return str.indexOf(': error waiting for bot - Bot did not respond within') > 0;
9849
9980
  };
9850
9981
  var TranscriptUtils = {
9982
+ findTranscription: findTranscription,
9983
+ transcriptionFromFilename: transcriptionFromFilename,
9851
9984
  hasWaitForBotTimeout: hasWaitForBotTimeout
9852
9985
  };
9853
9986