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.
Files changed (85) hide show
  1. package/dist/botium-cjs.js +215 -55
  2. package/dist/botium-cjs.js.map +1 -1
  3. package/dist/botium-es.js +215 -54
  4. package/dist/botium-es.js.map +1 -1
  5. package/package.json +35 -40
  6. package/src/BotDriver.js +1 -1
  7. package/src/Events.js +1 -3
  8. package/src/containers/GridContainer.js +0 -4
  9. package/src/helpers/TranscriptUtils.js +66 -0
  10. package/src/scripting/Convo.js +9 -0
  11. package/src/scripting/ScriptingProvider.js +36 -5
  12. package/src/scripting/logichook/userinput/MediaInput.js +10 -2
  13. package/src/utils/boolean.js +39 -0
  14. package/test/compiler/compilercsv.spec.js +34 -0
  15. package/test/compiler/compilermarkdown.spec.js +11 -0
  16. package/test/compiler/compilertxt.spec.js +21 -0
  17. package/test/compiler/compilerxlsx.spec.js +27 -0
  18. package/test/compiler/precompilerjson.spec.js +1 -0
  19. package/test/compiler/precompilermarkdownrasa.spec.js +1 -0
  20. package/test/connectors/pluginconnectorcontainer.spec.js +1 -0
  21. package/test/connectors/simplerest.spec.js +3 -1
  22. package/test/convo/failure.spec.js +1 -0
  23. package/test/convo/fillAndApplyScriptingMemory.spec.js +56 -0
  24. package/test/convo/partialconvo.spec.js +3 -0
  25. package/test/convo/retry.spec.js +9 -0
  26. package/test/convo/retryasserter.spec.js +9 -0
  27. package/test/convo/transcript.spec.js +33 -0
  28. package/test/convo/tree.spec.js +5 -0
  29. package/test/driver/capabilities.spec.js +16 -0
  30. package/test/helpers/capabilitiesutils.spec.js +8 -0
  31. package/test/helpers/transcriptutils.spec.js +1 -0
  32. package/test/hooks/customhooks.spec.js +3 -0
  33. package/test/logichooks/hookfromsrc.spec.js +3 -0
  34. package/test/logichooks/textfromhook.spec.js +1 -0
  35. package/test/plugins/plugins.spec.js +3 -0
  36. package/test/scripting/asserters/buttonsAsserter.spec.js +15 -0
  37. package/test/scripting/asserters/cardsAsserter.spec.js +12 -0
  38. package/test/scripting/asserters/convoStepParameters.spec.js +11 -0
  39. package/test/scripting/asserters/entitiesAsserter.spec.js +1 -0
  40. package/test/scripting/asserters/entityValuesAsserter.spec.js +7 -0
  41. package/test/scripting/asserters/formsAsserter.spec.js +10 -0
  42. package/test/scripting/asserters/intentAsserter.spec.js +4 -0
  43. package/test/scripting/asserters/intentUniqueAsserter.spec.js +2 -0
  44. package/test/scripting/asserters/jsonpathAsserter.spec.js +25 -0
  45. package/test/scripting/asserters/mediaAsserter.spec.js +20 -0
  46. package/test/scripting/asserters/responseLengthAsserter.spec.js +4 -0
  47. package/test/scripting/asserters/textAsserter.spec.js +1 -0
  48. package/test/scripting/asserters/textContainsAllAsserter.spec.js +1 -0
  49. package/test/scripting/asserters/textContainsAnyAsserter.spec.js +1 -0
  50. package/test/scripting/asserters/textEqualsAsserter.spec.js +1 -0
  51. package/test/scripting/asserters/textRegexpAllAsserter.spec.js +1 -0
  52. package/test/scripting/asserters/textRegexpAnyAsserter.spec.js +1 -0
  53. package/test/scripting/asserters/textWildcardAllAsserter.spec.js +1 -0
  54. package/test/scripting/asserters/textWildcardAnyAsserter.spec.js +1 -0
  55. package/test/scripting/asserters/textWildcardExactAllAsserter.spec.js +1 -0
  56. package/test/scripting/asserters/textWildcardExactAnyAsserter.spec.js +1 -0
  57. package/test/scripting/asserters/werAsserter.spec.js +6 -0
  58. package/test/scripting/logichooks/customConditionalStepLogicHook.spec.js +2 -0
  59. package/test/scripting/logichooks/localvsglobal.spec.js +1 -0
  60. package/test/scripting/logichooks/pauseLogic.spec.js +4 -0
  61. package/test/scripting/logichooks/setClearScriptingMemory.spec.js +3 -0
  62. package/test/scripting/logichooks/updateCustom.spec.js +2 -0
  63. package/test/scripting/matching/matchingmode.spec.js +48 -0
  64. package/test/scripting/scriptingModificator.spec.js +1 -0
  65. package/test/scripting/scriptingmemory/fillScriptingMemoryFromFile.spec.js +4 -0
  66. package/test/scripting/scriptingmemory/regexp.spec.js +1 -0
  67. package/test/scripting/scriptingmemory/useScriptingMemoryForAssertion.spec.js +3 -0
  68. package/test/scripting/txt/decompile.spec.js +20 -0
  69. package/test/scripting/userinputs/buttonInputConvos.spec.js +1 -0
  70. package/test/scripting/userinputs/defaultUserInputs.spec.js +13 -0
  71. package/test/scripting/userinputs/mediaInputConvos.spec.js +10 -0
  72. package/test/scripting/utteranceexpansion/associateByIndex.spec.js +2 -0
  73. package/test/security/allowUnsafe.spec.js +5 -0
  74. package/test/utils.spec.js +2 -0
  75. package/samples/postman/Botium Agent Sample.postman_collection.json +0 -834
  76. package/samples/postman/README.md +0 -5
  77. package/samples/postman/botiumFluent.js +0 -37
  78. package/src/grid/agent/AgentWorker.js +0 -204
  79. package/src/grid/agent/agent.js +0 -96
  80. package/src/grid/agent/agentworkerpool.js +0 -58
  81. package/src/grid/agent/routes.js +0 -353
  82. package/src/grid/agent/swagger.json +0 -327
  83. package/src/grid/agent/swaggerDef.json +0 -8
  84. package/src/grid/agent/views/index.html +0 -39
  85. package/test/grid/agent/client.js +0 -65
