@tiledesk/tiledesk-server 2.9.24 → 2.9.26

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/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
  */