@tiledesk/tiledesk-tybot-connector 0.2.35 → 0.2.37

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.
@@ -0,0 +1,405 @@
1
+ const axios = require("axios").default;
2
+ const { TiledeskChatbot } = require('../../models/TiledeskChatbot');
3
+ const { Filler } = require('../Filler');
4
+ let https = require("https");
5
+ const { DirIntent } = require("./DirIntent");
6
+ require('dotenv').config();
7
+
8
+ class DirAskGPT {
9
+
10
+ constructor(context) {
11
+ if (!context) {
12
+ throw new Error('context object is mandatory');
13
+ }
14
+ this.context = context;
15
+ this.tdcache = this.context.tdcache;
16
+ this.requestId = this.context.requestId;
17
+ this.intentDir = new DirIntent(context);
18
+ this.log = context.log;
19
+ }
20
+
21
+ execute(directive, callback) {
22
+ if (this.log) { console.log("AskGPT directive: ", directive); }
23
+ let action;
24
+ if (directive.action) {
25
+ action = directive.action;
26
+ }
27
+ else {
28
+ console.error("Incorrect directive: ", JSON.stringify(directive));
29
+ callback();
30
+ return;
31
+ }
32
+ this.go(action, (stop) => {
33
+ callback(stop);
34
+ })
35
+ }
36
+
37
+ async go(action, callback) {
38
+ if (this.log) { console.log("DirAskGPT action:", JSON.stringify(action)); }
39
+ if (!this.tdcache) {
40
+ console.error("Error: DirAskGPT tdcache is mandatory");
41
+ callback();
42
+ return;
43
+ }
44
+
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);
68
+ return;
69
+ }
70
+
71
+ if (!action.kbid) {
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);
78
+ return;
79
+ }
80
+
81
+ let requestVariables = null;
82
+ requestVariables =
83
+ await TiledeskChatbot.allParametersStatic(
84
+ this.tdcache, this.requestId
85
+ );
86
+
87
+ const filler = new Filler();
88
+ const filled_question = filler.fill(action.question, requestVariables);
89
+
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;
92
+ if (this.log) {
93
+ console.log("DirAskGPT ApiEndpoint URL: ", server_base_url);
94
+ console.log("DirAskGPT ApiEndpoint URL: ", pai_url);
95
+ }
96
+
97
+ const INTEGRATIONS_HTTPREQUEST = {
98
+ url: server_base_url + "/" + this.context.projectId + "/integration/name/openai",
99
+ headers: {
100
+ 'Content-Type': 'application/json',
101
+ 'Authorization': 'JWT ' + this.context.token
102
+ },
103
+ method: "GET"
104
+ }
105
+ if (this.log) { console.log("DirGptTask INTEGRATIONS_HTTPREQUEST ", INTEGRATIONS_HTTPREQUEST) }
106
+
107
+ this.#myrequest(
108
+ INTEGRATIONS_HTTPREQUEST, async (err, integration) => {
109
+ if (err) {
110
+ if (callback) {
111
+ console.error("DirAskGPT get integrations error: ", err);
112
+ callback();
113
+ return;
114
+ }
115
+ } else if (callback) {
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;
122
+ }
123
+
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
+
226
+ } else {
227
+
228
+ if (this.log) { console.log("DirGptTask - Key found in Integrations") };
229
+
230
+ let json = {
231
+ question: filled_question,
232
+ kbid: action.kbid,
233
+ gptkey: key
234
+ };
235
+ if (this.log) { console.log("DirAskGPT json:", json); }
236
+
237
+ const HTTPREQUEST = {
238
+ url: pai_url,
239
+ json: json,
240
+ method: "POST"
241
+ }
242
+ if (this.log) { console.log("DirAskGPT HTTPREQUEST", HTTPREQUEST); }
243
+
244
+ this.#myrequest(
245
+ HTTPREQUEST, async (err, resbody) => {
246
+ if (this.log && err) {
247
+ console.log("DirAskGPT error: ", err);
248
+ }
249
+ if (this.log) { console.log("DirAskGPT resbody:", resbody); }
250
+ let answer = resbody.answer;
251
+ let source = resbody.source_url;
252
+ await this.#assignAttributes(action, answer, source);
253
+
254
+ if (err) {
255
+ if (callback) {
256
+ if (falseIntent) {
257
+ await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
258
+ }
259
+ callback(true);
260
+ return;
261
+ }
262
+ }
263
+ else if (resbody.success === true) {
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;
275
+ }
276
+ }
277
+ )
278
+
279
+ }
280
+
281
+ }
282
+ }
283
+ )
284
+
285
+
286
+ }
287
+
288
+ async #executeCondition(result, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes, callback) {
289
+ let trueIntentDirective = null;
290
+ if (trueIntent) {
291
+ trueIntentDirective = DirIntent.intentDirectiveFor(trueIntent, trueIntentAttributes);
292
+ }
293
+ let falseIntentDirective = null;
294
+ if (falseIntent) {
295
+ falseIntentDirective = DirIntent.intentDirectiveFor(falseIntent, falseIntentAttributes);
296
+ }
297
+ if (result === true) {
298
+ if (trueIntentDirective) {
299
+ this.intentDir.execute(trueIntentDirective, () => {
300
+ if (callback) {
301
+ callback();
302
+ }
303
+ })
304
+ }
305
+ else {
306
+ if (this.log) { console.log("No trueIntentDirective specified"); }
307
+ if (callback) {
308
+ callback();
309
+ }
310
+ }
311
+ }
312
+ else {
313
+ if (falseIntentDirective) {
314
+ this.intentDir.execute(falseIntentDirective, () => {
315
+ if (callback) {
316
+ callback();
317
+ }
318
+ });
319
+ }
320
+ else {
321
+ if (this.log) { console.log("No falseIntentDirective specified"); }
322
+ if (callback) {
323
+ callback();
324
+ }
325
+ }
326
+ }
327
+ }
328
+
329
+ async #assignAttributes(action, answer, source) {
330
+ if (this.log) {
331
+ console.log("assignAttributes action:", action)
332
+ console.log("assignAttributes answer:", answer)
333
+ console.log("assignAttributes source:", source)
334
+ }
335
+ if (this.context.tdcache) {
336
+ if (action.assignReplyTo && answer) {
337
+ await TiledeskChatbot.addParameterStatic(this.context.tdcache, this.context.requestId, action.assignReplyTo, answer);
338
+ }
339
+ // console.log("--> action.assignSourceTo: ", action.assignSourceTo)
340
+ // console.log("--> source: ", source)
341
+ if (action.assignSourceTo && source) {
342
+ // console.log("--> source: ", source)
343
+ await TiledeskChatbot.addParameterStatic(this.context.tdcache, this.context.requestId, action.assignSourceTo, source);
344
+ }
345
+ // Debug log
346
+ if (this.log) {
347
+ const all_parameters = await TiledeskChatbot.allParametersStatic(this.context.tdcache, this.context.requestId);
348
+ for (const [key, value] of Object.entries(all_parameters)) {
349
+ if (this.log) { console.log("(askgpt) request parameter:", key, "value:", value, "type:", typeof value) }
350
+ }
351
+ }
352
+ }
353
+ }
354
+
355
+ #myrequest(options, callback) {
356
+ if (this.log) {
357
+ console.log("API URL:", options.url);
358
+ console.log("** Options:", JSON.stringify(options));
359
+ }
360
+ let axios_options = {
361
+ url: options.url,
362
+ method: options.method,
363
+ params: options.params,
364
+ headers: options.headers
365
+ }
366
+ if (options.json !== null) {
367
+ axios_options.data = options.json
368
+ }
369
+ if (this.log) {
370
+ console.log("axios_options:", JSON.stringify(axios_options));
371
+ }
372
+ if (options.url.startsWith("https:")) {
373
+ const httpsAgent = new https.Agent({
374
+ rejectUnauthorized: false,
375
+ });
376
+ axios_options.httpsAgent = httpsAgent;
377
+ }
378
+ axios(axios_options)
379
+ .then((res) => {
380
+ if (this.log) {
381
+ console.log("Response for url:", options.url);
382
+ console.log("Response headers:\n", JSON.stringify(res.headers));
383
+ }
384
+ if (res && res.status == 200 && res.data) {
385
+ if (callback) {
386
+ callback(null, res.data);
387
+ }
388
+ }
389
+ else {
390
+ if (callback) {
391
+ callback(new Error("Response status is not 200"), null);
392
+ }
393
+ }
394
+ })
395
+ .catch((error) => {
396
+ // console.error("An error occurred:", JSON.stringify(error.data));
397
+ if (callback) {
398
+ callback(error, null);
399
+ }
400
+ });
401
+ }
402
+
403
+ }
404
+
405
+ module.exports = { DirAskGPT }