@tiledesk/tiledesk-tybot-connector 2.0.20 → 2.0.21-rc2

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.20",
3
+ "version": "2.0.21-rc2",
4
4
  "description": "Tiledesk Tybot connector",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -0,0 +1,105 @@
1
+ const httpUtils = require('../utils/HttpUtils');
2
+ const winston = require('../utils/winston');
3
+ const API_ENDPOINT = process.env.API_ENDPOINT;
4
+
5
+ class KbService {
6
+
7
+ constructor() { }
8
+
9
+ async getNamespace(id_project, token, name, id) {
10
+ return new Promise((resolve) => {
11
+ const http_request = {
12
+ url: API_ENDPOINT + "/" + id_project + "/kb/namespace/all",
13
+ headers: {
14
+ 'Content-Type': 'application/json',
15
+ 'Authorization': 'JWT ' + token
16
+ },
17
+ method: "GET"
18
+ }
19
+ winston.debug("Kb HttpRequest", http_request);
20
+
21
+ httpUtils.request(
22
+ http_request, async (err, namespaces) => {
23
+ if (err) {
24
+ winston.error("Error getting namespaces:", err);
25
+ reject(err);
26
+ } else {
27
+ winston.debug("Get namespaces response:", namespaces);
28
+ if (!Array.isArray(namespaces)) {
29
+ reject(new Error('Invalid response format'));
30
+ return;
31
+ }
32
+
33
+ let namespace;
34
+ if (name) {
35
+ namespace = namespaces.find(n => n.name === name);
36
+ } else {
37
+ namespace = namespaces.find(n => n.id === id);
38
+ }
39
+ resolve(namespace || null);
40
+ }
41
+ }
42
+ )
43
+ })
44
+ }
45
+
46
+ async getKeyFromKbSettings(id_project, token) {
47
+
48
+ return new Promise((resolve) => {
49
+ const http_request = {
50
+ url: API_ENDPOINT + "/" + id_project + "/kbsettings",
51
+ headers: {
52
+ 'Content-Type': 'application/json',
53
+ 'Authorization': 'JWT ' + token
54
+ },
55
+ method: "GET"
56
+ }
57
+ winston.debug("Kb HttpRequest", http_request);
58
+
59
+ httpUtils.request(
60
+ http_request, async (err, resbody) => {
61
+ if (err) {
62
+ winston.error("Error getting kb settings:", err?.response?.data);
63
+ resolve(null);
64
+ } else {
65
+ if (!resbody || !resbody.gptkey) {
66
+ resolve(null);
67
+ } else {
68
+ resolve(resbody.gptkey);
69
+ }
70
+ }
71
+ }
72
+ )
73
+ })
74
+ }
75
+
76
+ async addUnansweredQuestion(id_project, namespace, question, token) {
77
+
78
+ const json = { namespace, question };
79
+
80
+ return new Promise((resolve, reject) => {
81
+ const http_request = {
82
+ url: API_ENDPOINT + "/" + id_project + "/kb/unanswered/",
83
+ headers: {
84
+ 'Content-Type': 'application/json',
85
+ 'Authorization': 'JWT ' + token
86
+ },
87
+ method: "POST",
88
+ json: json
89
+ }
90
+ winston.debug("Kb HttpRequest", http_request);
91
+
92
+ httpUtils.request(http_request, (err, response) => {
93
+ if (err) {
94
+ winston.error("Error adding unanswered question:", err);
95
+ reject(err);
96
+ } else {
97
+ resolve(response);
98
+ }
99
+ });
100
+ });
101
+ }
102
+ }
103
+
104
+ const kbService = new KbService();
105
+ module.exports = kbService;
@@ -0,0 +1,69 @@
1
+ const httpUtils = require('../utils/HttpUtils');
2
+ const winston = require('../utils/winston');
3
+ const API_ENDPOINT = process.env.API_ENDPOINT;
4
+
5
+ class QuotasService {
6
+
7
+ constructor() { }
8
+
9
+ async checkQuoteAvailability(id_project, token) {
10
+ return new Promise((resolve) => {
11
+
12
+ const http_request = {
13
+ url: API_ENDPOINT + "/" + id_project + "/quotes/tokens",
14
+ headers: {
15
+ 'Content-Type': 'application/json',
16
+ 'Authorization': 'JWT ' + token
17
+ },
18
+ method: "GET"
19
+ }
20
+ winston.debug("QuotasService HttpRequest", http_request);
21
+
22
+ httpUtils.request(
23
+ http_request, async (err, resbody) => {
24
+ if (err) {
25
+ winston.error("Check quote availability err: ", err);
26
+ resolve(true)
27
+ } else {
28
+ if (resbody.isAvailable === true) {
29
+ resolve(true)
30
+ } else {
31
+ resolve(false)
32
+ }
33
+ }
34
+ }
35
+ )
36
+ })
37
+ }
38
+
39
+ async updateQuote(id_project, token, tokens_usage) {
40
+ return new Promise((resolve, reject) => {
41
+
42
+ const http_request = {
43
+ url: API_ENDPOINT + "/" + id_project + "/quotes/incr/tokens",
44
+ headers: {
45
+ 'Content-Type': 'application/json',
46
+ 'Authorization': 'JWT ' + token
47
+ },
48
+ json: tokens_usage,
49
+ method: "POST"
50
+ }
51
+ winston.debug("DirAskGPTV2 update quote HttpRequest ", http_request);
52
+
53
+ httpUtils.request(
54
+ http_request, async (err, resbody) => {
55
+ if (err) {
56
+ winston.error("Increment tokens quote err: ", err);
57
+ reject(false)
58
+ } else {
59
+ resolve(true);
60
+ }
61
+ }
62
+ )
63
+ })
64
+ }
65
+
66
+ }
67
+
68
+ const quotasService = new QuotasService();
69
+ module.exports = quotasService;
@@ -54,13 +54,13 @@ const { DirMoveToUnassigned } = require('./directives/DirMoveToUnassigned');
54
54
  const { DirAddTags } = require('./directives/DirAddTags');
