@tiledesk/tiledesk-server 2.9.24 → 2.9.26

Sign up to get free protection for your applications and to get access to all the features.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,13 @@
5
5
  🚀 IN PRODUCTION 🚀
6
6
  (https://www.npmjs.com/package/@tiledesk/tiledesk-server/v/2.3.77)
7
7
 
8
+ # 2.9.26
9
+ - Updated tybot-connector to 0.2.105
10
+ - Added route for faqs csv file uploading on /kb
11
+
12
+ # 2.9.25
13
+ - Updated vxml-connector to 0.1.44
14
+
8
15
  # 2.9.24
9
16
  - Updated tybot-connector to 0.2.104
10
17
 
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.9.24",
4
+ "version": "2.9.26",
5
5
  "scripts": {
6
6
  "start": "node ./bin/www",
7
7
  "pretest": "mongodb-runner start",
@@ -48,11 +48,11 @@
48
48
  "@tiledesk/tiledesk-rasa-connector": "^1.0.10",
49
49
  "@tiledesk/tiledesk-telegram-connector": "^0.1.14",
50
50
  "@tiledesk/tiledesk-train-jobworker": "^0.0.11",
51
- "@tiledesk/tiledesk-tybot-connector": "^0.2.104",
51
+ "@tiledesk/tiledesk-tybot-connector": "^0.2.105",
52
52
  "@tiledesk/tiledesk-whatsapp-connector": "^0.1.73",
53
53
  "@tiledesk/tiledesk-whatsapp-jobworker": "^0.0.8",
54
54
  "@tiledesk/tiledesk-sms-connector": "^0.1.10",
55
- "@tiledesk/tiledesk-vxml-connector": "^0.1.43",
55
+ "@tiledesk/tiledesk-vxml-connector": "^0.1.44",
56
56
  "amqplib": "^0.5.5",
57
57
  "app-root-path": "^3.0.0",
58
58
  "bcrypt-nodejs": "0.0.3",
package/routes/kb.js CHANGED
@@ -14,6 +14,7 @@ var mongoose = require('mongoose');
14
14
  const faq = require('../models/faq');
15
15
  const faq_kb = require('../models/faq_kb');
16
16
  let Integration = require('../models/integrations');
17
+ var parsecsv = require("fast-csv");
17
18
 
18
19
  const { MODELS_MULTIPLIER } = require('../utils/aiUtils');
19
20
 
@@ -994,6 +995,117 @@ router.post('/multi', upload.single('uploadFile'), async (req, res) => {
994
995
 
995
996
  })
996
997
 
998
+ router.post('/csv', upload.single('uploadFile'), async (req, res) => {
999
+
1000
+ let project_id = req.projectid;
1001
+
1002
+ let csv = req.file.buffer.toString('utf8');
1003
+ winston.debug("csv: ", csv);
1004
+
1005
+ let delimiter = req.body.delimiter || ";";
1006
+ winston.debug("delimiter: ", delimiter);
1007
+
1008
+ let namespace_id = req.query.namespace;
1009
+ if (!namespace_id) {
1010
+ return res.status(400).send({ success: false, error: "queryParam 'namespace' is not defined" })
1011
+ }
1012
+
1013
+ let namespaces = await Namespace.find({ id_project: project_id }).catch((err) => {
1014
+ winston.error("find namespaces error: ", err)
1015
+ res.status(500).send({ success: false, error: err })
1016
+ })
1017
+
1018
+ if (!namespaces || namespaces.length == 0) {
1019
+ let alert = "No namespace found for the selected project " + project_id + ". Cannot add content to a non-existent namespace."
1020
+ winston.warn(alert);
1021
+ res.status(403).send({ success: false, error: alert });
1022
+ }
1023
+
1024
+ let namespaceIds = namespaces.map(namespace => namespace.id);
1025
+
1026
+ if (!namespaceIds.includes(namespace_id)) {
1027
+ return res.status(403).send({ success: false, error: "Not allowed. The namespace does not belong to the current project." })
1028
+ }
1029
+
1030
+ let quoteManager = req.app.get('quote_manager');
1031
+ let limits = await quoteManager.getPlanLimits(req.project);
1032
+ let kbs_limit = limits.kbs;
1033
+ winston.verbose("Limit of kbs for current plan: " + kbs_limit);
1034
+
1035
+ let kbs_count = await KB.countDocuments({ id_project: project_id }).exec();
1036
+ winston.verbose("Kbs count: " + kbs_count);
1037
+
1038
+ if (kbs_count >= kbs_limit) {
1039
+ return res.status(403).send({ success: false, error: "Maximum number of resources reached for the current plan", plan_limit: kbs_limit })
1040
+ }
1041
+
1042
+ let webhook = apiUrl + '/webhook/kb/status?token=' + KB_WEBHOOK_TOKEN;
1043
+
1044
+ let kbs = [];
1045
+
1046
+ parsecsv.parseString(csv, { headers: false, delimiter: delimiter })
1047
+ .on("data", (data) => {
1048
+
1049
+ let question = data[0];
1050
+ let answer = data[1];
1051
+
1052
+ console.log("data. ", data)
1053
+ kbs.push({
1054
+ id_project: project_id,
1055
+ name: question,
1056
+ source: question,
1057
+ type: 'faq',
1058
+ content: question + "\n" + answer,
1059
+ namespace: namespace_id,
1060
+ status: -1
1061
+ })
1062
+ })
1063
+ .on("end", () => {
1064
+ winston.debug("kbs after CSV parsing: ", kbs);
1065
+
1066
+ let total_count = kbs_count + kbs.length;
1067
+ if (total_count >= kbs_limit) {
1068
+ return res.status(403).send({ success: false, error: "Cannot exceed the number of resources in the current plan", plan_limit: kbs_limit })
1069
+ }
1070
+
1071
+ if (kbs.length > 300) {
1072
+ return res.status(403).send({ success: false, error: "Too many faqs. Can't index more than 300 urls at a time." })
1073
+ }
1074
+
1075
+ let operations = kbs.map(doc => {
1076
+ return {
1077
+ updateOne: {
1078
+ filter: { id_project: doc.id_project, type: 'faq', source: doc.source },
1079
+ update: doc,
1080
+ upsert: true,
1081
+ returnOriginal: false
1082
+ }
1083
+ }
1084
+ })
1085
+
1086
+ saveBulk(operations, kbs, project_id).then((result) => {
1087
+ let resources = result.map(({ name, status, __v, createdAt, updatedAt, id_project, ...keepAttrs }) => keepAttrs)
1088
+ resources = resources.map(({ _id, ...rest}) => {
1089
+ return { id: _id, webhooh: webhook, ...rest };
1090
+ })
1091
+ winston.verbose("resources to be sent to worker: ", resources);
1092
+ if (!process.env.NODE_ENV) {
1093
+ scheduleScrape(resources);
1094
+ }
1095
+ res.status(200).send(result);
1096
+ }).catch((err) => {
1097
+ winston.error("Unabled to saved kbs in bulk " + err);
1098
+ res.status(500).send(err);
1099
+ })
1100
+
1101
+ })
1102
+ .on("error", (err) => {
1103
+ winston.error("CSV parsing error: ", err);
1104
+ res.status(400).send({ success: false, error: err });
1105
+ })
1106
+
1107
+ })
1108
+
997
1109
  router.post('/sitemap', async (req, res) => {
998
1110
 
999
1111
  let sitemap_url = req.body.sitemap;
@@ -0,0 +1,2 @@
1
+ Question 1;Question 1 Answer 1
2
+ Question 2;Question 2 Answer 2
package/test/kbRoute.js CHANGED
@@ -277,6 +277,51 @@ describe('KbRoute', () => {
277
277
  })
278
278
  }).timeout(20000)
279
279
 
280
+ it('add-multiple-faqs-with-csv', (done) => {
281
+
282
+ var email = "test-signup-" + Date.now() + "@email.com";
283
+ var pwd = "pwd";
284
+
285
+ userService.signup(email, pwd, "Test Firstname", "Test lastname").then(function (savedUser) {
286
+ projectService.create("test-faqkb-create", savedUser._id).then(function (savedProject) {
287
+
288
+ chai.request(server)
289
+ .get('/' + savedProject._id + '/kb/namespace/all')
290
+ .auth(email, pwd)
291
+ .end((err, res) => {
292
+
293
+ if (err) { console.error("err: ", err); }
294
+ if (log) { console.log("res.body: ", res.body) }
295
+
296
+ res.should.have.status(200)
297
+ expect(res.body.length).to.equal(1);
298
+
299
+ let namespace_id = res.body[0].id;
300
+
301
+ chai.request(server)
302
+ .post('/' + savedProject._id + '/kb/csv?namespace=' + namespace_id)
303
+ .auth(email, pwd)
304
+ .set('Content-Type', 'text/csv')
305
+ .attach('uploadFile', fs.readFileSync(path.resolve(__dirname, './example-kb-faqs.csv')), 'example-kb-faqs.csv')
306
+ .field('delimiter', ';')
307
+ .end((err, res) => {
308
+
309
+ if (err) { console.error("err: ", err); }
310
+ if (log) { console.log("res.body: ", res.body) }
311
+ console.log("res.body: ", res.body)
312
+
313
+ res.should.have.status(200);
314
+
315
+ done();
316
+
317
+ })
318
+ })
319
+ });
320
+ });
321
+
322
+ }).timeout(10000)
323
+
324
+
280
325
  /**
281
326
  * If you try to add content to a project that has no namespace, it returns 403 forbidden.
282
327
  */