@tiledesk/tiledesk-server 2.7.0 → 2.7.2

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/deploy.sh CHANGED
@@ -1,5 +1,5 @@
1
1
  git pull
2
- npm version minor
2
+ npm version patch
3
3
  version=`node -e 'console.log(require("./package.json").version)'`
4
4
  echo "version $version"
5
5
 
@@ -4,20 +4,30 @@ var path = require('path');
4
4
  var winston = require('../config/winston');
5
5
 
6
6
 
7
- var labelsDir = __dirname+"/../config/labels/";
7
+ var labelsDir = __dirname + "/../config/labels/";
8
8
  winston.debug('labelsDir: ' + labelsDir);
9
9
 
10
10
 
11
- module.exports = function(req, res, next) {
12
- var filePath = path.join(labelsDir, 'widget.json');
13
-
14
- fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){
15
- if (err) {
16
- winston.error('Error getting labels', err);
17
- return res.status(500).send({ success: false, msg: 'Error reading object.' });
18
- }
19
- winston.debug('label fetched', data);
20
- req.labels = JSON.parse(data);
21
- next();
22
- });
11
+ module.exports = function (req, res, next) {
12
+ var filePath = path.join(labelsDir, 'widget.json');
13
+
14
+ fs.readFile(filePath, { encoding: 'utf-8' }, function (err, data) {
15
+ if (err) {
16
+ winston.error('Error getting labels', err);
17
+ return res.status(500).send({ success: false, msg: 'Error reading object.' });
18
+ }
19
+ winston.debug('label fetched', data);
20
+
21
+ // Replace {{ BRAND_NAME }} with process.env.BRAND_NAME value (default value "Tiledesk")
22
+ let brand_name = process.env.BRAND_NAME;
23
+
24
+ if (brand_name) {
25
+ data = data.replaceAll("Tiledesk", brand_name);
26
+ data = data.replaceAll("tiledesk", brand_name.toLowerCase());
27
+
28
+ }
29
+
30
+ req.labels = JSON.parse(data);
31
+ next();
32
+ });
23
33
  }
