@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.
- package/.github/workflows/docker-community-profiler-latest.yml +23 -0
- package/CHANGELOG.md +8 -0
- package/Dockerfile-profiler +33 -0
- package/app.js +10 -3
- package/package.json +3 -3
- package/routes/faq.js +13 -1
- package/routes/faq_kb.js +13 -1
- package/routes/files.js +10 -2
- package/routes/images.js +15 -3
- package/routes/kb.js +15 -2
- package/routes/llm.js +63 -0
- package/routes/message.js +0 -6
- package/services/aiService.js +22 -1
- package/websocket/webSocketServer.js +1 -1
@@ -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
|
-
|
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.
|
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.
|
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.
|
51
|
-
"@tiledesk/tiledesk-whatsapp-connector": "^0.1.
|
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
|
-
|
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
|
64
|
-
"gpt-4o-mini": "You are an helpful assistant for question-answering tasks
|
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
|
|
package/services/aiService.js
CHANGED
@@ -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
|
-
|
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
|