@tiledesk/tiledesk-voice-twilio-connector 0.1.28 → 0.2.0-rc3

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.
Files changed (50) hide show
  1. package/LICENSE +179 -0
  2. package/README.md +44 -0
  3. package/index.js +7 -1562
  4. package/package.json +23 -22
  5. package/src/app.js +146 -0
  6. package/src/config/index.js +32 -0
  7. package/src/controllers/VoiceController.js +488 -0
  8. package/src/controllers/VoiceController.original.js +811 -0
  9. package/src/middlewares/httpLogger.js +31 -0
  10. package/src/models/KeyValueStore.js +78 -0
  11. package/src/routes/manageApp.js +298 -0
  12. package/src/routes/voice.js +22 -0
  13. package/src/services/AiService.js +219 -0
  14. package/src/services/AiService.sdk.js +367 -0
  15. package/src/services/IntegrationService.js +74 -0
  16. package/src/services/MessageService.js +133 -0
  17. package/src/services/README_SDK.md +107 -0
  18. package/src/services/SessionService.js +143 -0
  19. package/src/services/SpeechService.js +134 -0
  20. package/src/services/TiledeskMessageBuilder.js +135 -0
  21. package/src/services/TwilioService.js +122 -0
  22. package/src/services/UploadService.js +78 -0
  23. package/src/services/channels/TiledeskChannel.js +269 -0
  24. package/{tiledesk → src/services/channels}/VoiceChannel.js +17 -56
  25. package/src/services/clients/TiledeskSubscriptionClient.js +78 -0
  26. package/src/services/index.js +45 -0
  27. package/src/services/translators/TiledeskTwilioTranslator.js +509 -0
  28. package/{tiledesk/TiledeskTwilioTranslator.js → src/services/translators/TiledeskTwilioTranslator.original.js} +119 -212
  29. package/src/utils/fileUtils.js +24 -0
  30. package/src/utils/logger.js +32 -0
  31. package/{tiledesk → src/utils}/utils-message.js +6 -21
  32. package/logs/app.log +0 -3082
  33. package/routes/manageApp.js +0 -419
  34. package/tiledesk/KVBaseMongo.js +0 -101
  35. package/tiledesk/TiledeskChannel.js +0 -363
  36. package/tiledesk/TiledeskSubscriptionClient.js +0 -135
  37. package/tiledesk/fileUtils.js +0 -55
  38. package/tiledesk/services/AiService.js +0 -230
  39. package/tiledesk/services/IntegrationService.js +0 -81
  40. package/tiledesk/services/UploadService.js +0 -88
  41. /package/{winston.js → src/config/logger.js} +0 -0
  42. /package/{tiledesk → src}/services/voiceEventEmitter.js +0 -0
  43. /package/{template → src/template}/configure.html +0 -0
  44. /package/{template → src/template}/css/configure.css +0 -0
  45. /package/{template → src/template}/css/error.css +0 -0
  46. /package/{template → src/template}/css/style.css +0 -0
  47. /package/{template → src/template}/error.html +0 -0
  48. /package/{tiledesk → src/utils}/constants.js +0 -0
  49. /package/{tiledesk → src/utils}/errors.js +0 -0
  50. /package/{tiledesk → src/utils}/utils.js +0 -0
