@tiledesk/tiledesk-tybot-connector 2.0.33 → 2.0.34

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.34",
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;
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}####",
@@ -105,16 +100,18 @@ class DirAskGPTV2 {
105
100
 
106
101
  let source = null;
107
102
 
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...");
103
+ await this.checkMandatoryParameters(action).catch( async (missing_param) => {
104
+ this.logger.error(`[Ask Knowledge Base] missing attribute '${missing_param}'`);
105
+ await this.chatbot.addParameter("flowError", `AskKnowledgeBase Error: '${missing_param}' attribute is undefined`);
111
106
  await this.#assignAttributes(action, answer, source);
112
107
  if (falseIntent) {
113
108
  await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
109
+ callback(true);
110
+ return Promise.reject();
114
111
  }
115
- callback(true);
116
- return;
117
- }
112
+ callback();
113
+ return Promise.reject();
114
+ })
118
115
 
119
116
  if (action.namespace) {
120
117
  namespace = action.namespace;
@@ -122,30 +119,27 @@ class DirAskGPTV2 {
122
119
  if (action.model) {
123
120
  model = action.model;
124
121
  }
125
-
126
122
  if (action.top_k) {
127
123
  top_k = action.top_k;
128
124
  }
129
-
130
125
  if (action.temperature) {
131
126
  temperature = action.temperature;
132
127
  }
133
-
134
128
  if (action.max_tokens) {
135
129
  max_tokens = action.max_tokens;
136
130
  }
137
-
138
131
  if (action.alpha) {
139
132
  alpha = action.alpha;
140
133
  }
141
-
142
134
  if (action.citations) {
143
135
  citations = action.citations;
144
136
  }
145
-
146
137
  if (action.chunks_only) {
147
138
  chunks_only = action.chunks_only;
148
139
  }
140
+ if (action.reranking) {
141
+ reranking = action.reranking;
142
+ }
149
143
 
150
144
  let requestVariables = null;
151
145
  requestVariables =
@@ -175,41 +169,67 @@ class DirAskGPTV2 {
175
169
  }
176
170
  }
177
171
 
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
- }
184
-
185
- if (!key) {
186
- winston.verbose("DirAskGPTV2 - Retrieve public gptkey")
187
- key = process.env.GPTKEY;
188
- publicKey = true;
172
+ let key;
173
+ let publicKey = false;
174
+ let ollama_integration;
175
+
176
+ if (action.llm === 'ollama') {
177
+ ollama_integration = await integrationService.getIntegration(this.projectId, action.llm, this.token).catch( async (err) => {
178
+ this.logger.error("[Ask Knowledge Base] Error getting ollama integration.");
179
+ await this.chatbot.addParameter("flowError", "Ollama integration not found");
180
+ if (falseIntent) {
181
+ await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
182
+ callback(true);
183
+ return;
184
+ }
185
+ callback();
186
+ return;
187
+ })
189
188
  } else {
190
- this.logger.native("[Ask Knowledge Base] use your own OpenAI key")
191
- }
189
+ key = await integrationService.getKeyFromIntegrations(this.projectId, action.llm, this.token);
192
190
 
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);
191
+ if (!key && action.llm === 'openai') {
192
+ this.logger.native("[Ask Knowledge Base] OpenAI key not found in Integration. Retrieve shared OpenAI key.");
193
+ key = process.env.GPTKEY;
194
+ publicKey = true;
195
+ }
196
+
197
+ if (!key) {
198
+ this.logger.error(`[Ask Knowledge Base] llm key for ${action.llm} not found in integrations`);
199
+ await this.chatbot.addParameter("flowError", `AskKnowledgeBase Error: missing key for llm ${action.llm}`);
200
+ if (falseIntent) {
201
+ await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
202
+ callback(true);
203
+ return;
204
+ }
205
+ callback();
199
206
  return;
200
207
  }
201
- callback();
202
- return;
203
208
  }
204
209
 
205
210
  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);
