@tiledesk/tiledesk-server 2.7.1 → 2.7.2

Sign up to get free protection for your applications and to get access to all the features.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,10 @@
5
5
  🚀 IN PRODUCTION 🚀
6
6
  (https://www.npmjs.com/package/@tiledesk/tiledesk-server/v/2.3.77)
7
7
 
8
+ # 2.7.2
9
+ - Improved QuoteManager with kbs and chatbots (disabled)
10
+ - Improved QuoteManager with AI multipliers
11
+
8
12
  # 2.7.1
9
13
  - Updated widget.json translation file
10
14
  - Improved widget White Label
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.1",
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 }