@tiledesk/tiledesk-tybot-connector 2.0.10-rc6 → 2.0.10-rc8

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.10-rc6",
3
+ "version": "2.0.10-rc8",
4
4
  "description": "Tiledesk Tybot connector",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -57,6 +57,7 @@ const { DirReplaceBotV3 } = require('./directives/DirReplaceBotV3');
57
57
  const { DirAiTask, DirAiPrompt } = require('./directives/DirAiPrompt');
58
58
  const { DirWebResponse } = require('./directives/DirWebResponse');
59
59
  const { DirConnectBlock } = require('./directives/DirConnectBlock');
60
+ const { DirAddKbContent } = require('./directives/DirAddKbContent');
60
61
 
61
62
  const winston = require('../utils/winston');
62
63
  const { DirFlowLog } = require('./directives/DirFlowLog');
@@ -721,6 +722,12 @@ class DirectivesChatbotPlug {
721
722
  this.process(next_dir);
722
723
  })
723
724
  }
725
+ else if (directive_name === Directives.ADD_KB_CONTENT) {
726
+ new DirAddKbContent(context).execute(directive, async () => {
727
+ let next_dir = await this.nextDirective(this.directives);
728
+ this.process(next_dir);
729
+ });
730
+ }
724
731
  else {
725
732
  let next_dir = await this.nextDirective(this.directives);
726
733
  this.process(next_dir);
@@ -0,0 +1,331 @@
1
+ const axios = require("axios").default;
2
+ const { TiledeskChatbot } = require('../../engine/TiledeskChatbot');
3
+ const { Filler } = require('../Filler');
4
+ let https = require("https");
5
+ const { DirIntent } = require("./DirIntent");
6
+ const { TiledeskChatbotConst } = require("../../engine/TiledeskChatbotConst");
7
+ const { TiledeskChatbotUtil } = require("../../utils/TiledeskChatbotUtil");
8
+ const assert = require("assert");
9
+ require('dotenv').config();
10
+ const winston = require('../../utils/winston');
11
+ const httpUtils = require("../../utils/HttpUtils");
12
+ const integrationService = require("../../services/IntegrationService");
13
+ const { Logger } = require("../../Logger");
14
+
15
+ class DirAddKbContent {
16
+
17
+ constructor(context) {
18
+ if (!context) {
19
+ throw new Error('context object is mandatory');
20
+ }
21
+ this.context = context;
22
+ this.chatbot = context.chatbot;
23
+ this.tdcache = this.context.tdcache;
24
+ this.requestId = this.context.requestId;
25
+ this.projectId = this.context.projectId;
26
+ this.token = this.context.token;
27
+ this.intentDir = new DirIntent(context);
28
+ this.API_ENDPOINT = this.context.API_ENDPOINT;
29
+ this.log = context.log;
30
+ this.logger = new Logger({ request_id: this.requestId, dev: this.context.supportRequest.draft });
31
+ }
32
+
33
+ execute(directive, callback) {
34
+ this.logger.info("Execute AskKnowledgeBase action")
35
+ winston.debug("DirAskGPTV2 directive: ", directive);
36
+ let action;
37
+ if (directive.action) {
38
+ action = directive.action;
39
+ }
40
+ else {
41
+ this.logger.error("Incorrect action for ", directive.name, directive)
42
+ winston.debug("DirAskGPTV2 Incorrect directive: ", directive);
43
+ callback();
44
+ return;
45
+ }
46
+ this.go(action, (stop) => {
47
+ this.logger.info("Acion AskKnowledgeBase completed");
48
+ callback(stop);
49
+ })
50
+ }
51
+
52
+ async go(action, callback) {
53
+ winston.debug("[DirAddKbContent] action:", action);
54
+ if (!this.tdcache) {
55
+ winston.error("[DirAddKbContent] Error: tdcache is mandatory");
56
+ callback();
57
+ return;
58
+ }
59
+
60
+ let publicKey = false;
61
+ let type = action.type;
62
+ let name = action.name;
63
+ let content = action.content;
64
+ let engine;
65
+
66
+ // default values
67
+ let namespace = this.context.projectId;
68
+
69
+ if (action.namespace) {
70
+ namespace = action.namespace;
71
+ }
72
+
73
+ let requestVariables = null;
74
+ requestVariables =
75
+ await TiledeskChatbot.allParametersStatic(
76
+ this.tdcache, this.requestId
77
+ );
78
+
79
+ const filler = new Filler();
80
+ const filled_content = filler.fill(content, requestVariables);
81
+
82
+ const kb_endpoint = process.env.API_ENDPOINT;
83
+ winston.verbose("[DirAddKbContent] KbEndpoint URL: " + kb_endpoint);
84
+
85
+ let key = await integrationService.getKeyFromIntegrations(this.projectId, 'openai', this.token);
86
+ if (!key) {
87
+ this.logger.debug("[DirAddKbContent] OpenAI key not found in Integration. Using shared OpenAI key");
88
+ winston.verbose("[DirAddKbContent] - Key not found in Integrations. Searching in kb settings...");
89
+ key = await this.getKeyFromKbSettings();
90
+ }
91
+
92
+ if (!key) {
93
+ winston.verbose("[DirAddKbContent] - Retrieve public gptkey")
94
+ key = process.env.GPTKEY;
95
+ publicKey = true;
96
+ } else {
97
+ this.logger.debug("[DirAddKbContent] use your own OpenAI key")
98
+ }
99
+
100
+ if (!key) {
101
+ winston.info("[DirAddKbContent] Error: gptkey is mandatory");
102
+ await this.chatbot.addParameter("flowError", "[DirAddKbContent] Error: gptkey is mandatory");
103
+ callback();
104
+ return;
105
+ }
106
+
107
+ if (publicKey === true) {
108
+ let keep_going = await this.checkQuoteAvailability();
109
+ if (keep_going === false) {
110
+ this.logger.warn("[DirAddKbContent] Tokens quota exceeded. Skip the action")
111
+ winston.verbose("[DirAddKbContent] - Quota exceeded for tokens. Skip the action")
112
+ await this.chatbot.addParameter("flowError", "[DirAddKbContent] Error: tokens quota exceeded");
113
+ callback(true);
114
+ return;
115
+ }
116
+ }
117
+
118
+ let ns;
119
+
120
+ if (action.namespaceAsName) {
121
+ // Namespace could be an attribute
122
+ const filled_namespace = filler.fill(action.namespace, requestVariables)
123
+ this.logger.debug("[DirAddKbContent] Searching namespace by name ", filled_namespace);
124
+ ns = await this.getNamespace(filled_namespace, null);
125
+ namespace = ns?.id;
126
+ winston.verbose("[DirAddKbContent] - Retrieved namespace id from name " + namespace);
127
+ } else {
128
+ this.logger.debug("[DirAddKbContent] Searching namespace by id ", namespace);
129
+ ns = await this.getNamespace(null, namespace);
130
+ }
131
+
132
+ if (!ns) {
133
+ this.logger.error("[DirAddKbContent] Namespace not found");
134
+ await this.chatbot.addParameter("flowError", "[DirAddKbContent] Error: namespace not found");
135
+ callback();
136
+ return;
137
+ }
138
+
139
+ if (ns.engine) {
140
+ engine = ns.engine;
141
+ } else {
142
+ engine = await this.setDefaultEngine()
143
+ }
144
+
145
+ if (!namespace) {
146
+ this.logger.error("[DirAddKbContent] Namespace is undefined")
147
+ winston.verbose("[DirAddKbContent] - Error: namespace is undefined")
148
+ await this.chatbot.addParameter("flowError", "[DirAddKbContent] Error: namespace is undefined");
149
+ callback(true);
150
+ return;
151
+ }
152
+
153
+ let json = {
154
+ content: filled_content,
155
+ namespace: namespace,
156
+ type: type,
157
+ name: name,
158
+ source: name
159
+ };
160
+
161
+ winston.debug("[DirAddKbContent] json:", json);
162
+
163
+ const HTTPREQUEST = {
164
+ url: kb_endpoint + "/" + this.projectId + "/kb",
165
+ headers: {
166
+ 'Content-Type': 'application/json',
167
+ 'Authorization': 'JWT ' + this.context.token
168
+ },
169
+ json: json,
170
+ method: "POST"
171
+ }
172
+ winston.debug("[DirAddKbContent] HttpRequest: ", HTTPREQUEST);
173
+
174
+ httpUtils.request(
175
+ HTTPREQUEST, async (err, resbody) => {
176
+
177
+ if (err) {
178
+ this.logger.error("[DirAddKbContent] error: " + JSON.stringify(err?.response));
179
+ winston.error("[DirAddKbContent] error: ", err?.response);
180
+ if (callback) {
181
+ callback();
182
+ return;
183
+ }
184
+ }
185
+ else if (resbody.success === true) {
186
+ winston.debug("[DirAddKbContent] resbody: ", resbody);
187
+ callback();
188
+ return;
189
+ } else {
190
+ callback();
191
+ return;
192
+ }
193
+ }
194
+ )
195
+ }
196
+
197
+ async getKeyFromKbSettings() {
198
+ return new Promise((resolve) => {
199
+
200
+ const KB_HTTPREQUEST = {
201
+ url: this.API_ENDPOINT + "/" + this.context.projectId + "/kbsettings",
202
+ headers: {
203
+ 'Content-Type': 'application/json',
204
+ 'Authorization': 'JWT ' + this.context.token
205
+ },
206
+ method: "GET"
207
+ }
208
+ winston.debug("DirAskGPTV2 KB HttpRequest", KB_HTTPREQUEST);
209
+
210
+ httpUtils.request(
211
+ KB_HTTPREQUEST, async (err, resbody) => {
212
+ if (err) {
213
+ winston.error("DirAskGPTV2 Get kb settings error ", err?.response?.data);
214
+ resolve(null);
215
+ } else {
216
+ if (!resbody.gptkey) {
217
+ resolve(null);
218
+ } else {
219
+ resolve(resbody.gptkey);
220
+ }
221
+ }
222
+ }
223
+ )
224
+ })
225
+ }
226
+
227
+ async checkQuoteAvailability() {
228
+ return new Promise((resolve) => {
229
+
230
+ const HTTPREQUEST = {
231
+ url: this.API_ENDPOINT + "/" + this.context.projectId + "/quotes/tokens",
232
+ headers: {
233
+ 'Content-Type': 'application/json',
234
+ 'Authorization': 'JWT ' + this.context.token
235
+ },
236
+ method: "GET"
237
+ }
238
+ winston.debug("DirAskGPTV2 check quote availability HttpRequest", HTTPREQUEST);
239
+
240
+ httpUtils.request(
241
+ HTTPREQUEST, async (err, resbody) => {
242
+ if (err) {
243
+ winston.error("DirAskGPTV2 Check quote availability err: ", err);
244
+ resolve(true)
245
+ } else {
246
+ if (resbody.isAvailable === true) {
247
+ resolve(true)
248
+ } else {
249
+ resolve(false)
250
+ }
251
+ }
252
+ }
253
+ )
254
+ })
255
+ }
256
+
257
+ async updateQuote(tokens_usage) {
258
+ return new Promise((resolve, reject) => {
259
+
260
+ const HTTPREQUEST = {
261
+ url: this.API_ENDPOINT + "/" + this.context.projectId + "/quotes/incr/tokens",
262
+ headers: {
263
+ 'Content-Type': 'application/json',
264
+ 'Authorization': 'JWT ' + this.context.token
265
+ },
266
+ json: tokens_usage,
267
+ method: "POST"
268
+ }
269
+ winston.debug("DirAskGPTV2 update quote HttpRequest ", HTTPREQUEST);
270
+
271
+ httpUtils.request(
272
+ HTTPREQUEST, async (err, resbody) => {
273
+ if (err) {
274
+ winston.error("DirAskGPTV2 Increment tokens quote err: ", err);
275
+ reject(false)
276
+ } else {
277
+ resolve(true);
278
+ }
279
+ }
280
+ )
281
+ })
282
+ }
283
+
284
+ async getNamespace(name, id) {
285
+ return new Promise((resolve) => {
286
+ const HTTPREQUEST = {
287
+ url: this.API_ENDPOINT + "/" + this.context.projectId + "/kb/namespace/all",
288
+ headers: {
289
+ 'Content-Type': 'application/json',
290
+ 'Authorization': 'JWT ' + this.context.token
291
+ },
292
+ method: "GET"
293
+ }
294
+ winston.debug("DirAskGPTV2 get all namespaces HttpRequest", HTTPREQUEST);
295
+ httpUtils.request(
296
+ HTTPREQUEST, async (err, namespaces) => {
297
+ if (err) {
298
+ winston.error("DirAskGPTV2 get all namespaces err: ", err);
299
+ resolve(null)
300
+ } else {
301
+ winston.debug("DirAskGPTV2 get all namespaces resbody: ", namespaces);
302
+ if (name) {
303
+ let namespace = namespaces.find(n => n.name === name);
304
+ resolve(namespace);
305
+ } else {
306
+ let namespace = namespaces.find(n => n.id === id);
307
+ resolve(namespace);
308
+ }
309
+
310
+ }
311
+ }
312
+ )
313
+ })
314
+ }
315
+
316
+ async setDefaultEngine() {
317
+ return new Promise((resolve) => {
318
+ let engine = {
319
+ name: "pinecone",
320
+ type: process.env.PINECONE_TYPE,
321
+ apikey: "",
322
+ vector_size: 1536,
323
+ index_name: process.env.PINECONE_INDEX
324
+ }
325
+ resolve(engine);
326
+ })
327
+ }
328
+
329
+ }
330
+
331
+ module.exports = { DirAddKbContent }
@@ -31,7 +31,7 @@ class DirAskGPTV2 {
31
31
  }
32
32
 
33
33
  execute(directive, callback) {
34
- this.logger.error("Execute AskKnowledgeBase action")
34
+ this.logger.info("Execute AskKnowledgeBase action")
35
35
  winston.debug("DirAskGPTV2 directive: ", directive);
36
36
  let action;
37
37
  if (directive.action) {
@@ -54,10 +54,10 @@ class DirWebRequestV2 {
54
54
  let trueIntentAttributes = action.trueIntentAttributes;
55
55
  let falseIntentAttributes = action.falseIntentAttributes;
56
56
 
57
- winston.debug("DirWebRequestV2 trueIntent " + trueIntent)
58
- winston.debug("DirWebRequestV2 falseIntent " + falseIntent)
59
- winston.debug("DirWebRequestV2 trueIntentAttributes " + trueIntentAttributes)
60
- winston.debug("DirWebRequestV2 falseIntentAttributes " + falseIntentAttributes)
57
+ winston.debug("DirWebRequestV2 trueIntent " + trueIntent)
58
+ winston.debug("DirWebRequestV2 falseIntent " + falseIntent)
59
+ winston.debug("DirWebRequestV2 trueIntentAttributes " + trueIntentAttributes)
60
+ winston.debug("DirWebRequestV2 falseIntentAttributes " + falseIntentAttributes)
61
61
 
62
62
  let requestAttributes = null;
63
63
  requestAttributes =
@@ -139,6 +139,7 @@ class DirWebRequestV2 {
139
139
  }
140
140
  else {
141
141
  this.logger.warn("WebRequest status ", status);
142
+ this.logger.error("WebRequest error ", error);
142
143
  if (falseIntent) {
143
144
  await this.#executeCondition(false, trueIntent, trueIntentAttributes, falseIntent, falseIntentAttributes);
144
145
  callback(true);
@@ -61,6 +61,7 @@ class Directives {
61
61
  static WEBHOOK = 'webhook';
62
62
  static WEB_RESPONSE = "web_response";
63
63
  static FLOW_LOG = "flow_log";
64
+ static ADD_KB_CONTENT = "add_kb_content";
64
65
 
65
66
  // static WHEN_ONLINE_MOVE_TO_AGENT = "whenonlinemovetoagent"; // DEPRECATED?
66
67
  // static WHEN_OFFLINE_HOURS = "whenofflinehours"; // DEPRECATED // adds a message on top of the original message when offline hours opts: --replace