@tiledesk/tiledesk-server 2.10.56 → 2.10.58

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,23 @@
1
+ name: Docker Image Community Profiler latest CI
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ branches: [ master ]
8
+
9
+ jobs:
10
+ push_to_registry:
11
+ name: Push Docker image to Docker Hub
12
+ runs-on: ubuntu-latest
13
+
14
+ steps:
15
+ - uses: actions/checkout@v2
16
+ name: Check out the repo
17
+ - uses: docker/build-push-action@v1
18
+ with:
19
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
20
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
21
+ repository: tiledesk/tiledesk-server
22
+ dockerfile: Dockerfile-profiler
23
+ tags: latest-profiler
package/CHANGELOG.md CHANGED
@@ -5,6 +5,14 @@
5
5
  🚀 IN PRODUCTION 🚀
6
6
  (https://www.npmjs.com/package/@tiledesk/tiledesk-server/v/2.3.77)
7
7
 
8
+ # 2.10.58
9
+ - updated tybot-connector to 0.2.150
10
+ - fix issue on reconnect to rabbit queue (kb indexing)
11
+ - updated multi-worker to 0.1.19
12
+ - fix issue on TILEBOT_ENDPOINT undefined
13
+ - added endpoint for llm preview
14
+ - updated default contexts for gpt-4o and gpt-4o-mini
15
+
8
16
  # 2.10.56
9
17
  - bug fix: wrong tilebot_endpoint declaration
10
18
 
@@ -0,0 +1,33 @@
1
+ FROM node:16
2
+
3
+ RUN sed -i 's/stable\/updates/stable-security\/updates/' /etc/apt/sources.list
4
+
5
+
6
+ RUN apt-get update
7
+
8
+ # Create app directory
9
+ WORKDIR /usr/src/app
10
+
11
+ ARG NPM_TOKEN
12
+
13
+ RUN if [ "$NPM_TOKEN" ]; \
14
+ then RUN COPY .npmrc_ .npmrc \
15
+ else export SOMEVAR=world; \
16
+ fi
17
+
18
+
19
+ # Install app dependencies
20
+ # A wildcard is used to ensure both package.json AND package-lock.json are copied
21
+ # where available (npm@5+)
22
+ COPY package*.json ./
23
+
24
+ RUN npm install --production
25
+
26
+ RUN rm -f .npmrc
27
+
28
+ # Bundle app source
29
+ COPY . .
30
+
31
+ EXPOSE 3000
32
+
33
+ CMD [ "node", "--prof", "./bin/www" ]
package/app.js CHANGED
@@ -122,6 +122,7 @@ var key = require('./routes/key');
122
122
  var widgets = require('./routes/widget');
123
123
  var widgetsLoader = require('./routes/widgetLoader');
124
124
  var openai = require('./routes/openai');
125
+ var llm = require('./routes/llm');
125
126
  var quotes = require('./routes/quotes');
126
127
  var integration = require('./routes/integration')
127
128
  var kbsettings = require('./routes/kbsettings');
@@ -600,7 +601,7 @@ app.use('/:projectid/emails',[passport.authenticate(['basic', 'jwt'], { session:
600
601
  app.use('/:projectid/properties',[passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRoleOrTypes('agent', ['bot','subscription'])], property);
601
602
  app.use('/:projectid/segments',[passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRoleOrTypes('agent', ['bot','subscription'])], segment);
602
603
 
603
- // app.use('/:projectid/openai', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRoleOrTypes('agent')], openai);
604
+ app.use('/:projectid/llm', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRoleOrTypes('admin', ['bot','subscription'])], llm);
604
605
  app.use('/:projectid/openai', openai);
605
606
  app.use('/:projectid/quotes', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRoleOrTypes('agent', ['bot','subscription'])], quotes)
606
607
 
@@ -655,11 +656,17 @@ app.use((err, req, res, next) => {
655
656
 
656
657
  winston.debug("err.name", err.name)
657
658
  if (err.name === "IpDeniedError") {
658
- winston.info("IpDeniedError");
659
+ winston.debug("IpDeniedError");
659
660
  return res.status(401).json({ err: "error ip filter" });
661
+ }
662
+
663
+ //emitted by multer when the file is too big
664
+ if (err.code === "LIMIT_FILE_SIZE") {
665
+ winston.debug("LIMIT_FILE_SIZE");
666
+ return res.status(413).json({ err: "Content Too Large", limit_file_size: process.env.MAX_UPLOAD_FILE_SIZE });
660
667
  }
661
668
 
662
- winston.error("General error", err);
669
+ winston.error("General error:: ", err);
663
670
  return res.status(500).json({ err: "error" });
664
671
  });
665
672
 
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.10.56",
4
+ "version": "2.10.58",
5
5
  "scripts": {
6
6
  "start": "node ./bin/www",
7
7
  "pretest": "mongodb-runner start",
@@ -47,8 +47,8 @@
47
47
  "@tiledesk/tiledesk-messenger-connector": "^0.1.23",
48
48
  "@tiledesk/tiledesk-rasa-connector": "^1.0.10",
49
49
  "@tiledesk/tiledesk-telegram-connector": "^0.1.14",
50
- "@tiledesk/tiledesk-tybot-connector": "^0.2.148",
51
- "@tiledesk/tiledesk-whatsapp-connector": "^0.1.76",
50
+ "@tiledesk/tiledesk-tybot-connector": "^0.2.150",
51
+ "@tiledesk/tiledesk-whatsapp-connector": "^0.1.77",
52
52
  "@tiledesk/tiledesk-whatsapp-jobworker": "^0.0.11",
53
53
  "@tiledesk/tiledesk-sms-connector": "^0.1.11",
54
54
  "@tiledesk/tiledesk-vxml-connector": "^0.1.67",
package/routes/faq.js CHANGED
@@ -3,7 +3,6 @@ var router = express.Router();
3
3
  var Faq = require("../models/faq");
4
4
  var Faq_kb = require("../models/faq_kb");
5
5
  var multer = require('multer')
6
- var upload = multer()
7
6
  const faqBotEvent = require('../event/faqBotEvent');
8
7
  var winston = require('../config/winston');
9
8
  const faqEvent = require('../event/faqBotEvent')
@@ -20,6 +19,19 @@ const roleChecker = require('../middleware/has-role');
20
19
 
21
20
  const apiUrl = process.env.API_URL || configGlobal.apiUrl;
22
21
 
22
+
23
+ let MAX_UPLOAD_FILE_SIZE = process.env.MAX_UPLOAD_FILE_SIZE;
24
+ let uploadlimits = undefined;
25
+
26
+ if (MAX_UPLOAD_FILE_SIZE) {
27
+ uploadlimits = {fileSize: parseInt(MAX_UPLOAD_FILE_SIZE)} ;
28
+ winston.debug("Max upload file size is : " + MAX_UPLOAD_FILE_SIZE);
29
+ } else {
30
+ winston.debug("Max upload file size is infinity");
31
+ }
32
+ var upload = multer({limits: uploadlimits});
33
+
34
+
23
35
  // POST CSV FILE UPLOAD FROM CLIENT
24
36
  router.post('/uploadcsv', roleChecker.hasRoleOrTypes('admin', ['bot', 'subscription']), upload.single('uploadFile'), function (req, res, next) {
25
37
  winston.debug(' -> -> REQ BODY ', req.body);
package/routes/faq_kb.js CHANGED
@@ -10,7 +10,6 @@ var winston = require('../config/winston');
10
10
  var httpUtil = require("../utils/httpUtil");
11
11
  const { forEach } = require('lodash');
12
12
  var multer = require('multer')
13
- var upload = multer()
14
13
  var configGlobal = require('../config/global');
15
14
  const faq = require('../models/faq');
16
15
  var jwt = require('jsonwebtoken');
@@ -22,6 +21,19 @@ const errorCodes = require('../errorCodes');
22
21
 
23
22
  let chatbot_templates_api_url = process.env.CHATBOT_TEMPLATES_API_URL
24
23
 
24
+
25
+ let MAX_UPLOAD_FILE_SIZE = process.env.MAX_UPLOAD_FILE_SIZE;
26
+ let uploadlimits = undefined;
27
+
28
+ if (MAX_UPLOAD_FILE_SIZE) {
29
+ uploadlimits = {fileSize: parseInt(MAX_UPLOAD_FILE_SIZE)} ;
30
+ winston.debug("Max upload file size is : " + MAX_UPLOAD_FILE_SIZE);
31
+ } else {
32
+ winston.debug("Max upload file size is infinity");
33
+ }
34
+ var upload = multer({limits: uploadlimits});
35
+
36
+
25
37
  router.post('/', roleChecker.hasRole('admin'), async function (req, res) {
26
38
  winston.debug('create BOT ', req.body);
27
39
 
package/routes/files.js CHANGED
@@ -19,8 +19,16 @@ const fileService = new FileGridFsService("files");
19
19
 
20
20
 
21
21
 
22
-
23
- const upload = multer({ storage: fileService.getStorage("files") });
22
+ let MAX_UPLOAD_FILE_SIZE = process.env.MAX_UPLOAD_FILE_SIZE;
23
+ let uploadlimits = undefined;
24
+
25
+ if (MAX_UPLOAD_FILE_SIZE) {
26
+ uploadlimits = {fileSize: parseInt(MAX_UPLOAD_FILE_SIZE)} ;
27
+ winston.info("Max upload file size is : " + MAX_UPLOAD_FILE_SIZE);
28
+ } else {
29
+ winston.info("Max upload file size is infinity");
30
+ }
31
+ const upload = multer({ storage: fileService.getStorage("files"),limits: uploadlimits});
24
32
 
25
33
  /*
26
34
  curl -u andrea.leo@f21.it:123456 \
package/routes/images.js CHANGED
@@ -35,6 +35,18 @@ const fileFilter = (req, file, cb) => {
35
35
  }
36
36
  }
37
37
 
38
+
39
+ let MAX_UPLOAD_FILE_SIZE = process.env.MAX_UPLOAD_FILE_SIZE;
40
+ let uploadlimits = undefined;
41
+
42
+ if (MAX_UPLOAD_FILE_SIZE) {
43
+ uploadlimits = {fileSize: parseInt(MAX_UPLOAD_FILE_SIZE)} ;
44
+ winston.debug("Max upload file size is : " + MAX_UPLOAD_FILE_SIZE);
45
+ } else {
46
+ winston.debug("Max upload file size is infinity");
47
+ }
48
+
49
+
38
50
  // const bodymiddleware = function(req, res, next) {
39
51
  // winston.info("YYYYYY req.body.folder:"+req.body.folder);
40
52
  // winston.info("YYYYYY req.body:",req.body);
@@ -42,7 +54,7 @@ const fileFilter = (req, file, cb) => {
42
54
  // }
43
55
 
44
56
 
45
- const upload = multer({ storage: fileService.getStorage("images"), fileFilter: fileFilter });
57
+ const upload = multer({ storage: fileService.getStorage("images"), fileFilter: fileFilter, limits: uploadlimits });
46
58
 
47
59
  /*
48
60
  curl -u andrea.leo@f21.it:123456 \
@@ -96,7 +108,7 @@ upload.single('file'), (req, res, next) => {
96
108
 
97
109
 
98
110
 
99
- const uploadFixedFolder = multer({ storage: fileService.getStorageFixFolder("images"), fileFilter: fileFilter });
111
+ const uploadFixedFolder = multer({ storage: fileService.getStorageFixFolder("images"), fileFilter: fileFilter, limits: uploadlimits });
100
112
 
101
113
  /*
102
114
  curl -v -X PUT -u andrea.leo@f21.it:123456 \
@@ -158,7 +170,7 @@ uploadFixedFolder.single('file'), (req, res, next) => {
158
170
 
159
171
 
160
172
 
161
- const uploadAvatar= multer({ storage: fileService.getStorageAvatar("images"), fileFilter: fileFilter });
173
+ const uploadAvatar= multer({ storage: fileService.getStorageAvatar("images"), fileFilter: fileFilter, limits: uploadlimits });
162
174
 
163
175
  /*
164
176
  curl -v -X PUT -u andrea.leo@f21.it:123456 \
package/routes/kb.js CHANGED
@@ -24,6 +24,19 @@ const JOB_TOPIC_EXCHANGE = process.env.JOB_TOPIC_EXCHANGE_TRAIN || 'tiledesk-tra
24
24
  const KB_WEBHOOK_TOKEN = process.env.KB_WEBHOOK_TOKEN || 'kbcustomtoken';
25
25
  const apiUrl = process.env.API_URL || configGlobal.apiUrl;
26
26
 
27
+
28
+ let MAX_UPLOAD_FILE_SIZE = process.env.MAX_UPLOAD_FILE_SIZE;
29
+ let uploadlimits = undefined;
30
+
31
+ if (MAX_UPLOAD_FILE_SIZE) {
32
+ uploadlimits = {fileSize: parseInt(MAX_UPLOAD_FILE_SIZE)} ;
33
+ winston.debug("Max upload file size is : " + MAX_UPLOAD_FILE_SIZE);
34
+ } else {
35
+ winston.debug("Max upload file size is infinity");
36
+ }
37
+ var upload = multer({limits: uploadlimits});
38
+
39
+
27
40
  let jobManager = new JobManager(AMQP_MANAGER_URL, {
28
41
  debug: false,
29
42
  topic: JOB_TOPIC_EXCHANGE,
@@ -60,8 +73,8 @@ let contexts = {
60
73
  "gpt-3.5-turbo": "You are an helpful assistant for question-answering tasks.\nUse ONLY the pieces of retrieved context delimited by #### to answer the question.\nIf you don't know the answer, just say: \"I don't know<NOANS>\"\n\n####{context}####",
61
74
  "gpt-4": "You are an helpful assistant for question-answering tasks.\nUse ONLY the pieces of retrieved context delimited by #### to answer the question.\nIf you don't know the answer, just say that you don't know.\nIf and only if none of the retrieved context is useful for your task, add this word to the end <NOANS>\n\n####{context}####",
62
75
  "gpt-4-turbo-preview": "You are an helpful assistant for question-answering tasks.\nUse ONLY the pieces of retrieved context delimited by #### to answer the question.\nIf you don't know the answer, just say that you don't know.\nIf and only if none of the retrieved context is useful for your task, add this word to the end <NOANS>\n\n####{context}####",
63
- "gpt-4o": "You are an helpful assistant for question-answering tasks.\nUse ONLY the pieces of retrieved context delimited by #### to answer the question.\nIf you don't know the answer, just say that you don't know.\nIf the context does not contain sufficient information to generate an accurate and informative answer, return <NOANS>\n\n####{context}####",
64
- "gpt-4o-mini": "You are an helpful assistant for question-answering tasks.\nUse ONLY the pieces of retrieved context delimited by #### to answer the question.\nIf you don't know the answer, just say that you don't know.\nIf the context does not contain sufficient information to generate an accurate and informative answer, return <NOANS>\n\n####{context}####"
76
+ "gpt-4o": "You are an helpful assistant for question-answering tasks. Follow these steps carefully:\n1. Answer in the same language of the user question, regardless of the retrieved context language\n2. Use ONLY the pieces of the retrieved context to answer the question.\n3. If the retrieved context does not contain sufficient information to generate an accurate and informative answer, return <NOANS>\n\n==Retrieved context start==\n{{context}}\n==Retrieved context end==",
77
+ "gpt-4o-mini": "You are an helpful assistant for question-answering tasks. Follow these steps carefully:\n1. Answer in the same language of the user question, regardless of the retrieved context language\n2. Use ONLY the pieces of the retrieved context to answer the question.\n3. If the retrieved context does not contain sufficient information to generate an accurate and informative answer, return <NOANS>\n\n==Retrieved context start==\n{{context}}\n==Retrieved context end==",
65
78
  }
66
79
 
67
80
  /**
package/routes/llm.js ADDED
@@ -0,0 +1,63 @@
1
+ var express = require('express');
2
+ var router = express.Router();
3
+ var winston = require('../config/winston');
4
+ let Integration = require('../models/integrations');
5
+ const aiService = require('../services/aiService');
6
+
7
+ router.post('/preview', async (req, res) => {
8
+
9
+ let id_project = req.projectid;
10
+ let body = req.body;
11
+ let key;
12
+
13
+ if (!body.llm) {
14
+ return res.status(400).send({ success: false, error: "Missing required parameter 'llm'" });
15
+ }
16
+
17
+ let integration = await Integration.findOne({ id_project: id_project, name: body.llm }).catch((err) => {
18
+ winston.error("Error finding integration with name: ", body.llm);
19
+ return res.status(500).send({ success: false, error: "Error finding integration for " + body.llm});
20
+ })
21
+
22
+ if (!integration) {
23
+ winston.verbose("Integration for " + body.llm + " not found.")
24
+ return res.status(404).send({ success: false, error: "Integration for " + body.llm + " not found."})
25
+ }
26
+
27
+ if (!integration?.value?.apikey) {
28
+ return res.status(422).send({ success: false, error: "The key provided for " + body.llm + " is not valid or undefined." })
29
+ }
30
+
31
+ key = integration.value.apikey;
32
+
33
+ let json = {
34
+ question: body.question,
35
+ llm: body.llm,
36
+ model: body.model,
37
+ llm_key: key,
38
+ temperature: body.temperature,
39
+ max_tokens: body.max_tokens
40
+ }
41
+
42
+ if (body.context) {
43
+ json.system_context = body.context;
44
+ }
45
+
46
+ aiService.askllm(json).then((response) => {
47
+ winston.verbose("Askllm response: ", response);
48
+ res.status(200).send(response.data)
49
+ }).catch((err) => {
50
+ if (err.response?.data?.detail[0]) {
51
+ res.status(400).send({ success: false, error: err.response.data.detail[0]?.msg, detail: err.response.data.detail });
52
+ } else if (err.response?.data?.detail?.answer) {
53
+ res.status(400).send({ success: false, error: err.response.data.detail.answer, detail: err.response.data.detail });
54
+ } else if (err.response?.data) {
55
+ res.status(500).send({ success: false, error: err.response.data });
56
+ } else {
57
+ res.status(500).send({ success: false, error: err });
58
+ }
59
+ })
60
+
61
+ })
62
+
63
+ module.exports = router;
package/routes/message.js CHANGED
@@ -247,12 +247,6 @@ async (req, res) => {
247
247
  });
248
248
  }).catch(function (err) { //pubblica questo
249
249
  winston.error('Error creating request: ' + JSON.stringify(err));
250
- winston.log({
251
- level: 'error',
252
- message: 'Error creating request: ' + JSON.stringify(err) + " " + JSON.stringify(req.body),
253
- label: req.projectid
254
- });
255
- // winston.error("Error creating message", err);
256
250
  return res.status(500).send({ success: false, msg: 'Error creating request', err: err });
257
251
  });
258
252
 
@@ -36,8 +36,29 @@ class AiService {
36
36
 
37
37
  }
38
38
 
39
+ // LLM
40
+ askllm(data) {
41
+ winston.debug("[OPENAI SERVICE] llm endpoint: " + kb_endpoint_qa);
39
42
 
40
- // PUGLIA AI
43
+ return new Promise((resolve, reject) => {
44
+
45
+ axios({
46
+ url: kb_endpoint_qa + "/ask",
47
+ headers: {
48
+ 'Content-Type': 'application/json'
49
+ },
50
+ data: data,
51
+ method: 'POST'
52
+ }).then((resbody) => {
53
+ resolve(resbody)
54
+ }).catch((err) => {
55
+ reject(err)
56
+ })
57
+ })
58
+ }
59
+
60
+
61
+ // KB
41
62
  checkStatus(data) {
42
63
  winston.debug("[OPENAI SERVICE] kb endpoint: " + kb_endpoint);
43
64
 
@@ -93,7 +93,7 @@ class WebSocketServer {
93
93
  token = token.replace('JWT ', '');
94
94
  jwt.verify(token, configSecretOrPubicKay, function (err, decoded) { //pub_jwt pp_jwt
95
95
  if (err) {
96
- winston.error('WebSocket error verifing websocket jwt token ', err);
96
+ winston.error('WebSocket error verifing websocket jwt token: ' + token, err);
97
97
  return cb(false, 401, 'Unauthorized');
98
98
  } else {
99
99
  // uncomment it