@tiledesk/tiledesk-tybot-connector 0.2.33 → 0.2.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/CHANGELOG.md CHANGED
@@ -5,6 +5,16 @@
5
5
  available on:
6
6
  ▶️ https://www.npmjs.com/package/@tiledesk/tiledesk-tybot-connector
7
7
 
8
+ # v0.2.35
9
+ - added validation check for requests ids (support-group- && automation-request-)
10
+ - refactorized GptTask, AskGPT and Qapla actions in order to support integrations
11
+ - added integrated condition in GptTask
12
+ - added automatic JSON conversion in GptTask
13
+
14
+ # v0.2.34
15
+ - stopOnConditionMet is always true in DirJSONCondition
16
+ - Fixes the WebRequestV2 branching
17
+
8
18
  # v0.2.33
9
19
  - Added lead attributes (userEmail, userPhone, userFullname, userLeadId, userCompany)
10
20
 
package/index.js CHANGED
@@ -47,6 +47,7 @@ router.post('/ext/:botid', async (req, res) => {
47
47
  const requestId = message.request.request_id;
48
48
  const projectId = message.id_project;
49
49
  if (log) {console.log("message.id_project:", message.id_project);}
50
+
50
51
  // adding info for internal context workflow
51
52
  message.request.bot_id = botId;
52
53
  if (message.request.id_project === null || message.request.id_project === undefined) {
@@ -59,8 +60,19 @@ router.post('/ext/:botid', async (req, res) => {
59
60
  // } else {
60
61
  // return res.status(400).send({ "success": false, "message": "Invalid request_id"})
61
62
  // }
62
- res.status(200).send({"success":true});
63
-
63
+ // res.status(200).send({"success":true});
64
+
65
+ // validate reuqestId
66
+ let isValid = TiledeskChatbotUtil.validateRequestId(requestId, projectId);
67
+ if (isValid) {
68
+ res.status(200).send({"success":true});
69
+ }
70
+ else {
71
+ res.status(400).send({"success": false, error: "Request id is invalid"});
72
+ // console.log("request id, projectId:", requestId, projectId)
73
+ // process.exit(0)
74
+ }
75
+
64
76
  const request_botId_key = "tilebot:botId_requests:" + requestId;
65
77
  await tdcache.set(
66
78
  request_botId_key,
@@ -626,6 +626,34 @@ class TiledeskChatbotUtil {
626
626
  }
627
627
  }
628
628
 
629
+ static validateRequestId(requestId, projectId) {
630
+ // console.log("checking requestId:", requestId, projectId)
631
+ let isValid = false;
632
+ if (requestId.startsWith("support-group-")) {
633
+ const parts = requestId.split("-");
634
+ // console.log("parts support request:", parts);
635
+ if (parts.length === 4) {
636
+ isValid = (parts[0] === "support" && parts[1] === "group" && parts[2] === projectId && parts[3].length > 0);
637
+ }
638
+ else {
639
+ isValid = false;
640
+ }
641
+ } else if (requestId.startsWith("automation-request-")) {
642
+ const parts = requestId.split("-");
643
+ // console.log("parts automation request:", parts);
644
+ if (parts.length === 4) {
645
+ isValid = (parts[0] === "automation" && parts[1] === "request" && parts[2] === projectId && parts[3].length > 0);
646
+ }
647
+ else {
648
+ isValid = false;
649
+ }
650
+ }
651
+ else {
652
+ isValid = false;
653
+ }
654
+ return isValid;
655
+ }
656
+
629
657
  }
630
658
 
631
659
  module.exports = { TiledeskChatbotUtil };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiledesk/tiledesk-tybot-connector",
3
- "version": "0.2.33",
3
+ "version": "0.2.35",
4
4
  "description": "Tiledesk Tybot connector",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -587,15 +587,29 @@ class DirectivesChatbotPlug {
587
587
  });
588
588
  }
589
589
  else if (directive_name === Directives.ASK_GPT) {
590
- new DirAskGPT(context).execute(directive, async () => {
591
- let next_dir = await this.nextDirective(this.directives);
592
- this.process(next_dir);
590
+ new DirAskGPT(context).execute(directive, async (stop) => {;
591
+ if (context.log) { console.log("AskGPT stop?", stop);}
592
+ if (stop == true) {
593
+ if (context.log) { console.log("Stopping Actions on:", JSON.stringify(directive));}
594
+ this.theend();
595
+ }
596
+ else {
597
+ let next_dir = await this.nextDirective(this.directives);
598
+ this.process(next_dir);
599
+ }
593
600
  });
594
601
  }
595
602
  else if (directive_name === Directives.GPT_TASK) {
596
- new DirGptTask(context).execute(directive, async () => {
597
- let next_dir = await this.nextDirective(this.directives);
598
- this.process(next_dir);
603
+ new DirGptTask(context).execute(directive, async (stop) => {
604
+ if (context.log) { console.log("AskGPT stop?", stop);}
605
+ if (stop == true) {
606
+ if (context.log) { console.log("Stopping Actions on:", JSON.stringify(directive));}
607
+ this.theend();
608
+ }
609
+ else {
610
+ let next_dir = await this.nextDirective(this.directives);
611
+ this.process(next_dir);
612
+ }
599
613
  });
600
614
  }
601
615
  else if (directive_name === Directives.WHATSAPP_ATTRIBUTE) {
@@ -29,28 +29,52 @@ class DirAskGPT {
29
29
  callback();
30
30
  return;
31
31
  }
32
- this.go(action, () => {
33
- callback();
32
+ this.go(action, (stop) => {
33
+ callback(stop);
34
34
  })
35
35
  }
36
36
 
37
37
  async go(action, callback) {
38
- if (this.log) { console.log("AskGPT action:", JSON.stringify(action)); }
38
+ if (this.log) { console.log("DirAskGPT action:", JSON.stringify(action)); }
39
39
  if (!this.tdcache) {
40
40
  console.error("Error: DirAskGPT tdcache is mandatory");
41
41
  callback();
42
42
  return;
43
43
  }
44
44
 
45
- if (!action.question) {
46
- console.error("Error: DirAskGPT questionAttribute is mandatory");
47
- callback();
45
+ let trueIntent = action.trueIntent;
46
+ let falseIntent = action.falseIntent;
47
+ let trueIntentAttributes = action.trueIntentAttributes;
48
+ let falseIntentAttributes = action.falseIntentAttributes;
49
+
50
+ if (this.log) {
51
+ console.log("DirAskGPT trueIntent", trueIntent)
52
+ console.log("DirAskGPT falseIntent", falseIntent)
53
+ console.log("DirAskGPT trueIntentAttributes", trueIntentAttributes)
54
+ console.log("DirAskGPT falseIntentAttributes", falseIntentAttributes)
55
+ }
56
+
57
+ // default values
58
+ let answer = "No answers";
59
+ let source = null;
60
+
61
+ if (!action.question || action.question === '') {
62
+ console.error("Error: DirAskGPT question attribute is mandatory. Executing condition false...");
63
+ await this.#assignAttributes(action, answer, source);
64
+ if (falseIntent) {
65
+ await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
66
+ }
67
+ callback(true);
48
68
  return;
49
69
  }
50
70
 
51
71
  if (!action.kbid) {
52
- console.error("Error: DirAskGPT kbid is mandatory");
53
- callback();
72
+ console.error("Error: DirAskGPT kbid attribute is mandatory. Executing condition false...");
73
+ await this.#assignAttributes(action, answer, source);
74
+ if (falseIntent) {
75
+ await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes)
76
+ }
77
+ callback(true);
54
78
  return;
55
79
  }
56
80
 
@@ -63,106 +87,202 @@ class DirAskGPT {
63
87
  const filler = new Filler();
64
88
  const filled_question = filler.fill(action.question, requestVariables);
65
89
 
66
- let trueIntent = action.trueIntent;
67
- let falseIntent = action.falseIntent;
68
- let trueIntentAttributes = action.trueIntentAttributes;
69
- let falseIntentAttributes = action.falseIntentAttributes;
70
-
90
+ const server_base_url = process.env.API_ENDPOINT || process.env.API_URL;
91
+ const pai_url = process.env.PAI_ENDPOINT || process.env.GPT_ENDPOINT;
71
92
  if (this.log) {
72
- console.log("trueIntent",trueIntent )
73
- console.log("falseIntent",falseIntent )
74
- console.log("trueIntentAttributes",trueIntentAttributes )
75
- console.log("falseIntentAttributes",falseIntentAttributes )
93
+ console.log("DirAskGPT ApiEndpoint URL: ", server_base_url);
94
+ console.log("DirAskGPT ApiEndpoint URL: ", pai_url);
76
95
  }
77
96
 
78
- const server_base_url = process.env.API_ENDPOINT || process.env.API_URL;
79
- const kb_url = server_base_url + "/" + this.context.projectId + "/kbsettings";
80
- if (this.log) { console.log("ApiEndpoint URL: ", kb_url); }
81
- const KB_HTTPREQUEST = {
82
- url: kb_url,
97
+ const INTEGRATIONS_HTTPREQUEST = {
98
+ url: server_base_url + "/" + this.context.projectId + "/integration/name/openai",
83
99
  headers: {
84
100
  'Content-Type': 'application/json',
85
101
  'Authorization': 'JWT ' + this.context.token
86
102
  },
87
103
  method: "GET"
88
104
  }
89
- if (this.log) { console.log("AskGPT KB_HTTPREQUEST", KB_HTTPREQUEST); }
105
+ if (this.log) { console.log("DirGptTask INTEGRATIONS_HTTPREQUEST ", INTEGRATIONS_HTTPREQUEST) }
90
106
 
91
- this.myrequest(
92
- KB_HTTPREQUEST, async (err, resbody) => {
93
- if (this.log) { console.log("AskGPT resbody:", resbody); }
107
+ this.#myrequest(
108
+ INTEGRATIONS_HTTPREQUEST, async (err, integration) => {
94
109
  if (err) {
95
- if (this.log) { console.error("AskGPT error:", err); }
96
110
  if (callback) {
97
- let answer = "No answers";
98
- let source = null;
99
- await this.#assignAttributes(action, answer, source);
100
- this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes, () => {
101
- callback(false); // continue the flow
102
- });
111
+ console.error("DirAskGPT get integrations error: ", err);
112
+ callback();
113
+ return;
103
114
  }
104
115
  } else if (callback) {
105
- if (this.log) {
106
- console.log("resbody", resbody);
107
- console.log("gptkey", resbody.gptkey);
116
+ if (this.log) { console.log("DirAskGPT get integrations resbody: ", integration) };
117
+
118
+ let key;
119
+ if (integration &&
120
+ integration.value) {
121
+ key = integration.value.apikey;
108
122
  }
109
123
 
110
- if (!resbody.gptkey) {
111
- let answer = "No answers";
112
- let source = null;
113
- await this.#assignAttributes(action, answer, source);
114
- this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes, () => {
115
- callback(false); // continue the flow
116
- });
124
+ // key not present in integrations - for retro compatibility search in kbsettings
125
+ if (!key) {
126
+
127
+ if (this.log) { console.log("DirAskGPT - Key not found in Integrations. Searching in kb settings..."); }
128
+
129
+ const KB_HTTPREQUEST = {
130
+ url: server_base_url + "/" + this.context.projectId + "/kbsettings",
131
+ headers: {
132
+ 'Content-Type': 'application/json',
133
+ 'Authorization': 'JWT ' + this.context.token
134
+ },
135
+ method: "GET"
136
+ }
137
+ if (this.log) { console.log("DirAskGPT KB_HTTPREQUEST", KB_HTTPREQUEST); }
138
+
139
+ this.#myrequest(
140
+ KB_HTTPREQUEST, async (err, resbody) => {
141
+ if (this.log) { console.log("DirAskGPT get kbs resbody:", resbody); }
142
+
143
+ if (err) {
144
+ if (this.log) { console.error("DirAskGPT get kbs error:", err); }
145
+ if (callback) {
146
+ await this.#assignAttributes(action, answer, source);
147
+ console.error("Error: DirAskGPT missing gptkey. Executing condition false...");
148
+ if (falseIntent) {
149
+ this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
150
+ }
151
+ callback(true);
152
+ return;
153
+ }
154
+
155
+ } else if (callback) {
156
+ if (this.log) { console.log("DirAskGPT gptkey: " + resbody.gptkey); }
157
+
158
+ if (!resbody.gptkey) {
159
+ await this.#assignAttributes(action, answer, source);
160
+ console.error("Error: DirAskGPT missing gptkey. Executing condition false...");
161
+ if (falseIntent) {
162
+ this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
163
+ }
164
+ callback(true);
165
+ return;
166
+
167
+ } else {
168
+
169
+ if (this.log) { console.log("DirAskGpt - Key found in KbSettings") };
170
+
171
+ key = resbody.gptkey;
172
+
173
+ let json = {
174
+ question: filled_question,
175
+ kbid: action.kbid,
176
+ gptkey: key
177
+ };
178
+ if (this.log) { console.log("DirAskGPT json:", json); }
179
+
180
+ const HTTPREQUEST = {
181
+ url: pai_url,
182
+ json: json,
183
+ method: "POST"
184
+ }
185
+ if (this.log) { console.log("DirAskGPT HTTPREQUEST", HTTPREQUEST); }
186
+
187
+ this.#myrequest(
188
+ HTTPREQUEST, async (err, resbody) => {
189
+ if (this.log && err) {
190
+ console.log("DirAskGPT error: ", err);
191
+ }
192
+ if (this.log) { console.log("DirAskGPT resbody:", resbody); }
193
+ let answer = resbody.answer;
194
+ let source = resbody.source_url;
195
+ await this.#assignAttributes(action, answer, source);
196
+
197
+ if (err) {
198
+ if (callback) {
199
+ if (falseIntent) {
200
+ await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
201
+ }
202
+ callback(true);
203
+ return;
204
+ }
205
+ }
206
+ else if (resbody.success === true) {
207
+ if (trueIntent) {
208
+ await this.#executeCondition(true, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
209
+ }
210
+ callback(); // se la condition è true si deve ritornare true nella callback ugualmente?
211
+ return;
212
+ } else {
213
+ if (falseIntent) {
214
+ await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
215
+ }
216
+ callback(true);
217
+ return;
218
+ }
219
+ }
220
+ )
221
+ }
222
+ }
223
+ }
224
+ )
225
+
117
226
  } else {
227
+
228
+ if (this.log) { console.log("DirGptTask - Key found in Integrations") };
229
+
118
230
  let json = {
119
- "question": filled_question,
120
- "kbid": action.kbid,
121
- "gptkey": resbody.gptkey
231
+ question: filled_question,
232
+ kbid: action.kbid,
233
+ gptkey: key
122
234
  };
123
- if (this.log) {console.log("question_gpt:", json);}
235
+ if (this.log) { console.log("DirAskGPT json:", json); }
124
236
 
125
- const url = process.env.GPT_ENDPOINT; //"https://tiledesk-playground.azurewebsites.net/api/qa"; // TODO INSERIRE IN ENV
126
- if (this.log) {console.log("DirAskGPT URL", url);}
127
237
  const HTTPREQUEST = {
128
- url: url,
238
+ url: pai_url,
129
239
  json: json,
130
240
  method: "POST"
131
241
  }
132
- if (this.log) {console.log("AskGPT HTTPREQUEST", HTTPREQUEST);}
133
- this.myrequest(
242
+ if (this.log) { console.log("DirAskGPT HTTPREQUEST", HTTPREQUEST); }
243
+
244
+ this.#myrequest(
134
245
  HTTPREQUEST, async (err, resbody) => {
135
246
  if (this.log && err) {
136
- console.log("AskGPT error: ", err);
247
+ console.log("DirAskGPT error: ", err);
137
248
  }
138
- if (this.log) {console.log("AskGPT resbody:", resbody);}
249
+ if (this.log) { console.log("DirAskGPT resbody:", resbody); }
139
250
  let answer = resbody.answer;
140
251
  let source = resbody.source_url;
141
252
  await this.#assignAttributes(action, answer, source);
142
253
 
143
254
  if (err) {
144
255
  if (callback) {
145
- this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes, () => {
146
- callback(false); // continue the flow
147
- });
256
+ if (falseIntent) {
257
+ await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
258
+ }
259
+ callback(true);
260
+ return;
148
261
  }
149
- }
262
+ }
150
263
  else if (resbody.success === true) {
151
-
152
- await this.#executeCondition(true, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes, () => {
153
- callback(); // stop the flow
154
- })
155
- } else { //resbody.success === false
156
- await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes, () => {
157
- callback(false); // stop the flow
158
- })
264
+ if (trueIntent) {
265
+ await this.#executeCondition(true, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
266
+ }
267
+ callback(); // se la condition è true si deve ritornare true nella callback ugualmente?
268
+ return;
269
+ } else {
270
+ if (falseIntent) {
271
+ await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
272
+ }
273
+ callback(true);
274
+ return;
159
275
  }
160
276
  }
161
277
  )
278
+
162
279
  }
280
+
163
281
  }
164
282
  }
165
283
  )
284
+
285
+
166
286
  }
167
287
 
168
288
  async #executeCondition(result, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes, callback) {
@@ -177,23 +297,31 @@ class DirAskGPT {
177
297
  if (result === true) {
178
298
  if (trueIntentDirective) {
179
299
  this.intentDir.execute(trueIntentDirective, () => {
180
- callback();
300
+ if (callback) {
301
+ callback();
302
+ }
181
303
  })
182
304
  }
183
305
  else {
184
306
  if (this.log) { console.log("No trueIntentDirective specified"); }
185
- callback();
307
+ if (callback) {
308
+ callback();
309
+ }
186
310
  }
187
311
  }
188
312
  else {
189
313
  if (falseIntentDirective) {
190
314
  this.intentDir.execute(falseIntentDirective, () => {
191
- callback();
315
+ if (callback) {
316
+ callback();
317
+ }
192
318
  });
193
319
  }
194
320
  else {
195
321
  if (this.log) { console.log("No falseIntentDirective specified"); }
196
- callback();
322
+ if (callback) {
323
+ callback();
324
+ }
197
325
  }
198
326
  }
199
327
  }
@@ -224,7 +352,7 @@ class DirAskGPT {
224
352
  }
225
353
  }
226
354
 
227
- myrequest(options, callback) {
355
+ #myrequest(options, callback) {
228
356
  if (this.log) {
229
357
  console.log("API URL:", options.url);
230
358
  console.log("** Options:", JSON.stringify(options));
@@ -2,6 +2,7 @@ const axios = require("axios").default;
2
2
  const { TiledeskChatbot } = require("../../models/TiledeskChatbot");
3
3
  const { Filler } = require("../Filler");
4
4
  let https = require("https");
5
+ const { DirIntent } = require("./DirIntent");
5
6
  require('dotenv').config();
6
7
 
7
8
  class DirGptTask {
@@ -13,6 +14,7 @@ class DirGptTask {
13
14
  this.context = context;
14
15
  this.tdcache = this.context.tdcache;
15
16
  this.requestId = this.context.requestId;
17
+ this.intentDir = new DirIntent(context);
16
18
  this.log = context.log;
17
19
  }
18
20
 
@@ -21,30 +23,47 @@ class DirGptTask {
21
23
  let action;
22
24
  if (directive.action) {
23
25
  action = directive.action;
24
- console.log("-----> GPT TASK ACTION: \n", action);
25
26
  }
26
27
  else {
27
28
  console.error("Incorrect directive: ", JSON.stringify(directive));
28
29
  callback();
29
30
  return;
30
31
  }
31
- this.go(action, () => {
32
- callback();
32
+ this.go(action, (stop) => {
33
+ callback(stop);
33
34
  })
34
35
  }
35
36
 
36
37
  async go(action, callback) {
37
- if (this.log) { console.log("GptTask action:", JSON.stringify(action)); }
38
- console.log("GptTask action:", JSON.stringify(action));
39
- console.log("GptTask action model:", action.model);
38
+ if (this.log) { console.log("DirGptTask action:", JSON.stringify(action)); }
40
39
  if (!this.tdcache) {
41
40
  console.error("Error: DirGptTask tdcache is mandatory");
42
41
  callback();
43
42
  return;
44
43
  }
45
44
 
46
- if (!action.question) {
47
- console.error("Error: DirGptTask question attribute is mandatory");
45
+ let trueIntent = action.trueIntent;
46
+ let falseIntent = action.falseIntent;
47
+ let trueIntentAttributes = action.trueIntentAttributes;
48
+ let falseIntentAttributes = action.falseIntentAttributes;
49
+
50
+ if (this.log) {
51
+ console.log("DirAskGPT trueIntent", trueIntent)
52
+ console.log("DirAskGPT falseIntent", falseIntent)
53
+ console.log("DirAskGPT trueIntentAttributes", trueIntentAttributes)
54
+ console.log("DirAskGPT falseIntentAttributes", falseIntentAttributes)
55
+ }
56
+
57
+ // default value
58
+ let answer = "No answer.";
59
+
60
+ if (!action.question || action.question === '') {
61
+ console.error("Error: DirGptTask question attribute is mandatory. Executing condition false...")
62
+ if (falseIntent) {
63
+ await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
64
+ callback(true);
65
+ return;
66
+ }
48
67
  callback();
49
68
  return;
50
69
  }
@@ -55,15 +74,6 @@ class DirGptTask {
55
74
  this.tdcache, this.requestId
56
75
  )
57
76
 
58
- if (this.log) {
59
- console.log("*** GPT PARTITA ***")
60
- const all_parameters = await TiledeskChatbot.allParametersStatic(this.context.tdcache, this.context.requestId);
61
- for (const [key, value] of Object.entries(all_parameters)) {
62
- if (this.log) { console.log("(askgpt) request parameter:", key, "value:", value, "type:", typeof value) }
63
- }
64
- }
65
-
66
- // not necessary ?
67
77
  const filler = new Filler();
68
78
  const filled_question = filler.fill(action.question, requestVariables);
69
79
 
@@ -71,43 +81,161 @@ class DirGptTask {
71
81
  let temperature = action.temperature;
72
82
 
73
83
  if (this.log) {
74
- console.log("max_tokens: ", max_tokens);
75
- console.log("temperature: ", temperature);
84
+ console.log("DirGptTask max_tokens: ", max_tokens);
85
+ console.log("DirGptTask temperature: ", temperature);
76
86
  }
77
87
 
78
88
  const server_base_url = process.env.API_ENDPOINT || process.env.API_URL;
79
- const kb_url = server_base_url + "/" + this.context.projectId + "/kbsettings";
80
- if (this.log) { console.log("ApiEndpoint URL: ", kb_url); }
81
- const KB_HTTPREQUEST = {
82
- url: kb_url,
89
+ const openai_url = process.env.OPENAI_ENDPOINT + "/chat/completions";
90
+ if (this.log) {
91
+ console.log("DirGptTask server_base_url ", server_base_url);
92
+ console.log("DirGptTask openai_url ", openai_url);
93
+ }
94
+
95
+ const INTEGRATIONS_HTTPREQUEST = {
96
+ url: server_base_url + "/" + this.context.projectId + "/integration/name/openai",
83
97
  headers: {
84
98
  'Content-Type': 'application/json',
85
99
  'Authorization': 'JWT ' + this.context.token
86
100
  },
87
101
  method: "GET"
88
102
  }
89
- if (this.log) { console.log("GptTask KB_HTTPREQUEST", KB_HTTPREQUEST); }
103
+ if (this.log) { console.log("DirGptTask INTEGRATIONS_HTTPREQUEST ", INTEGRATIONS_HTTPREQUEST) }
90
104
 
91
105
  this.#myrequest(
92
- KB_HTTPREQUEST, async (err, resbody) => {
106
+ INTEGRATIONS_HTTPREQUEST, async (err, integration) => {
93
107
  if (err) {
94
108
  if (callback) {
95
- console.error("(httprequest) Get KnowledgeBase err:", err);
96
- callback();
109
+ console.error("(httprequest) DirGptTask get integrations err:", err);
110
+ // Don't stop the flow here. Try aniway to retrieve the key from KBs
111
+ // callback();
112
+ // return;
97
113
  }
98
114
  } else if (callback) {
99
- if (this.log) {
100
- console.log("Get KnowledgeBase settings resbody:", resbody);
101
- console.log("gptkey: ", resbody.gptkey);
115
+ if (this.log) { console.log("DirGptTask get integration resbody: ", integration); }
116
+
117
+ let key;
118
+ if (integration &&
119
+ integration.value) {
120
+ key = integration.value.apikey;
102
121
  }
103
122
 
104
- let gptkey = resbody.gptkey;
123
+ // key not present in integrations - for retro compatibility search in kbsettings
124
+ if (!key) {
105
125
 
106
- if (!gptkey) {
107
- console.error("Error: DirGptTask gptkey attribute is mandatory");
108
- callback();
126
+ // if (this.log) { console.log("DirGptTask - Key not found in Integrations. Searching in kb settings...")}
127
+ if (this.log) { console.log("DirGptTask - Key not found in Integrations. Searching in kb settings..."); }
128
+
129
+ const KB_HTTPREQUEST = {
130
+ url: server_base_url + "/" + this.context.projectId + "/kbsettings",
131
+ headers: {
132
+ 'Content-Type': 'application/json',
133
+ 'Authorization': 'JWT ' + this.context.token
134
+ },
135
+ method: "GET"
136
+ }
137
+ if (this.log) { console.log("DirGptTask KB_HTTPREQUEST", KB_HTTPREQUEST); }
138
+
139
+ this.#myrequest(
140
+ KB_HTTPREQUEST, async (err, resbody) => {
141
+ if (err) {
142
+ if (callback) {
143
+ console.error("(httprequest) DirGptTask Get KnowledgeBase err:", err);
144
+ await this.#assignAttributes(action, answer);
145
+ if (falseIntent) {
146
+ await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
147
+ callback(true);
148
+ return;
149
+ }
150
+ callback();
151
+ return;
152
+ }
153
+ } else if (callback) {
154
+ if (this.log) { console.log("DirGptTask Get KnowledgeBase settings resbody:", resbody); }
155
+
156
+ if (!resbody.gptkey) {
157
+ await this.#assignAttributes(action, answer);
158
+ if (falseIntent) {
159
+ await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
160
+ callback(true);
161
+ return;
162
+ }
163
+ callback();
164
+ return;
165
+
166
+ } else {
167
+
168
+ if (this.log) { console.log("DirGptTask - Key found in KbSettings") };
169
+
170
+ key = resbody.gptkey;
171
+
172
+ let json = {
173
+ "model": action.model,
174
+ "messages": [
175
+ {
176
+ "role": "user",
177
+ "content": filled_question
178
+ }
179
+ ],
180
+ "max_tokens": action.max_tokens,
181
+ "temperature": action.temperature
182
+ }
183
+
184
+ let message = { role: "", content: "" };
185
+ if (action.context) {
186
+ message.role = "system";
187
+ message.content = action.context;
188
+ json.messages.unshift(message);
189
+ }
190
+ if (this.log) { console.log("DirGptTask json: ", json) }
191
+
192
+ const HTTPREQUEST = {
193
+ url: openai_url,
194
+ headers: {
195
+ 'Content-Type': 'application/json',
196
+ 'Authorization': 'Bearer ' + key
197
+ },
198
+ json: json,
199
+ method: 'POST'
200
+ }
201
+ if (this.log) { console.log("DirGptTask HTTPREQUEST: ", HTTPREQUEST); }
202
+ this.#myrequest(
203
+ HTTPREQUEST, async (err, resbody) => {
204
+ if (err) {
205
+ if (this.log) {
206
+ console.error("(httprequest) DirGptTask openai err:", err);
207
+ console.error("(httprequest) DirGptTask openai err:", err.response.data);
208
+ }
209
+ await this.#assignAttributes(action, answer);
210
+ if (falseIntent) {
211
+ await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
212
+ callback(true);
213
+ return;
214
+ }
215
+ callback();
216
+ return;
217
+ } else {
218
+ if (this.log) { console.log("DirGptTask resbody: ", JSON.stringify(resbody)); }
219
+ answer = resbody.choices[0].message.content;
220
+ await this.#assignAttributes(action, answer);
221
+ if (trueIntent) {
222
+ await this.#executeCondition(true, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
223
+ callback(true);
224
+ return;
225
+ }
226
+ callback();
227
+ return;
228
+ }
229
+ }
230
+ )
231
+ }
232
+ }
233
+ }
234
+ )
109
235
  } else {
110
236
 
237
+ if (this.log) { console.log("DirGptTask - Key found in Integrations") };
238
+
111
239
  let json = {
112
240
  "model": action.model,
113
241
  "messages": [
@@ -119,58 +247,117 @@ class DirGptTask {
119
247
  "max_tokens": action.max_tokens,
120
248
  "temperature": action.temperature
121
249
  }
122
-
250
+
123
251
  let message = { role: "", content: "" };
124
252
  if (action.context) {
125
253
  message.role = "system";
126
254
  message.content = action.context;
127
255
  json.messages.unshift(message);
128
256
  }
257
+ if (this.log) { console.log("DirGptTask json: ", json) }
129
258
 
130
- if (this.log) { console.log("json: ", json) }
131
-
132
- const openai_url = process.env.OPENAI_ENDPOINT + "/chat/completions";
133
- if (this.log) { console.log("OpenAi endpoint URL: ", openai_url); }
134
259
  const HTTPREQUEST = {
135
260
  url: openai_url,
136
261
  headers: {
137
262
  'Content-Type': 'application/json',
138
- 'Authorization': 'Bearer ' + gptkey
263
+ 'Authorization': 'Bearer ' + key
139
264
  },
140
265
  json: json,
141
266
  method: 'POST'
142
267
  }
143
- if (this.log) { console.log(" ### GptTask HTTPREQUEST: ", HTTPREQUEST); }
268
+ if (this.log) { console.log("DirGptTask HTTPREQUEST: ", HTTPREQUEST); }
144
269
  this.#myrequest(
145
270
  HTTPREQUEST, async (err, resbody) => {
146
271
  if (err) {
147
272
  if (this.log) {
148
- console.error(" ### (httprequest) GptTask openai err:", err);
149
- console.error(" ### (httprequest) GptTask openai err:", err.response.data);
273
+ console.error("(httprequest) DirGptTask openai err:", err);
274
+ console.error("(httprequest) DirGptTask openai err:", err.response.data);
150
275
  }
151
- let answer = "No answer.";
152
- if (this.log) { console.log("answer: ", answer);}
153
276
  await this.#assignAttributes(action, answer);
277
+ if (falseIntent) {
278
+ await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
279
+ callback(true);
280
+ return;
281
+ }
154
282
  callback();
283
+ return;
155
284
  } else {
156
- if (this.log) { console.log(" ### GptTask resbody: ", JSON.stringify(resbody)); }
157
- let answer = resbody.choices[0].message.content;
158
- if (this.log) { console.log("answer: ", answer);}
159
- await this.#assignAttributes(action, answer);
285
+ if (this.log) { console.log("DirGptTask resbody: ", JSON.stringify(resbody)); }
286
+ answer = resbody.choices[0].message.content;
287
+ // check if answer is a json
288
+ let answer_json = await this.convertToJson(answer);
289
+ await this.#assignAttributes(action, answer_json);
290
+ if (trueIntent) {
291
+ await this.#executeCondition(true, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
292
+ callback(true);
293
+ return;
294
+ }
160
295
  callback();
296
+ return;
161
297
  }
162
-
163
298
  }
164
299
  )
165
300
 
166
301
  }
167
-
168
302
  }
169
303
  }
170
304
  )
305
+ }
306
+
307
+ async convertToJson(data) {
308
+
309
+ return new Promise((resolve) => {
310
+ let json = null;
311
+ try {
312
+ json = JSON.parse(data);
313
+ resolve(json)
314
+ } catch(err) {
315
+ resolve(data)
316
+ }
317
+ })
171
318
 
172
319
  }
173
320
 
321
+ async #executeCondition(result, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes, callback) {
322
+ let trueIntentDirective = null;
323
+ if (trueIntent) {
324
+ trueIntentDirective = DirIntent.intentDirectiveFor(trueIntent, trueIntentAttributes);
325
+ }
326
+ let falseIntentDirective = null;
327
+ if (falseIntent) {
328
+ falseIntentDirective = DirIntent.intentDirectiveFor(falseIntent, falseIntentAttributes);
329
+ }
330
+ if (result === true) {
331
+ if (trueIntentDirective) {
332
+ this.intentDir.execute(trueIntentDirective, () => {
333
+ if (callback) {
334
+ callback();
335
+ }
336
+ })
337
+ }
338
+ else {
339
+ if (this.log) { console.log("No trueIntentDirective specified"); }
340
+ if (callback) {
341
+ callback();
342
+ }
343
+ }
344
+ }
345
+ else {
346
+ if (falseIntentDirective) {
347
+ this.intentDir.execute(falseIntentDirective, () => {
348
+ if (callback) {
349
+ callback();
350
+ }
351
+ });
352
+ }
353
+ else {
354
+ if (this.log) { console.log("No falseIntentDirective specified"); }
355
+ if (callback) {
356
+ callback();
357
+ }
358
+ }
359
+ }
360
+ }
174
361
 
175
362
  async #assignAttributes(action, answer) {
176
363
  if (this.log) {
@@ -62,7 +62,7 @@ class DirJSONCondition {
62
62
  const falseIntent = action.falseIntent;
63
63
  const trueIntentAttributes = action.trueIntentAttributes;
64
64
  const falseIntentAttributes = action.falseIntentAttributes;
65
- let stopOnConditionMet = action.stopOnConditionMet;
65
+ let stopOnConditionMet = true; //action.stopOnConditionMet;
66
66
  if (this.log) {console.log("groups:", JSON.stringify(groups));}
67
67
  if (trueIntent && trueIntent.trim() === "") {
68
68
  trueIntent = null;
@@ -55,60 +55,99 @@ class DirQapla {
55
55
 
56
56
  const filler = new Filler();
57
57
  const tracking_number = filler.fill(action.trackingNumber, requestVariables);
58
- // let tracking_number = await this.context.chatbot.getParameter(action.trackingNumber);
59
- if (this.log) {console.log("DirQapla tracking number: ", tracking_number); }
58
+ if (this.log) { console.log("DirQapla tracking number: ", tracking_number); }
60
59
 
61
60
  if (!tracking_number || tracking_number === '') {
62
61
  console.error("DirQapla ERROR - tracking number is undefined or null or empty string");
63
62
  callback();
64
63
  }
65
64
 
65
+ const server_base_url = process.env.API_ENDPOINT || process.env.API_URL;
66
66
  const qapla_base_url = process.env.QAPLA_ENDPOINT || "https://api.qapla.it/1.2"
67
- if (this.log) { console.log("DirQapla QaplaEndpoint URL: ", qapla_base_url); }
68
- const QAPLA_HTTPREQUEST = {
69
- url: qapla_base_url + "/getShipment/",
67
+
68
+ const INTEGRATIONS_HTTPREQUEST = {
69
+ url: server_base_url + "/" + this.context.projectId + "/integration/name/qapla",
70
70
  headers: {
71
- 'Content-Type': 'application/json'
72
- },
73
- params: {
74
- apiKey: action.apiKey,
75
- trackingNumber: tracking_number
71
+ 'Content-Type': 'application/json',
72
+ 'Authorization': 'JWT ' + this.context.token
76
73
  },
77
74
  method: "GET"
78
75
  }
79
- if (this.log) { console.log("DirQapla QAPLA_HTTPREQUEST", QAPLA_HTTPREQUEST); }
76
+ if (this.log) { console.log("DirQapla INTEGRATIONS_HTTPREQUEST ", INTEGRATIONS_HTTPREQUEST) }
80
77
 
81
78
  this.#myrequest(
82
- QAPLA_HTTPREQUEST, async (err, resbody) => {
79
+ INTEGRATIONS_HTTPREQUEST, async (err, integration) => {
83
80
  if (err) {
84
81
  if (callback) {
85
- console.error("(httprequest) DirQapla getShipment err:", err);
82
+ console.error("(httprequest) DirQapla get integrations err:", err);
86
83
  callback();
87
84
  }
88
85
  } else if (callback) {
89
- if (this.log) { console.log("DirQapla getShipment resbody: ", resbody); }
90
-
91
- let status = null;;
92
- let result;
93
- let error;
94
-
95
- if (resbody.getShipment &&
96
- resbody.getShipment.shipments &&
97
- resbody.getShipment.shipments[0] &&
98
- resbody.getShipment.shipments[0].status &&
99
- resbody.getShipment.shipments[0].status.qaplaStatus &&
100
- resbody.getShipment.shipments[0].status.qaplaStatus.status) {
101
- status = resbody.getShipment.shipments[0].status.qaplaStatus.status;
86
+ if (this.log) { console.log("DirQapla get integration resbody: ", integration); }
87
+
88
+ let key;
89
+ if (integration &&
90
+ integration.value) {
91
+ key = integration.value.apikey;
102
92
  }
103
-
104
- result = resbody.getShipment.result;
105
- error = resbody.getShipment.error;
106
- await this.#assignAttributes(action, status, result, error);
107
- callback();
108
- }
109
- }
110
- )
111
93
 
94
+ if (!key) {
95
+ if (action.apiKey) {
96
+ console.log("DirQapla key retrieved from the action (deprecated)");
97
+ key = action.apiKey;
98
+ } else {
99
+ console.log("DirQapla invalid or empty key");
100
+ callback();
101
+ return;
102
+ }
103
+ }
104
+
105
+ if (this.log) { console.log("DirQapla QaplaEndpoint URL: ", qapla_base_url); }
106
+ const QAPLA_HTTPREQUEST = {
107
+ url: qapla_base_url + "/getShipment/",
108
+ headers: {
109
+ 'Content-Type': 'application/json'
110
+ },
111
+ params: {
112
+ apiKey: key,
113
+ trackingNumber: tracking_number
114
+ },
115
+ method: "GET"
116
+ }
117
+ if (this.log) { console.log("DirQapla QAPLA_HTTPREQUEST", QAPLA_HTTPREQUEST); }
118
+
119
+ this.#myrequest(
120
+ QAPLA_HTTPREQUEST, async (err, resbody) => {
121
+ if (err) {
122
+ if (callback) {
123
+ console.error("(httprequest) DirQapla getShipment err:", err);
124
+ callback();
125
+ }
126
+ } else if (callback) {
127
+ if (this.log) { console.log("DirQapla getShipment resbody: ", resbody); }
128
+
129
+ let status = null;;
130
+ let result;
131
+ let error;
132
+
133
+ if (resbody.getShipment &&
134
+ resbody.getShipment.shipments &&
135
+ resbody.getShipment.shipments[0] &&
136
+ resbody.getShipment.shipments[0].status &&
137
+ resbody.getShipment.shipments[0].status.qaplaStatus &&
138
+ resbody.getShipment.shipments[0].status.qaplaStatus.status) {
139
+ status = resbody.getShipment.shipments[0].status.qaplaStatus.status;
140
+ }
141
+
142
+ result = resbody.getShipment.result;
143
+ error = resbody.getShipment.error;
144
+ await this.#assignAttributes(action, status, result, error);
145
+ callback();
146
+ }
147
+ }
148
+ )
149
+ }
150
+ })
112
151
  }
113
152
 
114
153
 
@@ -102,20 +102,35 @@ class DirWebRequestV2 {
102
102
  if (err) {
103
103
  if (this.log) {console.error("webRequest error:", err);}
104
104
  if (callback) {
105
- this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes, () => {
105
+ if (falseIntent) {
106
+ this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes, () => {
107
+ callback(true); // stop the flow
108
+ });
109
+ }
110
+ else {
106
111
  callback(false); // continue the flow
107
- });
112
+ }
108
113
  }
109
114
  }
110
115
  else if(res.status >= 200 && res.status <= 299) {
111
- await this.#executeCondition(true, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes, () => {
112
- callback(stopOnConditionMet); // stop the flow
113
- });
116
+ if (trueIntent) {
117
+ await this.#executeCondition(true, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes, () => {
118
+ callback(true); // stop the flow
119
+ });
120
+ }
121
+ else {
122
+ callback(false); // continue the flow
123
+ }
114
124
  }
115
125
  else {
116
- await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes, () => {
126
+ if (falseIntent) {
127
+ this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes, () => {
128
+ callback(true); // stop the flow
129
+ });
130
+ }
131
+ else {
117
132
  callback(false); // continue the flow
118
- });
133
+ }
119
134
  }
120
135
  }
121
136
  );