@@ -1,230 +0,0 @@
1
- var winston = require('../../winston');
2
- const axios = require("axios").default;
3
- const FormData = require('form-data');
4
-
5
- /*ERROR HANDLER*/
6
- const { ServiceError } = require('../errors');
7
-
8
- /*UTILS*/
9
- const fileUtils = require('../fileUtils.js')
10
-
11
- class AiService {
12
-
13
- constructor(config) {
14
-
15
- if (!config) {
16
- throw new Error("[AiService] config is mandatory");
17
- }
18
- if (!config.OPENAI_ENDPOINT) {
19
- throw new Error("[AiService] config.OPENAI_ENDPOINT is mandatory");
20
- }
21
- if(!config.ELEVENLABS_ENDPOINT){
22
- throw new Error("[AiService] config.ELEVENLABS_ENDPOINT is mandatory");
23
- }
24
- if (!config.API_URL) {
25
- throw new Error("[AiService] config.API_URL is mandatory");
26
- }
27
-
28
-
29
- this.OPENAI_ENDPOINT = config.OPENAI_ENDPOINT;
30
- this.ELEVENLABS_ENDPOINT = config.ELEVENLABS_ENDPOINT;
31
- this.API_URL = config.API_URL;
32
-
33
- }
34
-
35
- async speechToText(fileUrl, model, GPT_KEY) {
36
- let start_time = new Date();
37
- winston.debug("[AiService] speechToText url: "+ fileUrl);
38
-
39
- return new Promise(async (resolve, reject) => {
40
-
41
- try {
42
- let file = await fileUtils.downloadFromUrl(fileUrl).catch((err) => {
43
- winston.error("[AiService] err while downloadFromUrl: ", err)
44
- return reject(new ServiceError('AISERVICE_FAILED', 'Cannot download audio file:', fileUrl));
45
- })
46
-
47
- if (!file) {
48
- winston.debug('[AiService] OPENAI speechToText file NOT EXIST: . . . return')
49
- return reject(new ServiceError('AISERVICE_FAILED', 'Cannot download audio file: file is null'));
50
- }
51
-
52
- const formData = new FormData();
53
- formData.append('file', file, { filename: 'audiofile.wav', contentType: 'audio/wav' });
54
- formData.append('model', model);
55
-
56
- axios({
57
- url: `${this.OPENAI_ENDPOINT}/audio/transcriptions`,
58
- headers: {
59
- ...formData.getHeaders(),
60
- "Authorization": "Bearer " + GPT_KEY
61
- },
62
- data: formData,
63
- method: 'POST'
64
- }).then((resbody) => {
65
- resolve(resbody.data.text);
66
- let end_time = new Date();
67
- winston.verbose(`-----> [AiService] OpenAI speechToText time elapsed: ${end_time - start_time} ms`);
68
- }).catch((err) => {
69
- reject(new ServiceError('AISERVICE_FAILED', 'OpenAI /audio/transcriptions API failed with err:', err));
70
- })
71
- } catch (error) {
72
- winston.error("[AiService] OpenAI STT error", err.message);
73
- reject(new ServiceError('AISERVICE_FAILED', 'OpenAI STT service failed with err:', err));
74
- }
75
-
76
-
77
- })
78
- }
79
-
80
- async textToSpeech(text, name, model, GPT_KEY){
81
- let start_time = new Date();
82
- winston.debug('[AiService] textToSpeech text:'+ text)
83
-
84
- const data = {
85
- model: model,
86
- input: text,
87
- voice: name,
88
- };
89
-
90
- winston.debug('[AiService] textToSpeech config:', data)
91
-
92
- return new Promise((resolve, reject) => {
93
- axios({
94
- url: `${this.OPENAI_ENDPOINT}/audio/speech`,
95
- headers: {
96
- "Content-Type": "application/json",
97
- "Authorization": "Bearer " + GPT_KEY
98
- },
99
- responseType: 'arraybuffer',
100
- data: data,
101
- method: "POST",
102
- }).then( async (response) => {
103
- //console.log('[AiService] textToSpeech result', response?.data)
104
- resolve(response?.data)
105
- let end_time = new Date();
106
- winston.verbose(`-----> [AiService] textToSpeech time elapsed: ${end_time - start_time} ms`);
107
- })
108
- .catch((err) => {
109
- winston.error("[AiService] textToSpeech error: ", err.response?.data);
110
- reject(new ServiceError('AISERVICE_FAILED', 'OpenAI textToSpeech API failed with err:', err));
111
- });
112
- });
113
-
114
- }
115
-
116
-
117
-
118
- async speechToTextElevenLabs(fileUrl, model, language, API_KEY) {
119
- let start_time = new Date();
120
- winston.debug("[AiService] ELEVEN Labs speechToText url: "+ fileUrl);
121
-
122
- return new Promise(async (resolve, reject) => {
123
-
124
- try {
125
- let file = await fileUtils.downloadFromUrl(fileUrl).catch((err) => {
126
- winston.error("[AiService] err: ", err)
127
- return reject(new ServiceError('AISERVICE_FAILED', 'Cannot download audio file:', fileUrl));
128
- })
129
-
130
- if (!file) {
131
- winston.debug('[AiService] ELEVEN Labs speechToText file NOT EXIST: . . . return')
132
- return reject(new ServiceError('AISERVICE_FAILED', 'Cannot download audio file: file is null'));
133
- }
134
-
135
-
136
- const formData = new FormData();
137
- formData.append('file', file, { filename: 'audiofile.wav', contentType: 'audio/wav' });
138
- formData.append('model_id', "scribe_v1");
139
- formData.append('language_code', language)
140
-
141
- axios({
142
- url: `${this.ELEVENLABS_ENDPOINT}/v1/speech-to-text`,
143
- headers: {
144
- ...formData.getHeaders(),
145
- "xi-api-key": API_KEY
146
- },
147
- data: formData,
148
- method: 'POST'
149
- }).then((resbody) => {
150
- resolve(resbody.data.text);
151
- let end_time = new Date();
152
- winston.verbose(`-----> [AiService] ELEVEN Labs speechToText time elapsed: ${end_time - start_time} ms`);
153
- }).catch((err) => {
154
- reject(new ServiceError('AISERVICE_FAILED', 'ElevenLabs /speech-to-text API failed with err:', err));
155
- })
156
- } catch (error) {
157
- winston.error("[AiService] ElevenLabs STT error", err.message);
158
- reject(new ServiceError('AISERVICE_FAILED', 'ElevenLabs STT service failed with err:', err));
159
- }
160
-
161
- })
162
- }
163
-
164
- async textToSpeechElevenLabs(text, voice_id, model, language_code, API_KEY){
165
- let start_time = new Date();
166
- const data = {
167
- model_id: model,
168
- text: text,
169
- language_code: language_code
170
- };
171
- winston.debug('[AiService] ELEVEN Labs textToSpeech config:', data)
172
-
173
- return new Promise((resolve, reject) => {
174
- axios({
175
- url: `${this.ELEVENLABS_ENDPOINT}/v1/text-to-speech/${voice_id}?output_format=mp3_44100_128`,
176
- headers: {
177
- "Content-Type": "application/json",
178
- "xi-api-key": API_KEY
179
- },
180
- responseType: 'arraybuffer',
181
- data: data,
182
- method: "POST",
183
- }).then( async (response) => {
184
- resolve(response?.data)
185
- let end_time = new Date();
186
- winston.verbose(`-----> [AiService] ELEVEN Labs textToSpeech time elapsed: ${end_time - start_time} ms`);
187
- })
188
- .catch((err) => {
189
- winston.error("[AiService] ELEVEN Labs textToSpeech error: ", err);
190
- reject(new ServiceError('AISERVICE_FAILED', 'ElevenLabs textToSpeech API failed with err:', err));
191
- });
192
- });
193
-
194
- }
195
-
196
-
197
-
198
- async checkQuoteAvailability(projectId, token) {
199
-
200
- winston.debug("[AiService] checkQuoteAvailability for project: "+ projectId);
201
-
202
- return new Promise((resolve, reject) => {
203
-
204
- axios({
205
- url: `${this.API_URL}/${projectId}/quotes/tokens`,
206
- headers: {
207
- 'Content-Type': 'application/json',
208
- 'Authorization': token
209
- },
210
- method: 'GET'
211
- }).then((resbody) => {
212
- if (resbody && resbody.data?.isAvailable === true) {
213
- resolve(true)
214
- } else {
215
- resolve(false)
216
- }
217
- }).catch((err) => {
218
- winston.error("[AiService] checkQuoteAvailability error: ", err.response?.data);
219
- reject(new ServiceError('AISERVICE_FAILED', 'checkQuoteAvailability API failed with err:', err));
220
- })
221
-
222
- })
223
- }
224
-
225
-
226
-
227
-
228
- }
229
-
230
- module.exports = { AiService };
@@ -1,81 +0,0 @@
1
-
2
- var winston = require('../../winston');
3
- const axios = require("axios").default;
4
- const FormData = require('form-data');
5
-
6
- /*UTILS*/
7
- const fileUtils = require('../fileUtils.js')
8
-
9
- class IntegrationService {
10
-
11
- constructor(config) {
12
-
13
- if (!config) {
14
- throw new Error("[IntegrationService] config is mandatory");
15
- }
16
- if (!config.API_URL) {
17
- throw new Error("[IntegrationService] config.API_URL is mandatory");
18
- }
19
-
20
- this.API_URL = config.API_URL;
21
-
22
- }
23
-
24
-
25
- async getKeyFromIntegrations(id_project, integration_name, token){
26
-
27
- winston.debug('[IntegrationService] getKeyFromIntegrations id_project:'+ id_project + ' ' + integration_name)
28
-
29
- return await axios({
30
- url: this.API_URL + "/"+ id_project + "/integration/name/" + integration_name,
31
- headers: {
32
- 'Content-Type': 'application/json',
33
- 'Authorization': token
34
- },
35
- data: {},
36
- method: "GET",
37
- }).then( async (response) => {
38
- if (!response.data || !response.data?.value) {
39
- return null;
40
- }
41
-
42
- return response.data?.value?.apikey
43
- })
44
- .catch((err) => {
45
- winston.error("[IntegrationService] getKeyFromIntegrations error: ", err.response?.data);
46
- return null;
47
- });
48
-
49
-
50
- }
51
-
52
- async getKeyFromKbSettings(id_project, token) {
53
-
54
- winston.debug('[IntegrationService] getKeyFromIntegrations id_project:', id_project)
55
-
56
- return await axios({
57
- url: this.API_URL + "/"+ id_project + "/kbsettings",
58
- headers: {
59
- 'Content-Type': 'application/json',
60
- 'Authorization': token
61
- },
62
- data: {},
63
- method: "GET",
64
- }).then( async (response) => {
65
- if (!response.data || response.data?.gptkey) {
66
- return null;
67
- }
68
-
69
- return response.data?.gptkey
70
- })
71
- .catch((err) => {
72
- return null;
73
- });
74
-
75
- }
76
-
77
-
78
-
79
- }
80
-
81
- module.exports = { IntegrationService };
@@ -1,88 +0,0 @@
1
- var winston = require('../../winston');
2
- const axios = require("axios").default;
3
- const FormData = require('form-data');
4
- const fs = require('fs');
5
- const path = require('path');
6
-
7
- /*UTILS*/
8
- const fileUtils = require('../fileUtils.js')
9
-
10
- /*ERROR HANDLER*/
11
- const { ServiceError } = require('../errors');
12
-
13
- class UploadService {
14
-
15
- constructor(config) {
16
-
17
- if (!config) {
18
- throw new Error("[UploadService] config is mandatory");
19
- }
20
- if (!config.API_URL) {
21
- throw new Error("[UploadService] config.API_URL is mandatory");
22
- }
23
-
24
- if (config.user) {
25
- this.user = config.user
26
- }
27
-
28
- this.API_URL = config.API_URL;
29
-
30
- }
31
-
32
- async upload(id, file, user) {
33
-
34
- winston.debug(`[UploadService] upload for id ${id} and user ${user}`);
35
-
36
-
37
- // Step 2: Salva il file MP3 localmente (temporaneamente)
38
- const tempFilePath = path.join(__dirname, `speech_${user._id}_${id}.wav`);
39
- fs.writeFileSync(tempFilePath, file);
40
-
41
- // Step 3: Carica il file al tuo server
42
- const formData = new FormData();
43
- formData.append('file', fs.createReadStream(tempFilePath), {
44
- filename: `audiofile_${user._id}_${id}.wav`,
45
- contentType: 'audio/mpeg'
46
- });
47
-
48
-
49
- return new Promise((resolve, reject) => {
50
-
51
- //const formData = new FormData();
52
- //formData.append('file', file, { filename: 'audiofile_'+user._id+'_'+id+'.mp3', contentType: 'audio/mpeg' });
53
- user.token = 'JWT eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2NWM1ZjExNjlmYWYyZDA0Y2Q3ZGE1MjciLCJlbWFpbCI6ImdhYnJpZWxlQHRpbGVkZXNrLmNvbSIsImZpcnN0bmFtZSI6IkdhYnJpZWxlIiwibGFzdG5hbWUiOiJQYW5pY28iLCJlbWFpbHZlcmlmaWVkIjp0cnVlLCJpYXQiOjE3NDgyNTY2MTUsImF1ZCI6Imh0dHBzOi8vdGlsZWRlc2suY29tIiwiaXNzIjoiaHR0cHM6Ly90aWxlZGVzay5jb20iLCJzdWIiOiJ1c2VyIiwianRpIjoiNWUyZDhhYmUtYzQ0YS00MjJiLWE3MjUtYWYwMjcxNDgyZTczIn0.AcT1tNbE3AcfctJXfOsfUbytRNUQlhBqPUctxzXMjehZOS2ORJThWaPqPxrvqTTIyeOU2l6eoTw8_tqfRJGlp6X4m9KLio87axGl1z3WYBgh8bSMIkAw2zSIUuJmpjBuT8EZdjXZClXRUAliAvAoFRgCmhWJ1tODVvBynLiSb37sB_zscqWH5L5eF1vdt6HHizEO4HbGABQS00I2hEPn99ssC9Y3W4_UhDcitZG80ACwS_Bpl6uk8OxAFybZ1DHHkBS1AK-lCO2P2JJCFRyM33mcvTgb9B6pADETzgJT2qfgOU4-1Pm0l55Mij1LS-h7QTj95DTFQMM7DD6elP0WcA'
54
-
55
- axios({
56
- url: this.API_URL + "/files/users",
57
- headers: {
58
- ...formData.getHeaders(),
59
- "Authorization": user.token
60
- },
61
- data: formData,
62
- method: 'POST'
63
- }).then((resbody) => {
64
- if(resbody?.data){
65
-
66
- // Step 4: Pulisci il file temporaneo
67
- fs.unlinkSync(tempFilePath);
68
-
69
- let fileUrl = this.API_URL + "/files?path="+resbody?.data.filename
70
- resolve(fileUrl);
71
- }
72
-
73
- }).catch((err) => {
74
- console.log('err', err)
75
- reject(new ServiceError('UPLOADSERVICE_FAILED', 'UploadService /files/users API failed with err:', err) );
76
- }).finally(() => {
77
- // Sempre eseguito
78
- if (fs.existsSync(tempFilePath)) {
79
- fs.unlinkSync(tempFilePath);
80
- }
81
- });
82
-
83
- })
84
- }
85
-
86
- }
87
-
88
- module.exports = { UploadService };
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes