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

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/CHANGELOG.md CHANGED
@@ -5,8 +5,6 @@
5
5
  available on:
6
6
  ▶️ https://www.npmjs.com/package/@tiledesk/tiledesk-tybot-connector
7
7
 
8
- # 2.0.9
9
-
10
8
  # 2.0.9-rc1
11
9
  - removed: speech-to-text management
12
10
 
@@ -20,6 +18,8 @@ available on:
20
18
 
21
19
  # v0.5.0
22
20
  - added: AI_ENDPOINT env var
21
+
22
+ # v0.5.0-rc1
23
23
  - added: ability to get 'none' as bodytype in webresponse
24
24
 
25
25
  # v0.4.2
@@ -34,6 +34,19 @@ available on:
34
34
  - changed: refactoring of DIrWebRequestv2
35
35
  - bug-fixed: erro while parsing webrequestv2 body
36
36
 
37
+ # v0.3.5-rc4
38
+ - added: webhook action (same as intent one)
39
+
40
+ # v0.3.5-rc3
41
+ - bug-fixed: jsonBody parse error in web-request-v2
42
+
43
+ # v0.3.5-rc2
44
+ - bug-fixed: cannot set status of undefined reading res.status in DirAssistant
45
+
46
+ # v0.3.5-rc1
47
+ - changed: refactoring web-request-v2
48
+ - bug-fixed: jsonBody parse error in web-request-v2
49
+
37
50
  # v0.3.4
38
51
  -bug-fixed: slit is undefined in TiledeskChatbotUtils
39
52
 
@@ -43,6 +56,18 @@ available on:
43
56
  # v0.3.2
44
57
  - bug-fixed: minor improvement
45
58
 
59
+ # v0.2.153-rc9
60
+ - changed: updated tiledesk-multi-worker to 0.2.1-rc2
61
+
62
+ # v0.2.153-rc8
63
+ - added: fixToken function in TiledeskService utils class
64
+
65
+ # v0.2.153-rc4
66
+ - log added
67
+
68
+ # v0.2.153-rc3
69
+ - added: specchToText function to transcript audio file
70
+
46
71
  # v0.2.153-rc1
47
72
  - changed: context for gpt-40 and gpt-40-mini
48
73
 
package/Logger.js CHANGED
@@ -12,6 +12,8 @@ let publisher = new Publisher(AMQP_MANAGER_URL, {
12
12
  exchange: "amq.topic"
13
13
  })
14
14
 
15
+ console.log("LOGGER publisher: ", publisher);
16
+
15
17
  class Logger {
16
18
 
17
19
  constructor(config) {
@@ -92,6 +94,7 @@ class Logger {
92
94
  }
93
95
 
94
96
  let topic = LOGS_BASE_ROUTING_KEY + `.${this.request_id}`;
97
+ console.log("LOGGER publishing on topic ", topic)
95
98
  publisher.publish(data, topic);
96
99
  return;
97
100
  }
@@ -24,8 +24,7 @@ class MockBotsDataSource {
24
24
  }catch(err){
25
25
  reject(err);
26
26
  }
27
-
28
- })
27
+ })
29
28
  }
30
29
 
31
30
  async getBotByIdCache(botId, tdcache) {
package/index.js CHANGED
@@ -100,6 +100,9 @@ router.post('/ext/:botid', async (req, res) => {
100
100
  Promise.reject(err);
101
101
  return;
102
102
  });
103
+
104
+ winston.debug("(tybotRoute) Bot found: ", bot)
105
+
103
106
 
104
107
  let intentsMachine;
105
108
  let backupMachine;
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-rc1",
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, reject) => {
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);
63
+ reject(err);
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);
package/TdCache copy.js DELETED
@@ -1,242 +0,0 @@
1
- const redis = require('redis');
2
-
3
- class TdCache {
4
-
5
- constructor(config) {
6
- this.redis_host = config.host;
7
- this.redis_port = config.port;
8
- this.redis_password = config.password;
9
- this.client = null;
10
- }
11
-
12
- async connect(callback) {
13
- // client = redis.createClient();
14
- return new Promise( async (resolve, reject) => {
15
- this.client = redis.createClient(
16
- {
17
- host: this.redis_host,
18
- port: this.redis_port,
19
- password: this.redis_password
20
- });
21
- this.client.on('error', err => {
22
- reject(err);
23
- if (callback) {
24
- callback(err);
25
- }
26
- });
27
- // this.client.on('connect', function() {
28
- // console.log('Redis Connected!');
29
- // });
30
- this.client.on('ready',function() {
31
- console.log("connected")
32
- resolve();
33
- if (callback) {
34
- callback();
35
- }
36
- //console.log("Redis is ready.");
37
- });
38
- });
39
- }
40
-
41
- async set(key, value, options) {
42
- //console.log("setting key value", key, value)
43
- if (!options) {
44
- options = {EX: 86400}
45
- }
46
- return new Promise( async (resolve, reject) => {
47
- if (options && options.EX) {
48
- //console.log("expires:", options.EX)
49
- try {
50
- await this.client.set(
51
- key,
52
- value,
53
- 'EX', options.EX);
54
- }
55
- catch(error) {
56
- reject(error)
57
- }
58
- }
59
- else {
60
- try {
61
- //console.log("setting here...key", key, value)
62
- await this.client.set(
63
- key,
64
- value);
65
- }
66
- catch(error) {
67
- console.error("Error", error);
68
- reject(error)
69
- }
70
- }
71
- if (options && options.callback) {
72
- options.callback();
73
- }
74
- //console.log("resolving...", key);
75
- return resolve();
76
- });
77
- }
78
-
79
- async incr(key) {
80
- // console.log("incr key:", key)
81
- return new Promise( async (resolve, reject) => {
82
- try {
83
- // console.log("incr here...key", key)
84
- await this.client.incr(key);
85
- }
86
- catch(error) {
87
- console.error("Error on incr:", error);
88
- reject(error)
89
- }
90
- return resolve();
91
- });
92
- }
93
-
94
- async hset(dict_key, key, value, options) {
95
- //console.log("hsetting dict_key key value", dict_key, key, value)
96
- return new Promise( async (resolve, reject) => {
97
- if (options && options.EX) {
98
- //console.log("expires:", options.EX)
99
- try {
100
- await this.client.hset(
101
- dict_key,
102
- key,
103
- value,
104
- 'EX', options.EX);
105
- }
106
- catch(error) {
107
- reject(error)
108
- }
109
- }
110
- else {
111
- try {
112
- //console.log("setting here...key", key, value)
113
- await this.client.hset(
114
- dict_key,
115
- key,
116
- value);
117
- }
118
- catch(error) {
119
- console.error("Error", error);
120
- reject(error)
121
- }
122
- }
123
- if (options && options.callback) {
124
- options.callback();
125
- }
126
- return resolve();
127
- });
128
- }
129
-
130
- async hdel(dict_key, key, options) {
131
- //console.log("hsetting dict_key key value", dict_key, key, value)
132
- return new Promise( async (resolve, reject) => {
133
- if (options && options.EX) {
134
- //console.log("expires:", options.EX)
135
- try {
136
- await this.client.hdel(
137
- dict_key,
138
- key,
139
- 'EX', options.EX);
140
- }
141
- catch(error) {
142
- reject(error)
143
- }
144
- }
145
- else {
146
- try {
147
- //console.log("setting here...key", key, value)
148
- await this.client.hdel(
149
- dict_key,
150
- key);
151
- }
152
- catch(error) {
153
- console.error("Error", error);
154
- reject(error);
155
- }
156
- }
157
- if (options && options.callback) {
158
- options.callback();
159
- }
160
- return resolve();
161
- });
162
- }
163
-
164
- async setJSON(key, value, options) {
165
- const _string = JSON.stringify(value);
166
- return await this.set(key, _string, options);
167
- }
168
-
169
- async get(key, callback) {
170
- //console.log("getting key", key)
171
- return new Promise( async (resolve, reject) => {
172
- this.client.get(key, (err, value) => {
173
- if (err) {
174
- reject(err);
175
- }
176
- else {
177
- if (callback) {
178
- callback(value);
179
- }
180
- return resolve(value);
181
- }
182
- });
183
- });
184
- }
185
-
186
- async hgetall(dict_key, callback) {
187
- //console.log("hgetting dics", dict_key);
188
- return new Promise( async (resolve, reject) => {
189
- this.client.hgetall(dict_key, (err, value) => {
190
- if (err) {
191
- reject(err);
192
- if (callback) {
193
- callback(err, null);
194
- }
195
- }
196
- else {
197
- if (callback) {
198
- callback(null, value);
199
- }
200
- resolve(value);
201
- }
202
- });
203
- });
204
- }
205
-
206
- async hget(dict_key, key, callback) {
207
- //console.log("hgetting dics", dict_key);
208
- return new Promise( async (resolve, reject) => {
209
- this.client.hget(dict_key, key, (err, value) => {
210
- if (err) {
211
- reject(err);
212
- if (callback) {
213
- callback(err, null);
214
- }
215
- }
216
- else {
217
- if (callback) {
218
- callback(null, value);
219
- }
220
- resolve(value);
221
- }
222
- });
223
- });
224
- }
225
-
226
- async getJSON(key, callback) {
227
- const value = await this.get(key);
228
- return JSON.parse(value);
229
- }
230
-
231
- async del(key, callback) {
232
- return new Promise( async (resolve, reject) => {
233
- await this.client.del(key);
234
- if (callback) {
235
- callback();
236
- }
237
- return resolve();
238
- })
239
- }
240
- }
241
-
242
- module.exports = { TdCache };
@@ -1,418 +0,0 @@
1
- let axios = require('axios');
2
- let https = require("https");
3
- const { Filler } = require('../Filler');
4
- const { TiledeskChatbot } = require('../../engine/TiledeskChatbot');
5
- const { DirIntent } = require('./DirIntent');
6
-
7
- class DirWebRequestV2 {
8
- constructor(context) {
9
- if (!context) {
10
- throw new Error('context object is mandatory.');
11
- }
12
- this.context = context;
13
- this.tdcache = context.tdcache;
14
- this.requestId = context.requestId;
15
- this.chatbot = context.chatbot;
16
- this.log = context.log;
17
-
18
- this.intentDir = new DirIntent(context);
19
- }
20
-
21
- execute(directive, callback) {
22
- let action;
23
- if (directive.action) {
24
- action = directive.action;
25
- }
26
- else {
27
- console.error("Incorrect directive:", JSON.stringify(directive));
28
- callback();
29
- return;
30
- }
31
- this.go(action, (stop) => {
32
- if (this.log) {console.log("(webrequestv2, stop?", stop); }
33
- callback(stop);
34
- });
35
- }
36
-
37
- async go(action, callback) {
38
- if (this.log) {console.log("webRequest action:", JSON.stringify(action));}
39
-
40
- // Condition branches
41
- let trueIntent = action.trueIntent;
42
- let falseIntent = action.falseIntent;
43
- const trueIntentAttributes = action.trueIntentAttributes;
44
- const falseIntentAttributes = action.falseIntentAttributes;
45
- let stopOnConditionMet = action.stopOnConditionMet;
46
- if (trueIntent && trueIntent.trim() === "") {
47
- trueIntent = null;
48
- }
49
- if (falseIntent && falseIntent.trim() === "") {
50
- falseIntent = null;
51
- }
52
-
53
- let requestAttributes = null;
54
- if (this.tdcache) {
55
- requestAttributes =
56
- await TiledeskChatbot.allParametersStatic(
57
- this.tdcache, this.requestId
58
- );
59
- }
60
- const filler = new Filler();
61
- const url = filler.fill(action.url, requestAttributes);
62
-
63
- let headers = {};
64
- if (action.headersString) {
65
- let headersDict = action.headersString
66
- for (const [key, value] of Object.entries(headersDict)) {
67
- if (this.log) {console.log("header:", key, "value:", value)}
68
- let filled_value = filler.fill(value, requestAttributes);
69
- headers[key] = filled_value;
70
- }
71
- }
72
-
73
- let json = null;
74
- try {
75
- if (action.jsonBody && action.bodyType == "json") {
76
- if (this.log) {console.log("action.body is:", action.jsonBody);}
77
- let jsonBody = filler.fill(action.jsonBody, requestAttributes);
78
- try {
79
- json = JSON.parse(jsonBody);
80
- if (this.log) {console.log("json is:", json);}
81
- }
82
- catch(err) {
83
- console.error("Error parsing webRequest jsonBody:", jsonBody);
84
- if (callback) {
85
- if (falseIntent) {
86
- await this.chatbot.addParameter("flowError", "Error parsing jsonBody");
87
- this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes, () => {
88
- console.log('herrrrr 11111' )
89
- callback(true); // stop the flow
90
- return;
91
- });
92
- }
93
- else {
94
- console.log('herrrrr 2222' )
95
- callback(false); // continue the flow
96
- return;
97
- }
98
- }
99
- }
100
- }
101
- else if (action.formData && action.bodyType == "form-data") {
102
- let formData = filler.fill(action.formData, requestAttributes);
103
- if (this.log) {console.log("action.body is form-data:", formData);}
104
- // // fill
105
- if (formData && formData.length > 0) {
106
- for (let i = 0; i < formData.length; i++) {
107
- let field = formData[i];
108
- if (field.value) {
109
- field.value = filler.fill(field.value, requestAttributes);
110
- if (this.log) {console.log("field filled:", field.value);}
111
- }
112
- }
113
- }
114
- json = {};
115
- for (let i = 0; i < formData.length; i++) {
116
- let field = formData[i];
117
- if (field.enabled && field.value && field.type === "URL") {
118
- if (this.log) {console.log("Getting file:", field.value);}
119
- let response = await axios.get(field.value,
120
- {
121
- responseType: 'stream'
122
- }
123
- );
124
- let stream = response.data;
125
- // if (this.log) {console.log("Stream data:", stream);}
126
- json[field.name] = stream;
127
- // process.exit(0);
128
- }
129
- else if (field.enabled && field.value && field.type === "Text") {
130
- json[field.name] = field.value;
131
- }
132
- }
133
- if (this.log) {console.log("final json:", json);}
134
- }
135
- else {
136
- if (this.log) {console.log("no action upload parts");}
137
- }
138
-
139
- }
140
- catch(error) {
141
- console.error("Error", error);
142
- if (callback) {
143
- if (falseIntent) {
144
- await this.chatbot.addParameter("flowError", "Error: " + error);
145
- this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes, () => {
146
- callback(true); // stop the flow
147
- return;
148
- });
149
- }
150
- else {
151
- callback(false); // continue the flow
152
- return;
153
- }
154
- }
155
- }
156
-
157
-
158
-
159
- let timeout = this.#webrequest_timeout(action, 20000, 1, 300000);
160
-
161
- if (this.log) {console.log("webRequest URL", url);}
162
-
163
- const HTTPREQUEST = {
164
- url: url,
165
- headers: headers,
166
- json: json,
167
- method: action.method,
168
- timeout: timeout
169
- };
170
-
171
- if (this.log) {console.log("webRequest HTTPREQUEST", HTTPREQUEST);}
172
- this.#myrequest(
173
- HTTPREQUEST, async (err, res) => {
174
- if (this.log && err) {
175
- console.log("webRequest error:", err);
176
- }
177
- if (this.log) {console.log("got res:", res);}
178
- let resbody = res.data;
179
- let status = res.status;
180
- let error = res.error;
181
- await this.#assignAttributes(action, resbody, status, error)
182
- if (this.log) {console.log("webRequest resbody:", resbody);}
183
- if (err) {
184
- if (this.log) {console.error("webRequest error:", err);}
185
- if (callback) {
186
- if (falseIntent) {
187
- this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes, () => {
188
- callback(true); // stop the flow
189
- });
190
- }
191
- else {
192
- callback(false); // continue the flow
193
- }
194
- }
195
- }
196
- else if(res.status >= 200 && res.status <= 299) {
197
- if (trueIntent) {
198
- await this.#executeCondition(true, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes, () => {
199
- callback(true); // stop the flow
200
- });
201
- }
202
- else {
203
- callback(false); // continue the flow
204
- }
205
- }
206
- else {
207
- if (falseIntent) {
208
- this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes, () => {
209
- callback(true); // stop the flow
210
- });
211
- }
212
- else {
213
- callback(false); // continue the flow
214
- }
215
- }
216
- }
217
- );
218
- }
219
-
220
- async #executeCondition(result, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes, callback) {
221
- let trueIntentDirective = null;
222
- if (trueIntent) {
223
- trueIntentDirective = DirIntent.intentDirectiveFor(trueIntent, trueIntentAttributes);
224
- }
225
- let falseIntentDirective = null;
226
- if (falseIntent) {
227
- falseIntentDirective = DirIntent.intentDirectiveFor(falseIntent, falseIntentAttributes);
228
- }
229
- if (result === true) {
230
- if (trueIntentDirective) {
231
- this.intentDir.execute(trueIntentDirective, () => {
232
- callback();
233
- });
234
- }
235
- else {
236
- if (this.log) {console.log("No trueIntentDirective specified");}
237
- callback();
238
- }
239
- }
240
- else {
241
- if (falseIntentDirective) {
242
- this.intentDir.execute(falseIntentDirective, () => {
243
- callback();
244
- });
245
- }
246
- else {
247
- if (this.log) {console.log("No falseIntentDirective specified");}
248
- callback();
249
- }
250
- }
251
- }
252
-
253
- async #assignAttributes(action, resbody, status, error) {
254
- if (this.log) {
255
- console.log("assignAttributes resbody:", resbody)
256
- console.log("assignAttributes error:", error)
257
- console.log("assignAttributes status:", status)
258
- console.log("assignAttributes action:", action)
259
- }
260
- if (this.context.tdcache) {
261
- if (action.assignResultTo && resbody) {
262
- if (this.log) {console.log("assign assignResultTo:", resbody);}
263
- await TiledeskChatbot.addParameterStatic(this.context.tdcache, this.context.requestId, action.assignResultTo, resbody);
264
- }
265
- if (action.assignErrorTo && error) {
266
- if (this.log) {console.log("assign assignResultTo:", error);}
267
- await TiledeskChatbot.addParameterStatic(this.context.tdcache, this.context.requestId, action.assignErrorTo, error);
268
- }
269
- if (action.assignStatusTo && status) {
270
- if (this.log) {console.log("assign assignStatusTo:", status);}
271
- await TiledeskChatbot.addParameterStatic(this.context.tdcache, this.context.requestId, action.assignStatusTo, status);
272
- }
273
- // Debug log
274
- if (this.log) {
275
- const all_parameters = await TiledeskChatbot.allParametersStatic(this.context.tdcache, this.context.requestId);
276
- for (const [key, value] of Object.entries(all_parameters)) {
277
- if (this.log) {console.log("(webRequest) request parameter:", key, "value:", value, "type:", typeof value)}
278
- }
279
- }
280
- }
281
- }
282
-
283
- #myrequest(options, callback) {
284
- try {
285
- if (this.log) {
286
- console.log("API URL:", options.url);
287
- //console.log("** Options:", JSON.stringify(options));
288
- // Stringify "options". FIX THE STRINGIFY OF CIRCULAR STRUCTURE BUG - START
289
- let cache = [];
290
- let str_Options = JSON.stringify(options, function(key, value) { // try to use a separate function
291
- if (typeof value === 'object' && value != null) {
292
- if (cache.indexOf(value) !== -1) {
293
- return;
294
- }
295
- cache.push(value);
296
- }
297
- return value;
298
- });
299
- console.log("** Options:", str_Options);
300
- }
301
- let axios_options = {
302
- url: options.url,
303
- method: options.method,
304
- params: options.params,
305
- headers: options.headers,
306
- timeout: options.timeout,
307
- maxContentLength: 10000000, // max 10mb response size
308
- maxBodyLength: 10000000 // max 10mb request body size
309
- }
310
-
311
- if (options.json !== null) {
312
- axios_options.data = options.json
313
- }
314
- // if (this.log) {
315
- // console.log("axios_options:", JSON.stringify(axios_options));
316
- // }
317
- if (options.url.startsWith("https:")) {
318
- const httpsAgent = new https.Agent({
319
- rejectUnauthorized: false,
320
- });
321
- axios_options.httpsAgent = httpsAgent;
322
- }
323
-
324
- axios(axios_options)
325
- .then((res) => {
326
- if (this.log) {
327
- console.log("Success Response:", res);
328
- console.log("Response for url:", options.url);
329
- console.log("Response headers:\n", JSON.stringify(res.headers));
330
- }
331
- if (callback) {
332
- callback(null, res);
333
- }
334
- })
335
- .catch( (err) => {
336
- if (this.log) {
337
- if (err.response) {
338
- console.log("Error Response data:", err.response.data);
339
- }
340
- // FIX THE STRINGIFY OF CIRCULAR STRUCTURE BUG - START
341
- let cache = [];
342
- let error_log = JSON.stringify(err, function(key, value) { // try to use a separate function
343
- if (typeof value === 'object' && value != null) {
344
- if (cache.indexOf(value) !== -1) {
345
- return;
346
- }
347
- cache.push(value);
348
- }
349
- return value;
350
- });
351
- console.error("An error occurred: ", error_log);
352
- // FIX THE STRINGIFY OF CIRCULAR STRUCTURE BUG - END
353
- // console.error("An error occurred:", JSON.stringify(err));
354
- }
355
- if (callback) {
356
- let status = 1000;
357
- let cache = [];
358
- let str_error = JSON.stringify(err, function(key, value) { // try to use a separate function
359
- if (typeof value === 'object' && value != null) {
360
- if (cache.indexOf(value) !== -1) {
361
- return;
362
- }
363
- cache.push(value);
364
- }
365
- return value;
366
- });
367
- let error = JSON.parse(str_error) // "status" disappears without this trick
368
- let errorMessage = JSON.stringify(error);
369
- if (error.status) {
370
- status = error.status;
371
- }
372
- if (error.message) {
373
- errorMessage = error.message;
374
- }
375
- let data = null;
376
- if (err.response) {
377
- data = err.response.data;
378
- }
379
- callback(
380
- null, {
381
- status: status,
382
- data: data,
383
- error: errorMessage
384
- }
385
- );
386
- }
387
- });
388
- }
389
- catch(error) {
390
- console.error("Error:", error);
391
- }
392
- }
393
-
394
- #webrequest_timeout(action, default_timeout, min, max) {
395
- let timeout = default_timeout;
396
- if (!action.settings) {
397
- return timeout;
398
- }
399
- // console.log("default timeout:", timeout);
400
- // console.log("action.settings:", action.settings);
401
- // console.log("action.settings.timeout:", action.settings.timeout);
402
- // console.log("typeof action.settings.timeout:", typeof action.settings.timeout);
403
- // console.log("action.settings.timeout > min", action.settings.timeout > min)
404
- // console.log("action.settings.timeout < max", action.settings.timeout < max)
405
-
406
- if (action.settings.timeout) {
407
- if ((typeof action.settings.timeout === "number") && action.settings.timeout > min && action.settings.timeout < max) {
408
- timeout = Math.round(action.settings.timeout)
409
- // console.log("new timeout:", timeout);
410
- }
411
- }
412
- // console.log("returning timeout:", timeout);
413
- return timeout
414
- }
415
-
416
- }
417
-
418
- module.exports = { DirWebRequestV2 };