211
+ try {
212
+ let keep_going = await quotasService.checkQuoteAvailability(this.projectId, this.token)
213
+ if (keep_going === false) {
214
+ this.logger.warn("[AI Prompt] OpenAI tokens quota exceeded");
215
+ await this.chatbot.addParameter("flowError", "GPT Error: tokens quota exceeded");
216
+ if (falseIntent) {
217
+ await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
218
+ callback();
219
+ return;
220
+ }
221
+ callback();
222
+ return;
223
+ }
224
+ } catch (err) {
225
+ this.logger.error("An error occured on checking token quota availability");
226
+ await this.chatbot.addParameter("flowError", "An error occured on checking token quota availability");
227
+ if (falseIntent) {
228
+ await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
229
+ callback();
230
+ return;
231
+ }
232
+ callback();
213
233
  return;
214
234
  }
215
235
  }
@@ -262,6 +282,7 @@ class DirAskGPTV2 {
262
282
  question: filled_question,
263
283
  gptkey: key,
264
284
  namespace: namespace,
285
+ llm: llm,
265
286
  model: model,
266
287
  citations: citations,
267
288
  engine: engine,
@@ -280,6 +301,16 @@ class DirAskGPTV2 {
280
301
  json.chunks_only = chunks_only;
281
302
  }
282
303
 
304
+ if (llm === 'ollama') {
305
+ json.gptkey = "";
306
+ json.model = {
307
+ name: action.model,
308
+ url: ollama_integration.value.url,
309
+ token: ollama_integration.value.token
310
+ }
311
+ json.stream = false;
312
+ }
313
+
283
314
 
284
315
  if (ns.hybrid === true) {
285
316
  json.search_type = 'hybrid';
@@ -301,13 +332,12 @@ class DirAskGPTV2 {
301
332
  json.chat_history_dict = await this.transcriptToLLM(transcript);
302
333
  }
303
334
 
304
- if (!this.rerankingOff) {
335
+ if (reranking === true) {
305
336
  json.reranking = true;
306
337
  json.reranking_multiplier = 3;
307
338
  json.reranker_model = "cross-encoder/ms-marco-MiniLM-L-6-v2";
308
339
  }
309
340
 
310
-
311
341
  winston.debug("DirAskGPTV2 json:", json);
312
342
 
313
343
  let kb_endpoint = process.env.KB_ENDPOINT_QA;
@@ -331,7 +361,8 @@ class DirAskGPTV2 {
331
361
  HTTPREQUEST, async (err, resbody) => {
332
362
 
333
363
  if (err) {
334
- winston.error("DirAskGPTV2 error: ", err?.respose);
364
+ winston.error("DirAskGPTV2 error: ", err?.response);
365
+ this.logger.error(`[Ask Knowledge Base] Error getting answer`);
335
366
  await this.#assignAttributes(action, answer, source);
336
367
  if (callback) {
337
368
  if (falseIntent) {
@@ -357,7 +388,7 @@ class DirAskGPTV2 {
357
388
 
358
389
  } else {
359
390
  await this.#assignAttributes(action, resbody.answer, resbody.source, resbody.content_chunks);
360
- if (publicKey === true) {
391
+ if (publicKey === true && !chunks_only) {
361
392
  let tokens_usage = {
362
393
  tokens: resbody.prompt_token_size,
363
394
  model: json.model
@@ -377,10 +408,12 @@ class DirAskGPTV2 {
377
408
  }
378
409
  } else {
379
410
  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
- })
411
+ if (!skip_unanswered) {
412
+ kbService.addUnansweredQuestion(this.projectId, json.namespace, json.question, this.token).catch((err) => {
413
+ winston.error("DirAskGPTV2 - Error adding unanswered question: ", err);
414
+ this.logger.warn("[Ask Knowledge Base] Unable to add unanswered question", json.question, "to namespacae", json.namespace);
415
+ })
416
+ }
384
417
  if (falseIntent) {
385
418
  await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
386
419
  callback(true);
@@ -451,6 +484,18 @@ class DirAskGPTV2 {
451
484
  }
452
485
  }
453
486
 
487
+ async checkMandatoryParameters(action) {
488
+ return new Promise((resolve, reject) => {
489
+ let params = ['question', 'llm', 'model']; // mandatory params
490
+ params.forEach((p) => {
491
+ if (!action[p]) {
492
+ reject(p)
493
+ }
494
+ })
495
+ resolve(true);
496
+ })
497
+ }
498
+
454
499
  /**
455
500
  * Transforms the transcirpt array in a dictionary like '0': { "question": "xxx", "answer":"xxx"}
456
501
  * merging consecutive messages with the same role in a single question or answer.