55
55
  const { DirSendWhatsapp } = require('./directives/DirSendWhatsapp');
56
56
  const { DirReplaceBotV3 } = require('./directives/DirReplaceBotV3');
57
- const { DirAiTask, DirAiPrompt } = require('./directives/DirAiPrompt');
57
+ const { DirAiPrompt } = require('./directives/DirAiPrompt');
58
58
  const { DirWebResponse } = require('./directives/DirWebResponse');
59
59
  const { DirConnectBlock } = require('./directives/DirConnectBlock');
60
+ const { DirAddKbContent } = require('./directives/DirAddKbContent');
61
+ const { DirFlowLog } = require('./directives/DirFlowLog');
60
62
 
61
63
  const winston = require('../utils/winston');
62
- const { DirFlowLog } = require('./directives/DirFlowLog');
63
- const { DirAddKbContent } = require('./directives/DirAddKbContent');
64
64
 
65
65
  class DirectivesChatbotPlug {
66
66
 
@@ -219,14 +219,13 @@ class DirectivesChatbotPlug {
219
219
  directive_name = directive.name.toLowerCase();
220
220
  }
221
221
  if (directive && directive.action) {
222
- const action_id = directive.action["_tdActionId"];
223
- const locked_action_id = await this.chatbot.currentLockedAction(this.supportRequest.request_id);
224
- if ( locked_action_id && (locked_action_id !== action_id) ) {
225
- let next_dir = await this.nextDirective(this.directives);
226
- this.process(next_dir);
227
- return;
228
- }
229
-
222
+ const action_id = directive.action["_tdActionId"];
223
+ const locked_action_id = await this.chatbot.currentLockedAction(this.supportRequest.request_id);
224
+ if ( locked_action_id && (locked_action_id !== action_id) ) {
225
+ let next_dir = await this.nextDirective(this.directives);
226
+ this.process(next_dir);
227
+ return;
228
+ }
230
229
  }
231
230
  if (directive == null || (directive !== null && directive["name"] === undefined)) {
232
231
  winston.debug("(DirectivesChatbotPlug) stop process(). directive is (null?): ", directive);
@@ -704,6 +703,19 @@ class DirectivesChatbotPlug {
704
703
  }
705
704
  });
706
705
  }