package/models/profile.js CHANGED
@@ -20,6 +20,9 @@ var ProfileSchema = new Schema({
20
20
  type: String,
21
21
  default: 'free',
22
22
  },
23
+ quotes: {
24
+ type: Object
25
+ },
23
26
  subStart: {
24
27
  type: Date,
25
28
  },
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tiledesk/tiledesk-server",
3
3
  "description": "The Tiledesk server module",
4
- "version": "2.7.0",
4
+ "version": "2.7.2",
5
5
  "scripts": {
6
6
  "start": "node ./bin/www",
7
7
  "pretest": "mongodb-runner start",
package/routes/faq_kb.js CHANGED
@@ -19,10 +19,23 @@ const trainingService = require('../services/trainingService');
19
19
 
20
20
  let chatbot_templates_api_url = process.env.CHATBOT_TEMPLATES_API_URL
21
21
 
22
- router.post('/', function (req, res) {
22
+ router.post('/', async function (req, res) {
23
23
  winston.debug('create BOT ', req.body);
24
24
  //create(name, url, projectid, user_id, type, description, webhook_url, webhook_enabled, language, template)
25
25
  //faqService.create(req.body.name, req.body.url, req.projectid, req.user.id, req.body.type, req.body.description, undefined, undefined, req.body.language, req.body.template, req.body.mainCategory, req.body.intentsEngine).then(function (savedFaq_kb) {
26
+ let quoteManager = req.app.get('quote_manager');
27
+ let limits = await quoteManager.getPlanLimits(req.project);
28
+ let chatbots_limit = limits.chatbots;
29
+ winston.debug("chatbots_limit for project " + req.projectid + ": " + chatbots_limit);
30
+
31
+ let chatbots_count = await Faq_kb.countDocuments({ id_project: req.projectid, type: { $ne: "identity" } }).exec();
32
+ winston.debug("chatbots_count for project " + req.projectid + ": " + chatbots_count);
33
+
34
+ if (chatbots_count >= chatbots_limit) {
35
+ //return res.status(403).send({ success: false, error: "Maximum number of chatbots reached for the current plan", plan_limit: chatbots_limit })
36
+ winston.info("Chatbots limit reached for project " + req.projectid + ". Block currently disabled.");
37
+ }
38
+
26
39
  faqService.create(req.body.name, req.body.url, req.projectid, req.user.id, req.body.type, req.body.description, req.body.webhook_url, req.body.webhook_enabled, req.body.language, req.body.template, req.body.mainCategory, req.body.intentsEngine, req.body.attributes).then(function (savedFaq_kb) {
27
40
  res.json(savedFaq_kb);
28
41
  });
package/routes/openai.js CHANGED
@@ -4,6 +4,7 @@ var { KBSettings } = require('../models/kb_setting');
4
4
  var openaiService = require('../services/openaiService');
5
5
  var winston = require('../config/winston');
6
6
  const { QuoteManager } = require('../services/QuoteManager');
7
+ const { MODEL_MULTIPLIER } = require('../utils/aiUtils');
7
8
 
8
9
  router.post('/', async (req, res) => {
9
10
 
@@ -60,8 +61,14 @@ router.post('/', async (req, res) => {
60
61
  json.messages.unshift(message);
61
62
  }
62
63
 
64
+ let multiplier = MODEL_MULTIPLIER[json.model];
65
+ if (!multiplier) {
66
+ multiplier = 1;
67
+ winston.info("No multiplier found for AI model")
68
+ }
69
+
63
70
  openaiService.completions(json, gptkey).then(async (response) => {
64
- let data = { createdAt: new Date(), tokens: response.data.usage.total_tokens }
71
+ let data = { createdAt: new Date(), tokens: response.data.usage.total_tokens, multiplier: multiplier }
65
72
  if (usePublicKey === true) {
66
73
  let incremented_key = await quoteManager.incrementTokenCount(req.project, data);
67
74
  winston.verbose("Tokens quota incremented for key " + incremented_key);
@@ -5,14 +5,14 @@ const messageEvent = require('../event/messageEvent');
5
5
  const emailEvent = require('../event/emailEvent');
6
6
 
7
7
  const PLANS_LIST = {
8
- FREE_TRIAL: { requests: 3000, messages: 0, tokens: 250000, email: 200, kbs: 50 }, // same as PREMIUM
9
- SANDBOX: { requests: 200, messages: 0, tokens: 10000, email: 200, kbs: 50 },
10
- BASIC: { requests: 800, messages: 0, tokens: 50000, email: 200, kbs: 150},
11
- PREMIUM: { requests: 3000, messages: 0, tokens: 250000, email: 200, kbs: 300},
12
- CUSTOM: { requests: 3000, messages: 0, tokens: 250000, email: 200, kbs: 300}
8
+ FREE_TRIAL: { requests: 3000, messages: 0, tokens: 250000, email: 200, chatbots: 20, kbs: 50 }, // same as PREMIUM
9
+ SANDBOX: { requests: 200, messages: 0, tokens: 10000, email: 200, chatbots: 2, kbs: 50 },
10
+ BASIC: { requests: 800, messages: 0, tokens: 50000, email: 200, chatbots: 5, kbs: 150},
11
+ PREMIUM: { requests: 3000, messages: 0, tokens: 250000, email: 200, chatbots: 20, kbs: 300},
12
+ CUSTOM: { requests: 3000, messages: 0, tokens: 250000, email: 200, chatbots: 20, kbs: 1000}
13
13
  }
14
14
 
15
- const typesList = ['requests', 'messages', 'email', 'tokens']
15
+ const typesList = ['requests', 'messages', 'email', 'tokens', 'chatbots', 'kbs']
16
16
 
17
17
  let quotes_enabled = true;
18
18
 
@@ -74,8 +74,11 @@ class QuoteManager {
74
74
  winston.debug("QUOTES DISABLED - incrementTokenCount")
75
75
  return key;
76
76
  }
77
-
78
- await this.tdCache.incrby(key, data.tokens);
77
+
78
+ let tokens = data.tokens * data.multiplier;
79
+ await this.tdCache.incrbyfloat(key, tokens);
80
+ // await this.tdCache.incrby(key, tokens);
81
+
79
82
  return key;
80
83
  }
81
84
  // INCREMENT KEY SECTION - END
@@ -156,6 +159,7 @@ class QuoteManager {
156
159
  this.project = project;
157
160
  let limits = await this.getPlanLimits();
158
161
  winston.verbose("limits for current plan: ", limits)
162
+
159
163
  let quote = await this.getCurrentQuote(project, object, type);
160
164
  winston.verbose("getCurrentQuote resp: ", quote)
161
165
 
@@ -194,16 +198,13 @@ class QuoteManager {
194
198
  case 'Custom':
195
199
  limits = PLANS_LIST.CUSTOM;
196
200
  break;
197
- case 'Sandbox':
198
- limits = PLANS_LIST.SANDBOX;
199
- break;
200
- case 'Growth':
201
+ case 'Growth': // OLD PLAN
201
202
  limits = PLANS_LIST.BASIC
202
203
  break;
203
- case 'Scale':
204
+ case 'Scale': // OLD PLAN
204
205
  limits = PLANS_LIST.PREMIUM
205
206
  break;
206
- case 'Plus':
207
+ case 'Plus': // OLD PLAN
207
208
  limits = PLANS_LIST.CUSTOM
208
209
  break;
209
210
  default:
@@ -212,7 +213,14 @@ class QuoteManager {
212
213
  } else {
213
214
  limits = PLANS_LIST.FREE_TRIAL;
214
215
  }
215
- return limits;
216
+
217
+ if (this.project?.profile?.quotes) {
218
+ let profile_quotes = this.project?.profile?.quotes;
219
+ const merged_quotes = Object.assign({}, limits, profile_quotes);
220
+ return merged_quotes;
221
+ } else {
222
+ return limits;
223
+ }
216
224
  }
217
225
 
218
226
 
@@ -226,7 +234,7 @@ class QuoteManager {
226
234
  }
227
235
  }
228
236
 
229
- winston.info("QUOTES ENABLED ? ", quotes_enabled);
237
+ winston.info("QUOTES ENABLED: " + quotes_enabled);
230
238
 
231
239
  // TODO - Try to generalize to avoid repetition
232
240
  let incrementEventHandler = (object) => { }
@@ -73,6 +73,74 @@ describe('FaqKBRoute', () => {
73
73
 
74
74
  }).timeout(20000);
75
75
 
76
+ /**
77
+ * This test will be no longer available after merge with master because
78
+ * the profile section can no longer be modified via api.
79
+ */
80
+ // it('createMaximumNumberExceeded', (done) => {
81
+
82
+ // var email = "test-signup-" + Date.now() + "@email.com";
83
+ // var pwd = "pwd";
84
+
85
+ // userService.signup(email, pwd, "Test Firstname", "Test lastname").then(function (savedUser) {
86
+ // projectService.create("test-faqkb-create", savedUser._id).then(function (savedProject) {
87
+
88
+ // chai.request(server)
89
+ // .put('/projects/' + savedProject._id)
90
+ // .auth(email, pwd)
91
+ // .send({ profile: { quotes: { chatbots: 2 } } })
92
+ // .end((err, res) => {
93
+
94
+ // if (log) { console.log("res.body", res.body); }
95
+
96
+ // chai.request(server)
97
+ // .post('/' + savedProject._id + '/faq_kb')
98
+ // .auth(email, pwd)
99
+ // .send({ "name": "testbot1", type: "external", language: 'en' })
100
+ // .end((err, res) => {
101
+ // if (log) { console.log("res.body", res.body); }
102
+ // res.should.have.status(200);
103
+ // res.body.should.be.a('object');
104
+ // expect(res.body.name).to.equal("testbot1");
105
+ // expect(res.body.language).to.equal("en");
106
+
107
+ // chai.request(server)
108
+ // .post('/' + savedProject._id + '/faq_kb')
109
+ // .auth(email, pwd)
110
+ // .send({ "name": "testbot2", type: "external", language: 'en' })
111
+ // .end((err, res) => {
112
+ // if (log) { console.log("res.body", res.body); }
113
+ // res.should.have.status(200);
114
+ // res.body.should.be.a('object');
115
+ // expect(res.body.name).to.equal("testbot2");
116
+ // expect(res.body.language).to.equal("en");
117
+
118
+ // chai.request(server)
119
+ // .post('/' + savedProject._id + '/faq_kb')
120
+ // .auth(email, pwd)
121
+ // .send({ "name": "testbot3", type: "external", language: 'en' })
122
+ // .end((err, res) => {
123
+
124
+ // if (log) { console.log("res.body", res.body); }
125
+
126
+ // res.should.have.status(403);
127
+ // res.body.should.be.a('object');
128
+ // expect(res.body.success).to.equal(false);
129
+ // expect(res.body.error).to.equal("Maximum number of chatbots reached for the current plan");
130
+ // expect(res.body.plan_limit).to.equal(2);
131
+
132
+ // done()
133
+
134
+ // });
135
+ // });
136
+ // });
137
+ // })
138
+ // });
139
+ // });
140
+
141
+ // }).timeout(20000);
142
+
143
+
76
144
  // it('train with tiledesk-ai', (done) => {
77
145
  // var email = "test-signup-" + Date.now() + "@email.com";
78
146
  // var pwd = "pwd";
@@ -69,9 +69,8 @@ describe('messageService', function () {
69
69
  let obj = { createdAt: new Date() }
70
70
 
71
71
  let quotes = await qm.getAllQuotes(savedProject, obj);
72
- console.log("quotes: ", quotes);
73
- quotes.messages.quote.should.be.a('string');
74
- expect(quotes.messages.quote).to.equal('1');
72
+ quotes.messages.quote.should.be.a('number');
73
+ expect(quotes.messages.quote).to.equal(1);
75
74
 
76
75
  done();
77
76
 
@@ -84,7 +83,7 @@ describe('messageService', function () {
84
83
  });
85
84
 
86
85
  });
87
- });
86
+ }).timeout(10000);
88
87
 
89
88
  it('createMessage', function (done) {
90
89
  // this.timeout(10000);
@@ -1,5 +1,6 @@
1
1
  //During the test the env variable is set to test
2
2
  process.env.NODE_ENV = 'test';
3
+ // process.env.GPTKEY = 'customgptkey';
3
4
 
4
5
  let log = false;
5
6
  var projectService = require('../services/projectService');
@@ -67,7 +68,43 @@ describe('OpenaiRoute', () => {
67
68
  // })
68
69
  // }).timeout(20000)
69
70
 
70
- it('completions missing gptkey', (done) => {
71
+ // it('completions missing gptkey', (done) => {
72
+
73
+ // var email = "test-signup-" + Date.now() + "@email.com";
74
+ // var pwd = "pwd";
75
+
76
+ // userService.signup(email, pwd, "Test Firstname", "Test Lastname").then((savedUser) => {
77
+ // projectService.create("test-openai-create", savedUser._id).then((savedProject) => {
78
+
79
+ // chai.request(server)
80
+ // .post('/' + savedProject._id + '/kbsettings')
81
+ // .auth(email, pwd)
82
+ // .send({}) // can be empty
83
+ // .end((err, res) => {
84
+ // if (log) { console.log("create kbsettings res.body: ", res.body); }
85
+ // res.should.have.status(200);
86
+ // res.body.should.be.a('object');
87
+
88
+ // chai.request(server)
89
+ // .post('/' + savedProject._id + '/openai')
90
+ // .auth(email, pwd)
91
+ // .send({ question: "Provide 3 names for a dog", context: "you are an awesome assistant", max_tokens: 100, temperature: 0, model: "gpt-3.5-turbo" })
92
+ // .end((err, res) => {
93
+ // if (log) { console.log("res.body: ", res.body); }
94
+ // console.log("res.body: ", res.body)
95
+ // // res.should.have.status(400);
96
+ // // res.body.should.be.a('object');
97
+ // // expect(res.body.success).to.equal(false);
98
+ // // expect(res.body.message).to.equal("Missing gptkey parameter");
99
+
100
+ // done();
101
+ // })
102
+ // })
103
+ // })
104
+ // })
105
+ // }).timeout(20000)
106
+
107
+ it('newCompletionsMissingGptkey', (done) => {
71
108
 
72
109
  var email = "test-signup-" + Date.now() + "@email.com";
73
110
  var pwd = "pwd";
@@ -76,32 +113,61 @@ describe('OpenaiRoute', () => {
76
113
  projectService.create("test-openai-create", savedUser._id).then((savedProject) => {
77
114
 
78
115
  chai.request(server)
79
- .post('/' + savedProject._id + '/kbsettings')
116
+ .post('/' + savedProject._id + '/openai')
80
117
  .auth(email, pwd)
81
- .send({}) // can be empty
118
+ .send({ question: "Provide 3 names for a dog", context: "you are an awesome assistant", max_tokens: 100, temperature: 0, model: "gpt-3.5-turbo" })
82
119
  .end((err, res) => {
83
- if (log) { console.log("create kbsettings res.body: ", res.body); }
84
- res.should.have.status(200);
120
+ if (log) { console.log("res.body: ", res.body); }
121
+ res.should.have.status(400);
85
122
  res.body.should.be.a('object');
123
+ expect(res.body.success).to.equal(false);
124
+ expect(res.body.message).to.equal("Missing gptkey parameter");
86
125
 
87
- chai.request(server)
88
- .post('/' + savedProject._id + '/openai')
89
- .auth(email, pwd)
90
- .send({ question: "Provide 3 names for a dog", context: "you are an awesome assistant", max_tokens: 100, temperature: 0, model: "gpt-3.5-turbo" })
91
- .end((err, res) => {
92
- if (log) {console.log("res.body: ", res.body);}
93
- res.should.have.status(400);
94
- res.body.should.be.a('object');
95
- expect(res.body.success).to.equal(false);
96
- expect(res.body.message).to.equal("Missing gptkey parameter");
97
-
98
- done();
99
- })
126
+ done();
100
127
  })
128
+
129
+
101
130
  })
102
131
  })
103
- }).timeout(20000)
132
+ }).timeout(10000)
133
+
134
+
135
+ /**
136
+ * This test will be no longer available after merge with master because
137
+ * the profile section can no longer be modified via api.
138
+ */
139
+ // it('completionsWithProfileModified', (done) => {
140
+
141
+ // var email = "test-signup-" + Date.now() + "@email.com";
142
+ // var pwd = "pwd";
143
+
144
+ // userService.signup(email, pwd, "Test Firstname", "Test Lastname").then((savedUser) => {
145
+ // projectService.create("test-openai-create", savedUser._id).then((savedProject) => {
146
+
147
+ // chai.request(server)
148
+ // .put('/projects/' + savedProject._id)
149
+ // .auth(email, pwd)
150
+ // .send({ profile: { quotes: { tokens: 400000, kbs: 100 } } })
151
+ // .end((err, res) => {
152
+ // if (log) { console.log("res.body: ", res.body); };
153
+ // console.log("res.body: ", res.body)
154
+
155
+ // chai.request(server)
156
+ // .post('/' + savedProject._id + '/openai')
157
+ // .auth(email, pwd)
158
+ // .send({ question: "Provide 3 names for a dog", context: "you are an awesome assistant", max_tokens: 100, temperature: 0, model: "gpt-3.5-turbo" })
159
+ // .end((err, res) => {
160
+
161
+ // if (log) { console.log("res.body: ", res.body); }
162
+ // done();
104
163
 
164
+ // })
165
+
166
+
167
+ // })
168
+ // })
169
+ // })
170
+ // }).timeout(10000)
105
171
 
106
172
  });
107
173
 
@@ -1,3 +1,6 @@
1
+ process.env.NODE_ENV = 'test';
2
+ process.env.QUOTES_ENABLED = 'true';
3
+
1
4
  const { QuoteManager } = require('../services/QuoteManager');
2
5
  const pubModulesManager = require('../pubmodules/pubModulesManager'); // on constructor init is undefined beacusae pub module is loaded after
3
6
  var projectService = require('../services/projectService');
@@ -198,7 +201,7 @@ describe('QuoteManager', function () {
198
201
  chai.request(server)
199
202
  .post('/' + savedProject._id + "/openai/quotes")
200
203
  .auth(email, pwd)
201
- .send({ createdAt: createdAt , tokens: 128 })
204
+ .send({ createdAt: createdAt , tokens: 128, multiplier: 25 })
202
205
  .end((err, res) => {
203
206
  if (log) { console.log("res.body", res.body )};
204
207
  res.should.have.status(200);
@@ -210,7 +213,8 @@ describe('QuoteManager', function () {
210
213
  let message_resp = "value incremented for key " + key;
211
214
  expect(res.body.message).to.equal(message_resp);
212
215
  expect(res.body.key).to.equal(key);
213
- expect(res.body.currentQuote).to.equal(128);
216
+ let expected_quote = 128 * 25;
217
+ expect(res.body.currentQuote).to.equal(expected_quote);
214
218
 
215
219
 
216
220
  done();
package/utils/TdCache.js CHANGED
@@ -103,6 +103,20 @@ class TdCache {
103
103
  })
104
104
  }
105
105
 
106
+ async incrbyfloat(key, increment) {
107
+ return new Promise( async (resolve, reject) => {
108
+ try {
109
+ await this.client.incrbyfloat(key, increment);
110
+ }
111
+
112
+ catch(error) {
113
+ console.error("Error on incrby: ", error);
114
+ reject(error);
115
+ }
116
+ return resolve();
117
+ })
118
+ }
119
+
106
120
  async hset(dict_key, key, value, options) {
107
121
  //console.log("hsetting dict_key key value", dict_key, key, value)
108
122
  return new Promise( async (resolve, reject) => {
@@ -0,0 +1,7 @@
1
+ MODEL_MULTIPLIER = {
2
+ "gpt-3.5-turbo": 0.6,
3
+ "gpt-4": 25,
4
+ "gpt-4-turbo-preview": 12
5
+ }
6
+
7
+ module.exports = { MODEL_MULTIPLIER }