@tiledesk/tiledesk-tybot-connector 2.0.33 → 2.0.35

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiledesk/tiledesk-tybot-connector",
3
- "version": "2.0.33",
3
+ "version": "2.0.35",
4
4
  "description": "Tiledesk Tybot connector",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -30,11 +30,6 @@ class DirAskGPTV2 {
30
30
 
31
31
  this.intentDir = new DirIntent(context);
32
32
  this.logger = new Logger({ request_id: this.requestId, dev: this.context.supportRequest?.draft, intent_id: this.context.reply?.attributes?.intent_info?.intent_id });
33
-
34
- this.rerankingOff = false;
35
- if (process.env.RERANKING_OFF && (process.env.RERANKING_OFF === "true" || process.env.RERANKING_OFF === true)) {
36
- this.rerankingOff = true;
37
- }
38
33
  }
39
34
 
40
35
  execute(directive, callback) {
@@ -63,7 +58,6 @@ class DirAskGPTV2 {
63
58
  return;
64
59
  }
65
60
 
66
- let publicKey = false;
67
61
  let trueIntent = action.trueIntent;
68
62
  let falseIntent = action.falseIntent;
69
63
  let trueIntentAttributes = action.trueIntentAttributes;
@@ -74,11 +68,11 @@ class DirAskGPTV2 {
74
68
  winston.debug("DirAskGPTV2 trueIntentAttributes", trueIntentAttributes)
75
69
  winston.debug("DirAskGPTV2 falseIntentAttributes", falseIntentAttributes)
76
70
 
77
-
78
71
  // default values
79
72
  let answer = "No answers";
80
73
  let namespace = this.context.projectId;
81
- let model = "gpt-3.5-turbo";
74
+ let llm = "openai";
75
+ let model;
82
76
  let temperature;
83
77
  let max_tokens;
84
78
  let top_k;
@@ -87,7 +81,8 @@ class DirAskGPTV2 {
87
81
  let citations = false;
88
82
  let chunks_only = false;
89
83
  let engine;
90
- //let default_context = "You are an helpful assistant for question-answering tasks.\nUse ONLY the following pieces of retrieved context to answer the question.\nIf you don't know the answer, just say that you don't know.\nIf none of the retrieved context answer the question, add this word to the end <NOANS>\n\n{context}";
84
+ let reranking;
85
+ let skip_unanswered;
91
86
 
92
87
  let contexts = {
93
88
  "gpt-3.5-turbo": "You are an helpful assistant for question-answering tasks.\nUse ONLY the pieces of retrieved context delimited by #### to answer the question.\nIf you don't know the answer, just say: \"I don't know<NOANS>\"\n\n####{context}####",
@@ -104,48 +99,53 @@ class DirAskGPTV2 {
104
99
  }
105
100
 
106
101
  let source = null;
102
+ if (!action.llm) {
103
+ action.llm = "openai";
104
+ }
107
105
 
108
- if (!action.question || action.question === '') {
109
- this.logger.error("[Ask Knowledge Base] question attribute is mandatory");
110
- winston.error("DirAskGPTV2 Error: question attribute is mandatory. Executing condition false...");
106
+ await this.checkMandatoryParameters(action).catch( async (missing_param) => {
107
+ this.logger.error(`[Ask Knowledge Base] missing attribute '${missing_param}'`);
108
+ await this.chatbot.addParameter("flowError", `AskKnowledgeBase Error: '${missing_param}' attribute is undefined`);
111
109
  await this.#assignAttributes(action, answer, source);
112
110
  if (falseIntent) {
113
111
  await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
112
+ callback(true);
113
+ return Promise.reject();
114
114
  }
115
- callback(true);
116
- return;
117
- }
115
+ callback();
116
+ return Promise.reject();
117
+ })
118
118
 
119
119
  if (action.namespace) {
120
120
  namespace = action.namespace;
121
121
  }
122
+ if (action.llm) {
123
+ llm = action.llm;
124
+ }
122
125
  if (action.model) {
123
126
  model = action.model;
124
127
  }
125
-
126
128
  if (action.top_k) {
127
129
  top_k = action.top_k;
128
130
  }
129
-
130
131
  if (action.temperature) {
131
132
  temperature = action.temperature;
132
133
  }
133
-
134
134
  if (action.max_tokens) {
135
135
  max_tokens = action.max_tokens;
136
136
  }
137
-
138
137
  if (action.alpha) {
139
138
  alpha = action.alpha;
140
139
  }
141
-
142
140
  if (action.citations) {
143
141
  citations = action.citations;
144
142
  }
145
-
146
143
  if (action.chunks_only) {
147
144
  chunks_only = action.chunks_only;
148
145
  }
146
+ if (action.reranking) {
147
+ reranking = action.reranking;
148
+ }
149
149
 
150
150
  let requestVariables = null;
151
151
  requestVariables =
@@ -175,41 +175,84 @@ class DirAskGPTV2 {
175
175
  }
176
176
  }
177
177
 
178
- let key = await integrationService.getKeyFromIntegrations(this.projectId, 'openai', this.token);
179
- if (!key) {
180
- this.logger.native("[Ask Knowledge Base] OpenAI key not found in Integration. Using shared OpenAI key");
181
- winston.verbose("DirAskGPTV2 - Key not found in Integrations. Searching in kb settings...");
182
- key = await kbService.getKeyFromKbSettings(this.projectId, this.token);
183
- }
178
+ let key;
179
+ let publicKey = false;
180
+ let ollama_integration;
181
+ let vllm_integration;
184
182
 
185
- if (!key) {
186
- winston.verbose("DirAskGPTV2 - Retrieve public gptkey")
183
+ if (action.llm === 'ollama') {
187
184
  key = process.env.GPTKEY;
188
- publicKey = true;
189
- } else {
190
- this.logger.native("[Ask Knowledge Base] use your own OpenAI key")
185
+ ollama_integration = await integrationService.getIntegration(this.projectId, action.llm, this.token).catch( async (err) => {
186
+ this.logger.error("[Ask Knowledge Base] Error getting ollama integration.");
187
+ await this.chatbot.addParameter("flowError", "Ollama integration not found");
188
+ if (falseIntent) {
189
+ await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
190
+ callback(true);
191
+ return;
192
+ }
193
+ callback();
194
+ return;
195
+ })
191
196
  }
197
+ else if (action.llm === 'vllm') {
198
+ key = process.env.GPTKEY;
199
+ vllm_integration = await integrationService.getIntegration(this.projectId, action.llm, this.token).catch( async (err) => {
200
+ this.logger.error("[Ask Knowledge Base] Error getting vllm integration.");
201
+ await this.chatbot.addParameter("flowError", "vLLM integration not found");
202
+ if (falseIntent) {
203
+ await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
204
+ callback(true);
205
+ return;
206
+ }
207
+ callback();
208
+ return;
209
+ })
210
+ }
211
+ else {
212
+ key = await integrationService.getKeyFromIntegrations(this.projectId, action.llm, this.token);
192
213
 
193
- if (!key) {
194
- winston.info("DirAskGPTV2 Error: gptkey is mandatory");
195
- await this.#assignAttributes(action, answer);
196
- if (falseIntent) {
197
- await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
198
- callback(true);
214
+ if (!key && action.llm === 'openai') {
215
+ this.logger.native("[Ask Knowledge Base] OpenAI key not found in Integration. Retrieve shared OpenAI key.");
216
+ key = process.env.GPTKEY;
217
+ publicKey = true;
218
+ }
219
+
220
+ if (!key) {
221
+ this.logger.error(`[Ask Knowledge Base] llm key for ${action.llm} not found in integrations`);
222
+ await this.chatbot.addParameter("flowError", `AskKnowledgeBase Error: missing key for llm ${action.llm}`);
223
+ if (falseIntent) {
224
+ await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
225
+ callback(true);
226
+ return;
227
+ }
228
+ callback();
199
229
  return;
200
230
  }
201
- callback();
202
- return;
203
231
  }
204
232
 
205
233
  if (publicKey === true && !chunks_only) {
206
- let keep_going = await quotasService.checkQuoteAvailability(this.projectId, this.token);
207
- if (keep_going === false) {
208
- this.logger.warn("[Ask Knowledge Base] Tokens quota exceeded. Skip the action")
209
- winston.verbose("DirAskGPTV2 - Quota exceeded for tokens. Skip the action")
210
- await this.chatbot.addParameter("flowError", "AskGPT Error: tokens quota exceeded");
211
- await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
212
- callback(true);
234
+ try {
235
+ let keep_going = await quotasService.checkQuoteAvailability(this.projectId, this.token)
236
+ if (keep_going === false) {
237
+ this.logger.warn("[AI Prompt] OpenAI tokens quota exceeded");
238
+ await this.chatbot.addParameter("flowError", "GPT Error: tokens quota exceeded");
239
+ if (falseIntent) {
240
+ await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
241
+ callback();
242
+ return;
243
+ }
244
+ callback();
245
+ return;
246
+ }
247
+ } catch (err) {
248
+ this.logger.error("An error occured on checking token quota availability");
249
+ await this.chatbot.addParameter("flowError", "An error occured on checking token quota availability");
250
+ if (falseIntent) {
251
+ await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
252
+ callback();
253
+ return;
254
+ }
255
+ callback();
213
256
  return;
214
257
  }
215
258
  }
@@ -262,6 +305,7 @@ class DirAskGPTV2 {
262
305
  question: filled_question,
263
306
  gptkey: key,
264
307
  namespace: namespace,
308
+ llm: llm,
265
309
  model: model,
266
310
  citations: citations,
267
311
  engine: engine,
@@ -280,6 +324,16 @@ class DirAskGPTV2 {
280
324
  json.chunks_only = chunks_only;
281
325
  }
282
326
 
327
+ if (llm === 'ollama') {
328
+ json.gptkey = "";
329
+ json.model = {
330
+ name: action.model,
331
+ url: ollama_integration.value.url,
332
+ token: ollama_integration.value.token
333
+ }
334
+ json.stream = false;
335
+ }
336
+
283
337
 
284
338
  if (ns.hybrid === true) {
285
339
  json.search_type = 'hybrid';
@@ -301,13 +355,12 @@ class DirAskGPTV2 {
301
355
  json.chat_history_dict = await this.transcriptToLLM(transcript);
302
356
  }
303
357
 
304
- if (!this.rerankingOff) {
358
+ if (reranking === true) {
305
359
  json.reranking = true;
306
360
  json.reranking_multiplier = 3;
307
361
  json.reranker_model = "cross-encoder/ms-marco-MiniLM-L-6-v2";
308
362
  }
309
363
 
310
-
311
364
  winston.debug("DirAskGPTV2 json:", json);
312
365
 
313
366
  let kb_endpoint = process.env.KB_ENDPOINT_QA;
@@ -331,7 +384,8 @@ class DirAskGPTV2 {
331
384
  HTTPREQUEST, async (err, resbody) => {
332
385
 
333
386
  if (err) {
334
- winston.error("DirAskGPTV2 error: ", err?.respose);
387
+ winston.error("DirAskGPTV2 error: ", err?.response);
388
+ this.logger.error(`[Ask Knowledge Base] Error getting answer`);
335
389
  await this.#assignAttributes(action, answer, source);
336
390
  if (callback) {
337
391
  if (falseIntent) {
@@ -357,7 +411,7 @@ class DirAskGPTV2 {
357
411
 
358
412
  } else {
359
413
  await this.#assignAttributes(action, resbody.answer, resbody.source, resbody.content_chunks);
360
- if (publicKey === true) {
414
+ if (publicKey === true && !chunks_only) {
361
415
  let tokens_usage = {
362
416
  tokens: resbody.prompt_token_size,
363
417
  model: json.model
@@ -377,10 +431,12 @@ class DirAskGPTV2 {
377
431
  }
378
432
  } else {
379
433
  await this.#assignAttributes(action, answer, source);
380
- kbService.addUnansweredQuestion(this.projectId, json.namespace, json.question, this.token).catch((err) => {
381
- winston.error("DirAskGPTV2 - Error adding unanswered question: ", err);
382
- this.logger.warn("[Ask Knowledge Base] Unable to add unanswered question", json.question, "to namespacae", json.namespace);
383
- })
434
+ if (!skip_unanswered) {
435
+ kbService.addUnansweredQuestion(this.projectId, json.namespace, json.question, this.token).catch((err) => {
436
+ winston.error("DirAskGPTV2 - Error adding unanswered question: ", err);
437
+ this.logger.warn("[Ask Knowledge Base] Unable to add unanswered question", json.question, "to namespacae", json.namespace);
438
+ })
439
+ }
384
440
  if (falseIntent) {
385
441
  await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
386
442
  callback(true);
@@ -451,6 +507,18 @@ class DirAskGPTV2 {
451
507
  }
452
508
  }
453
509
 
510
+ async checkMandatoryParameters(action) {
511
+ return new Promise((resolve, reject) => {
512
+ let params = ['question', 'llm', 'model']; // mandatory params
513
+ params.forEach((p) => {
514
+ if (!action[p]) {
515
+ reject(p)
516
+ }
517
+ })
518
+ resolve(true);
519
+ })
520
+ }
521
+
454
522
  /**
455
523
  * Transforms the transcirpt array in a dictionary like '0': { "question": "xxx", "answer":"xxx"}
456
524
  * merging consecutive messages with the same role in a single question or answer.