706
+ else if (directive_name === Directives.WEBHOOK) {
707
+ // console.log(".....DirIntent")
708
+ new DirIntent(context).execute(directive, async (stop) => {
709
+ if (stop) {
710
+ if (context.log) { console.log("Stopping Actions on:", JSON.stringify(directive));}
711
+ this.theend();
712
+ }
713
+ else {
714
+ let next_dir = await this.nextDirective(this.directives);
715
+ this.process(next_dir);
716
+ }
717
+ });
718
+ }
707
719
  else if (directive_name === Directives.WEB_RESPONSE) {
708
720
  new DirWebResponse(context).execute(directive, async () => {
709
721
  let next_dir = await this.nextDirective(this.directives);
@@ -716,6 +728,12 @@ class DirectivesChatbotPlug {
716
728
  this.process(next_dir);
717
729
  })
718
730
  }
731
+ else if (directive_name === Directives.ADD_KB_CONTENT) {
732
+ new DirAddKbContent(context).execute(directive, async () => {
733
+ let next_dir = await this.nextDirective(this.directives);
734
+ this.process(next_dir);
735
+ });
736
+ }
719
737
  else {
720
738
  let next_dir = await this.nextDirective(this.directives);
721
739
  this.process(next_dir);
@@ -11,6 +11,8 @@ const winston = require('../../utils/winston');
11
11
  const httpUtils = require("../../utils/HttpUtils");
12
12
  const integrationService = require("../../services/IntegrationService");
13
13
  const { Logger } = require("../../Logger");
14
+ const kbService = require("../../services/KBService");
15
+ const quotasService = require("../../services/QuotasService");
14
16
 
15
17
  class DirAskGPTV2 {
16
18
 
@@ -172,7 +174,7 @@ class DirAskGPTV2 {
172
174
  if (!key) {
173
175
  this.logger.native("[Ask Knowledge Base] OpenAI key not found in Integration. Using shared OpenAI key");
174
176
  winston.verbose("DirAskGPTV2 - Key not found in Integrations. Searching in kb settings...");
175
- key = await this.getKeyFromKbSettings();
177
+ key = await kbService.getKeyFromKbSettings(this.projectId, this.token);
176
178
  }
177
179
 
178
180
  if (!key) {
@@ -196,7 +198,7 @@ class DirAskGPTV2 {
196
198
  }
197
199
 
198
200
  if (publicKey === true && !chunks_only) {
199
- let keep_going = await this.checkQuoteAvailability();
201
+ let keep_going = await quotasService.checkQuoteAvailability(this.projectId, this.token);
200
202
  if (keep_going === false) {
201
203
  this.logger.warn("[Ask Knowledge Base] Tokens quota exceeded. Skip the action")
202
204
  winston.verbose("DirAskGPTV2 - Quota exceeded for tokens. Skip the action")
@@ -340,7 +342,9 @@ class DirAskGPTV2 {
340
342
  tokens: resbody.prompt_token_size,
341
343
  model: json.model
342
344
  }
343
- this.updateQuote(tokens_usage);
345
+ quotasService.updateQuote(this.projectId, this.token, tokens_usage).catch((err) => {
346
+ winston.error("Error updating quota: ", err);
347
+ })
344
348
  }
345
349
 
346
350
  if (trueIntent) {
@@ -353,6 +357,10 @@ class DirAskGPTV2 {
353
357
  }
354
358
  } else {
355
359
  await this.#assignAttributes(action, answer, source);
360
+ kbService.addUnansweredQuestion(this.projectId, json.namespace, json.question, this.token).catch((err) => {
361
+ winston.error("DirAskGPTV2 - Error adding unanswered question: ", err);
362
+ this.logger.warn("[Ask Knowledge Base] Unable to add unanswered question", json.question, "to namespacae", json.namespace);
363
+ })
356
364
  if (falseIntent) {
357
365
  await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
358
366
  callback(true);
@@ -423,93 +431,6 @@ class DirAskGPTV2 {
423
431
  }
424
432
  }
425
433
 
426
- async getKeyFromKbSettings() {
427
- return new Promise((resolve) => {
428
-
429
- const KB_HTTPREQUEST = {
430
- url: this.API_ENDPOINT + "/" + this.context.projectId + "/kbsettings",
431
- headers: {
432
- 'Content-Type': 'application/json',
433
- 'Authorization': 'JWT ' + this.context.token
434
- },
435
- method: "GET"
436
- }
437
- winston.debug("DirAskGPTV2 KB HttpRequest", KB_HTTPREQUEST);
438
-
439
- httpUtils.request(
440
- KB_HTTPREQUEST, async (err, resbody) => {
441
- if (err) {
442
- winston.error("DirAskGPTV2 Get kb settings error ", err?.response?.data);
443
- resolve(null);
444
- } else {
445
- if (!resbody.gptkey) {
446
- resolve(null);
447
- } else {
448
- resolve(resbody.gptkey);
449
- }
450
- }
451
- }
452
- )
453
- })
454
- }
455
-
456
- async checkQuoteAvailability() {
457
- return new Promise((resolve) => {
458
-
459
- const HTTPREQUEST = {
460
- url: this.API_ENDPOINT + "/" + this.context.projectId + "/quotes/tokens",
461
- headers: {
462
- 'Content-Type': 'application/json',
463
- 'Authorization': 'JWT ' + this.context.token
464
- },
465
- method: "GET"
466
- }
467
- winston.debug("DirAskGPTV2 check quote availability HttpRequest", HTTPREQUEST);
468
-
469
- httpUtils.request(
470
- HTTPREQUEST, async (err, resbody) => {
471
- if (err) {
472
- winston.error("DirAskGPTV2 Check quote availability err: ", err);
473
- resolve(true)
474
- } else {
475
- if (resbody.isAvailable === true) {
476
- resolve(true)
477
- } else {
478
- resolve(false)
479
- }
480
- }
481
- }
482
- )
483
- })
484
- }
485
-
486
- async updateQuote(tokens_usage) {
487
- return new Promise((resolve, reject) => {
488
-
489
- const HTTPREQUEST = {
490
- url: this.API_ENDPOINT + "/" + this.context.projectId + "/quotes/incr/tokens",
491
- headers: {
492
- 'Content-Type': 'application/json',
493
- 'Authorization': 'JWT ' + this.context.token
494
- },
495
- json: tokens_usage,
496
- method: "POST"
497
- }
498
- winston.debug("DirAskGPTV2 update quote HttpRequest ", HTTPREQUEST);
499
-
500
- httpUtils.request(
501
- HTTPREQUEST, async (err, resbody) => {
502
- if (err) {
503
- winston.error("DirAskGPTV2 Increment tokens quote err: ", err);
504
- reject(false)
505
- } else {
506
- resolve(true);
507
- }
508
- }
509
- )
510
- })
511
- }
512
-
513
434
  /**
514
435
  * Transforms the transcirpt array in a dictionary like '0': { "question": "xxx", "answer":"xxx"}
515
436
  * merging consecutive messages with the same role in a single question or answer.
@@ -19,6 +19,8 @@ class DirReply {
19
19
  this.tdcache = context.tdcache;
20
20
  this.log = context.log;
21
21
  this.API_ENDPOINT = context.API_ENDPOINT;
22
+
23
+ console.log("context.supportRequest: ", context.supportRequest);
22
24
 
23
25
  this.logger = new Logger({ request_id: this.requestId, dev: this.context.supportRequest?.draft, intent_id: this.context.reply?.attributes?.intent_info?.intent_id });
24
26
  this.tdClient = new TiledeskClient({ projectId: this.context.projectId, token: this.context.token, APIURL: this.API_ENDPOINT, APIKEY: "___", log: this.log });
@@ -118,7 +118,7 @@ class DirWebRequestV2 {
118
118
  this.logger.native("[Web Request] resbody: ", resbody);
119
119
 
120
120
  if (err) {
121
- this.logger.error("WebRequest error: ", err);
121
+ this.logger.error("[Web Request] error: ", err);
122
122
  winston.log("webRequest error: ", err);
123
123
  if (callback) {
124
124
  if (falseIntent) {
@@ -58,6 +58,7 @@ class Directives {
58
58
  static MOVE_TO_UNASSIGNED = "move_to_unassigned";
59
59
  static CONNECT_BLOCK = "connect_block";
60
60
  static ADD_TAGS = 'add_tags'
61
+ static WEBHOOK = 'webhook';
61
62
  static WEB_RESPONSE = "web_response";
62
63
  static FLOW_LOG = "flow_log";
63
64
  static ADD_KB_CONTENT = "add_kb_content";
@@ -333,27 +333,6 @@ class TiledeskChatbotUtil {
333
333
  }
334
334
  });
335
335
  }
336
-
337
- // "buttons": [
338
- // {
339
- // "type": "action",
340
- // "value": "Button1", // obbligatorio sempre
341
- // "action": "#bb347206-d639-4926-94c9-e94930623dce", // mandatory
342
- // "show_echo": true, // lo inserisco sempre
343
- // "alias": "button1 alias"
344
- // },
345
- // {
346
- // "type": "text",
347
- // "value": "Button2 text", // obbligatorio sempre
348
- // "show_echo": true // lo inserisco sempre
349
- // },
350
- // {
351
- // "type": "url",
352
- // "value": "Button3 link", // obbligatorio sempre
353
- // "link": "http://", // obbligatorio
354
- // "show_echo": true // lo inserisco sempre
355
- // }
356
- // ]
357
336
  }
358
337
  catch(error) {
359
338
  winston.warn("Invalid json_buttons:", error)
@@ -604,8 +583,10 @@ class TiledeskChatbotUtil {
604
583
  }
605
584
  let currentLeadName = await chatbot.getParameter(TiledeskChatbotConst.REQ_LEAD_USERFULLNAME_KEY);
606
585
  winston.debug("(TiledeskChatbotUtil) You lead email from attributes: " + currentLeadEmail);
586
+ console.log("currentLeadName: ", currentLeadName)
607
587
  if (message.request.lead.fullname && !currentLeadName) {
608
588
  // worth saving
589
+ console.log("inside if")
609
590
  winston.debug("(TiledeskChatbotUtil) worth saving email");
610
591
  try {
611
592
  await chatbot.addParameter(TiledeskChatbotConst.REQ_LEAD_USERFULLNAME_KEY, message.request.lead.fullname);