@@ -12,7 +12,6 @@ var sanitizeFilename = require('sanitize-filename');
12
12
  var moment = require('moment');
13
13
  var randomatic = require('randomatic');
14
14
  var lodash = require('lodash');
15
- var boolean$1 = require('boolean');
16
15
  var events = require('events');
17
16
  var debug$o = require('debug');
18
17
  var isClass = require('is-class');
@@ -50,7 +49,6 @@ var sanitizeFilename__default = /*#__PURE__*/_interopDefaultLegacy(sanitizeFilen
50
49
  var moment__default = /*#__PURE__*/_interopDefaultLegacy(moment);
51
50
  var randomatic__default = /*#__PURE__*/_interopDefaultLegacy(randomatic);
52
51
  var lodash__default = /*#__PURE__*/_interopDefaultLegacy(lodash);
53
- var boolean__default = /*#__PURE__*/_interopDefaultLegacy(boolean$1);
54
52
  var events__default = /*#__PURE__*/_interopDefaultLegacy(events);
55
53
  var debug__default = /*#__PURE__*/_interopDefaultLegacy(debug$o);
56
54
  var isClass__default = /*#__PURE__*/_interopDefaultLegacy(isClass);
@@ -76,8 +74,49 @@ var undici__default = /*#__PURE__*/_interopDefaultLegacy(undici);
76
74
  var express__default = /*#__PURE__*/_interopDefaultLegacy(express);
77
75
  var bodyParser__default = /*#__PURE__*/_interopDefaultLegacy(bodyParser);
78
76
 
77
+ /**
78
+ * Converts a value to a boolean.
79
+ * Similar to the 'boolean' npm package implementation.
80
+ *
81
+ * @param {*} value - The value to convert to boolean
82
+ * @returns {boolean} The boolean representation of the value
83
+ */
84
+ function boolean$1(value) {
85
+ // Handle null and undefined
86
+ if (value == null) {
87
+ return false;
88
+ }
89
+
90
+ // Handle boolean values
91
+ if (typeof value === 'boolean') {
92
+ return value;
93
+ }
94
+
95
+ // Handle numbers
96
+ if (typeof value === 'number') {
97
+ return value !== 0 && !isNaN(value);
98
+ }
99
+
100
+ // Handle strings
101
+ if (typeof value === 'string') {
102
+ const normalized = value.trim().toLowerCase();
103
+ if (normalized === 'true' || normalized === 'yes' || normalized === 'on' || normalized === '1') {
104
+ return true;
105
+ }
106
+ if (normalized === 'false' || normalized === 'no' || normalized === 'off' || normalized === '0' || normalized === '') {
107
+ return false;
108
+ }
109
+ }
110
+
111
+ // For all other values, use JavaScript's truthiness
112
+ return Boolean(value);
113
+ }
114
+ var boolean_1 = {
115
+ boolean: boolean$1
116
+ };
117
+
79
118
  var name = "botium-core";
80
- var version$1 = "1.15.9";
119
+ var version$1 = "1.15.12";
81
120
  var description = "The Selenium for Chatbots";
82
121
  var main = "index.js";
83
122
  var module$1 = "dist/botium-es.js";
@@ -90,8 +129,6 @@ var scripts = {
90
129
  eslint: "eslint \"./src/**/*.js\" \"./test/**/*.js\"",
91
130
  "eslint-fix": "eslint --fix \"./src/**/*.js\" \"./test/**/*.js\"",
92
131
  newpatch: "npm version patch",
93
- agent: "node ./src/grid/agent/agent.js",
94
- "agent-jsdoc": "swagger-jsdoc -d ./src/grid/agent/swaggerDef.json -o ./src/grid/agent/swagger.json ./src/grid/agent/routes.js",
95
132
  link: "npm link botium-connector-dialogflow botium-connector-webdriverio botium-connector-directline3 botium-connector-watson botium-connector-alexa-smapi botium-connector-echo",
96
133
  test: "cross-env NODE_PATH=\"./test/plugins/plugindir/fromfolder:./test/plugins/plugindir/fromfile:./test/security/resources\" mocha \"./test/**/*.spec.js\"",
97
134
  "coverage:report": "nyc report --reporter=lcov npm test",
@@ -108,66 +145,63 @@ var bugs = {
108
145
  };
109
146
  var homepage = "https://www.botium.ai";
110
147
  var dependencies = {
111
- "@babel/runtime": "^7.23.9",
112
- async: "^3.2.5",
113
- "body-parser": "^1.20.2",
114
- boolean: "^3.2.0",
148
+ "@babel/runtime": "^7.28.6",
149
+ async: "^3.2.6",
150
+ "body-parser": "^2.2.2",
115
151
  bottleneck: "^2.19.5",
116
- "csv-parse": "^5.5.3",
117
- debug: "^4.3.4",
118
- express: "^4.18.2",
152
+ "csv-parse": "^6.1.0",
153
+ debug: "^4.4.3",
154
+ express: "^5.2.1",
119
155
  globby: "11.0.4",
120
- ioredis: "^5.3.2",
156
+ ioredis: "^5.10.0",
121
157
  "is-class": "^0.0.9",
122
158
  "is-json": "^2.0.1",
123
- jsonpath: "^1.1.1",
124
- lodash: "^4.17.21",
125
- "markdown-it": "^14.0.0",
126
- "mime-types": "^2.1.35",
159
+ jsonpath: "^1.3.0",
160
+ lodash: "^4.17.23",
161
+ "markdown-it": "^14.1.1",
162
+ "mime-types": "^3.0.2",
127
163
  mkdirp: "^3.0.1",
128
164
  moment: "^2.30.1",
129
- "moment-timezone": "^0.5.45",
165
+ "moment-timezone": "^0.6.0",
130
166
  mustache: "^4.2.0",
131
167
  "promise-retry": "^2.0.1",
132
168
  "promise.allsettled": "^1.0.7",
133
169
  randomatic: "^3.1.1",
134
- rimraf: "^5.0.5",
170
+ rimraf: "^6.1.3",
135
171
  "sanitize-filename": "^1.6.3",
136
172
  slugify: "^1.6.6",
137
- "socket.io": "^4.7.4",
138
- "socket.io-client": "^4.7.4",
173
+ "socket.io": "^4.8.3",
174
+ "socket.io-client": "^4.8.3",
139
175
  "socketio-auth": "^0.1.1",
140
- "swagger-jsdoc": "^6.2.8",
141
- "swagger-ui-express": "^5.0.0",
142
- tinyglobby: "^0.2.10",
143
- undici: "^6.21.0",
176
+ tinyglobby: "^0.2.15",
177
+ undici: "^7.22.0",
144
178
  uuid: "^9.0.1",
145
179
  "word-error-rate": "0.0.7",
146
180
  "write-yaml": "^1.0.0",
147
181
  xlsx: "^0.18.5",
148
- xregexp: "^5.1.1",
149
- yaml: "^2.3.4"
182
+ xregexp: "^5.1.2",
183
+ yaml: "^2.8.2"
150
184
  };
151
185
  var devDependencies = {
152
- "@babel/core": "^7.23.9",
153
- "@babel/node": "^7.23.9",
154
- "@babel/plugin-transform-runtime": "^7.23.9",
155
- "@babel/preset-env": "^7.23.9",
186
+ "@babel/core": "^7.29.0",
187
+ "@babel/node": "^7.29.0",
188
+ "@babel/plugin-transform-runtime": "^7.29.0",
189
+ "@babel/preset-env": "^7.29.0",
156
190
  chai: "4.3.10",
157
- "chai-as-promised": "^7.1.1",
158
- "cross-env": "^7.0.3",
159
- eslint: "^8.56.0",
191
+ "chai-as-promised": "^7.1.2",
192
+ "cross-env": "^10.1.0",
193
+ eslint: "^8.57.1",
160
194
  "eslint-config-standard": "^17.1.0",
161
- "eslint-plugin-import": "^2.29.1",
162
- "eslint-plugin-mocha": "^10.2.0",
195
+ "eslint-plugin-import": "^2.32.0",
196
+ "eslint-plugin-mocha": "^10.5.0",
163
197
  "eslint-plugin-n": "^16.6.2",
164
- "eslint-plugin-promise": "^6.1.1",
198
+ "eslint-plugin-promise": "^6.6.0",
165
199
  "eslint-plugin-standard": "^4.1.0",
166
- mocha: "^10.3.0",
167
- nock: "^14.0.0-beta.19",
168
- "npm-check-updates": "^16.14.15",
169
- nyc: "^15.1.0",
170
- rollup: "2.79.1",
200
+ mocha: "^11.7.5",
201
+ nock: "^14.0.11",
202
+ "npm-check-updates": "^19.6.3",
203
+ nyc: "^18.0.0",
204
+ rollup: "2.80.0",
171
205
  "rollup-plugin-babel": "^4.4.0",
172
206
  "rollup-plugin-commonjs": "^10.1.0",
173
207
  "rollup-plugin-json": "^4.0.0",
@@ -901,9 +935,7 @@ var Events = {
901
935
  MESSAGE_RECEIVEDFROMBOT: 'MESSAGE_RECEIVEDFROMBOT',
902
936
  MESSAGE_RECEIVEFROMBOT_ERROR: 'MESSAGE_RECEIVEFROMBOT_ERROR',
903
937
  MESSAGE_ATTACHMENT: 'MESSAGE_ATTACHMENT',
904
- MESSAGE_TRANSCRIPT: 'MESSAGE_TRANSCRIPT',
905
- // Botium Agent Events
906
- TOOMUCHWORKERS_ERROR: 'TOOMUCHWORKERS_ERROR'
938
+ MESSAGE_TRANSCRIPT: 'MESSAGE_TRANSCRIPT'
907
939
  };
908
940
  Events.CONTAINER_BUILDING;
909
941
  Events.CONTAINER_BUILT;
@@ -925,7 +957,6 @@ Events.MESSAGE_RECEIVEDFROMBOT;
925
957
  Events.MESSAGE_RECEIVEFROMBOT_ERROR;
926
958
  Events.MESSAGE_ATTACHMENT;
927
959
  Events.MESSAGE_TRANSCRIPT;
928
- Events.TOOMUCHWORKERS_ERROR;
929
960
 
930
961
  function commonjsRequire () {
931
962
  throw new Error('Dynamic requires are not currently supported by rollup-plugin-commonjs');
@@ -3039,6 +3070,7 @@ class Convo$6 {
3039
3070
  }
3040
3071
  async runConversation(container, scriptingMemory, transcript) {
3041
3072
  const transcriptSteps = [];
3073
+ transcript.steps = transcriptSteps;
3042
3074
  try {
3043
3075
  let lastMeConvoStep = null;
3044
3076
  let botMsg = null;
@@ -3223,6 +3255,21 @@ class Convo$6 {
3223
3255
  throw failErr;
3224
3256
  }
3225
3257
  } else if (convoStep.sender === 'bot') {
3258
+ if (this.scriptingEvents.executeBotStep) {
3259
+ const executeBotStepResult = await this.scriptingEvents.executeBotStep({
3260
+ convo: this,
3261
+ convoStep,
3262
+ container,
3263
+ scriptingMemory,
3264
+ transcript,
3265
+ transcriptStep,
3266
+ transcriptSteps
3267
+ });
3268
+ if (executeBotStepResult) {
3269
+ skipTranscriptStep = true;
3270
+ continue;
3271
+ }
3272
+ }
3226
3273
  if (waitForBotSays) {
3227
3274
  botMsg = null;
3228
3275
  } else {
@@ -5796,6 +5843,31 @@ var ScriptingProvider_1 = class ScriptingProvider {
5796
5843
  ...rest
5797
5844
  });
5798
5845
  },
5846
+ executeBotStep: ({
5847
+ convo,
5848
+ convoStep,
5849
+ container,
5850
+ scriptingMemory,
5851
+ ...rest
5852
+ }) => {
5853
+ const logicHooks = convoStep?.logicHooks || [];
5854
+ const executeBotStepHooks = logicHooks.filter(l => this.logicHooks[l.name] && typeof this.logicHooks[l.name].executeBotStep === 'function');
5855
+ if (executeBotStepHooks.length > 1) {
5856
+ 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.`);
5857
+ }
5858
+ if (executeBotStepHooks.length === 1) {
5859
+ const lh = executeBotStepHooks[0];
5860
+ return this.logicHooks[lh.name].executeBotStep({
5861
+ convo,
5862
+ convoStep,
5863
+ scriptingMemory,
5864
+ container,
5865
+ args: ScriptingMemory.applyToArgs(lh.args, scriptingMemory, container.caps),
5866
+ ...rest
5867
+ });
5868
+ }
5869
+ return null;
5870
+ },
5799
5871
  assertConvoBegin: ({
5800
5872
  convo,
5801
5873
  convoStep,
@@ -6198,6 +6270,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
6198
6270
  onBotStart: this.scriptingEvents.onBotStart.bind(this),
6199
6271
  onBotPrepare: this.scriptingEvents.onBotPrepare.bind(this),
6200
6272
  onBotEnd: this.scriptingEvents.onBotEnd.bind(this),
6273
+ executeBotStep: this.scriptingEvents.executeBotStep.bind(this),
6201
6274
  setUserInput: this.scriptingEvents.setUserInput.bind(this),
6202
6275
  fail: this.scriptingEvents.fail && this.scriptingEvents.fail.bind(this)
6203
6276
  }
@@ -6718,7 +6791,11 @@ var ScriptingProvider_1 = class ScriptingProvider {
6718
6791
  // use skip and keep, or justHeader
6719
6792
  justHeader: false,
6720
6793
  // drop unwanted convos
6721
- convoFilter: null
6794
+ convoFilter: null,
6795
+ mediaInput: {
6796
+ // MESSAGE_TEXT_FROM_FILENAME or MESSAGE_TEXT_FROM_TRANSCRIPTION or falsy
6797
+ messageTextMode: null
6798
+ }
6722
6799
  }, options);
6723
6800
  const expandedConvos = [];
6724
6801
  // The globalContext is going to keep the data even if the Object.assign which happening to create the myContext in _expandConvo function
@@ -6756,7 +6833,11 @@ var ScriptingProvider_1 = class ScriptingProvider {
6756
6833
  ExpandConvosIterable(options = {}) {
6757
6834
  options = Object.assign({
6758
6835
  // drop unwanted convos
6759
- convoFilter: null
6836
+ convoFilter: null,
6837
+ mediaInput: {
6838
+ // MESSAGE_TEXT_FROM_FILENAME or MESSAGE_TEXT_FROM_TRANSCRIPTION or falsy
6839
+ messageTextMode: null
6840
+ }
6760
6841
  }, options);
6761
6842
  // The globalContext is going to keep the data even if the Object.assign which happening to create the myContext in _expandConvo function
6762
6843
  const context = {
@@ -6903,7 +6984,8 @@ var ScriptingProvider_1 = class ScriptingProvider {
6903
6984
  const expandedUserInputs = userInput.expandConvo({
6904
6985
  convo: currentConvo,
6905
6986
  convoStep: currentStep,
6906
- args: ui.args
6987
+ args: ui.args,
6988
+ options
6907
6989
  });
6908
6990
  if (expandedUserInputs && expandedUserInputs.length > 0) {
6909
6991
  // let sampleinputs = expandedUserInputs
@@ -6915,9 +6997,16 @@ var ScriptingProvider_1 = class ScriptingProvider {
6915
6997
  }
6916
6998
  };
6917
6999
  const processSampleInput = function* (sampleinput, length, index, myContext, uiIndex) {
7000
+ const {
7001
+ messageText,
7002
+ ...userInput
7003
+ } = sampleinput;
6918
7004
  const currentStepsStack = convoStepsStack.slice();
6919
7005
  const currentStepMod = lodash__default["default"].cloneDeep(currentStep);
6920
- currentStepMod.userInputs[uiIndex] = sampleinput;
7006
+ currentStepMod.userInputs[uiIndex] = userInput;
7007
+ if (messageText) {
7008
+ currentStepMod.messageText = messageText;
7009
+ }
6921
7010
  currentStepsStack.push(currentStepMod);
6922
7011
  const currentConvoLabeled = lodash__default["default"].cloneDeep(currentConvo);
6923
7012
  if (length > 1) {
@@ -7751,10 +7840,6 @@ var GridContainer_1 = class GridContainer extends BaseContainer_1 {
7751
7840
  debug$6(`unauthorized ${err.message}`);
7752
7841
  socketComplete(`Grid Access not authorized: ${err.message}`);
7753
7842
  });
7754
- this.socket.on(Events.TOOMUCHWORKERS_ERROR, err => {
7755
- debug$6(`TOOMUCHWORKERS_ERROR ${err.message}`);
7756
- socketComplete(`Grid Access not possible: ${err.message}`);
7757
- });
7758
7843
  this.socket.on(Events.CONTAINER_BUILT, () => {
7759
7844
  debug$6(Events.CONTAINER_BUILT);
7760
7845
  socketComplete();
@@ -9385,7 +9470,7 @@ const {
9385
9470
  } = rimraf__default["default"];
9386
9471
  const {
9387
9472
  boolean
9388
- } = boolean__default["default"];
9473
+ } = boolean_1;
9389
9474
  const debug$1 = debug__default["default"]('botium-core-BotDriver');
9390
9475
  const {
9391
9476
  version
@@ -9837,6 +9922,79 @@ Plugins.PLUGIN_TYPE_LOGICHOOK;
9837
9922
  Plugins.PLUGIN_TYPE_USERINPUT;
9838
9923
  Plugins.TYPE_TO_PREFIX;
9839
9924
 
9925
+ const {
9926
+ parse: csvParseSync
9927
+ } = sync__default["default"];
9928
+
9929
+ /**
9930
+ * Find transcription for an audio file: .txt same base name, or transcript.csv in parent dirs.
9931
+ * @param {string} baseDir - Base directory for resolving paths
9932
+ * @param {string} audioFile - Relative path to audio file
9933
+ * @param {object} [options] - Optional: { csvCache: {}, onError: (msg) => {} }
9934
+ * @returns {string|null} Transcription text or null
9935
+ */
9936
+ var findTranscription = (baseDir, audioFile, options = {}) => {
9937
+ const {
9938
+ csvCache = {},
9939
+ onError
9940
+ } = options;
9941
+ const transcriptionFilename = `${audioFile.substring(0, audioFile.lastIndexOf('.'))}.txt`;
9942
+ const transcriptionFilenameAbs = path__default["default"].resolve(baseDir, transcriptionFilename);
9943
+ try {
9944
+ if (fs__default["default"].existsSync(transcriptionFilenameAbs)) {
9945
+ return fs__default["default"].readFileSync(transcriptionFilenameAbs, {
9946
+ encoding: 'utf-8'
9947
+ }).trim();
9948
+ }
9949
+ } catch (err) {
9950
+ if (onError) onError(`Transcription File ${transcriptionFilenameAbs} not readable: ${err.message}`);
9951
+ throw new Error(`Reading transcription file ${transcriptionFilename} for ${audioFile} failed`);
9952
+ }
9953
+ if (csvCache[audioFile]) {
9954
+ return csvCache[audioFile];
9955
+ }
9956
+ const audioFileComponents = audioFile.split('/');
9957
+ for (let parentIndex = audioFileComponents.length - 1; parentIndex >= 0; parentIndex--) {
9958
+ const csvDirectory = audioFileComponents.slice(0, parentIndex);
9959
+ const csvFilename = path__default["default"].join(...csvDirectory, 'transcript.csv');
9960
+ const csvFilenameAbs = path__default["default"].resolve(baseDir, csvFilename);
9961
+ try {
9962
+ if (fs__default["default"].existsSync(csvFilenameAbs)) {
9963
+ const records = csvParseSync(fs__default["default"].readFileSync(csvFilenameAbs, {
9964
+ encoding: 'utf-8'
9965
+ }).trim(), {
9966
+ columns: ['filename', 'transcription'],
9967
+ delimiter: [',', ';', ':', '\t'],
9968
+ trim: true,
9969
+ skip_empty_lines: true
9970
+ });
9971
+ if (records && records.length > 0) {
9972
+ for (const record of records) {
9973
+ const fnKey = path__default["default"].join(...csvDirectory, record.filename);
9974
+ csvCache[fnKey] = record.transcription;
9975
+ }
9976
+ }
9977
+ }
9978
+ } catch (err) {
9979
+ if (onError) onError(`Transcription CSV File ${csvFilenameAbs} not readable: ${err.message}`);
9980
+ throw new Error(`Reading transcription CSV file for ${csvFilename} failed`);
9981
+ }
9982
+ if (csvCache[audioFile]) {
9983
+ return csvCache[audioFile];
9984
+ }
9985
+ }
9986
+ return null;
9987
+ };
9988
+
9989
+ /**
9990
+ * Derive transcription text from audio filename (basename without extension, underscores/hyphens → spaces).
9991
+ * @param {string} audioFile - Path or filename of audio file
9992
+ * @returns {string}
9993
+ */
9994
+ var transcriptionFromFilename = audioFile => {
9995
+ const filename = path__default["default"].basename(audioFile, path__default["default"].extname(audioFile));
9996
+ return filename.split(/[_-]+/).join(' ');
9997
+ };
9840
9998
  var hasWaitForBotTimeout = transciptError => {
9841
9999
  if (!transciptError) {
9842
10000
  return false;
@@ -9848,6 +10006,8 @@ var hasWaitForBotTimeout = transciptError => {
9848
10006
  return str.indexOf(': error waiting for bot - Bot did not respond within') > 0;
9849
10007
  };
9850
10008
  var TranscriptUtils = {
10009
+ findTranscription: findTranscription,
10010
+ transcriptionFromFilename: transcriptionFromFilename,
9851
10011
  hasWaitForBotTimeout: hasWaitForBotTimeout
9852
10012
  };
9853
10013