@tiledesk/tiledesk-tybot-connector 0.1.21 → 0.1.23
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 +10 -1
- package/ExtApi.js +37 -0
- package/index backup.js +656 -0
- package/index.js +58 -461
- package/models/IntentForm.js +12 -13
- package/models/MockBotsDataSource.js +74 -0
- package/models/MockIntentsMachine.js +39 -0
- package/models/MongodbBotsDataSource.js +73 -0
- package/models/MongodbIntentsMachine.js +55 -0
- package/models/{TiledeskChatbot_Intents_Adapter.js → TiledeskChatbot backup.js } +0 -1
- package/models/TiledeskChatbot.js +206 -180
- package/models/TiledeskIntentsMachine.js +90 -0
- package/models/faqKbService.js +27 -0
- package/models/faqService.js +22 -0
- package/models/faq_kb.js +11 -28
- package/package.json +2 -2
- package/test/close_directive_test.js +49 -0
- package/test/directives_test.js +24 -26
- package/test/disable_input_text_directive_test.js +88 -0
- package/test/mock_query_test.js +276 -0
- package/test/single_test.sh +4 -0
- package/test/when_open_directive_test.js +167 -0
- package/tiledeskChatbotPlugs/CHANGELOG.md +2 -0
- package/tiledeskChatbotPlugs/DirectivesChatbotPlug.js +66 -46
- package/tiledeskChatbotPlugs/directives/DirClose.js +25 -0
- package/tiledeskChatbotPlugs/directives/DirDeflectToHelpCenter.js +6 -6
- package/tiledeskChatbotPlugs/directives/DirDepartment.js +52 -0
- package/tiledeskChatbotPlugs/directives/DirDisableInputText.js +45 -0
- package/tiledeskChatbotPlugs/directives/DirIntent.js +50 -0
- package/tiledeskChatbotPlugs/directives/DirMessage.js +5 -4
- package/tiledeskChatbotPlugs/directives/DirWhenOpen.js +95 -0
- package/tiledeskChatbotPlugs/directives/Directives.js +3 -0
- package/tiledeskChatbotPlugs/package.json +1 -1
- package/models/MongoDBIntentsDataSource.js +0 -22
- package/models/StaticIntentsDataSource.js +0 -110
- package/test/chatbot_query_test.js_ +0 -41
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
let Faq = require('./faq');
|
|
2
|
-
let Faq_kb = require('./faq_kb');
|
|
3
|
-
const { ExtApi } = require('../ExtApi.js');
|
|
1
|
+
// let Faq = require('./faq');
|
|
2
|
+
// let Faq_kb = require('./faq_kb');
|
|
3
|
+
// const { ExtApi } = require('../ExtApi.js');
|
|
4
4
|
const { MessagePipeline } = require('../tiledeskChatbotPlugs/MessagePipeline');
|
|
5
|
-
const { DirectivesChatbotPlug } = require('../tiledeskChatbotPlugs/DirectivesChatbotPlug');
|
|
5
|
+
// const { DirectivesChatbotPlug } = require('../tiledeskChatbotPlugs/DirectivesChatbotPlug');
|
|
6
6
|
const { WebhookChatbotPlug } = require('../tiledeskChatbotPlugs/WebhookChatbotPlug');
|
|
7
7
|
const { TiledeskClient } = require('@tiledesk/tiledesk-client');
|
|
8
8
|
const { IntentForm } = require('./IntentForm.js');
|
|
@@ -10,9 +10,23 @@ const { IntentForm } = require('./IntentForm.js');
|
|
|
10
10
|
class TiledeskChatbot {
|
|
11
11
|
|
|
12
12
|
constructor(config) {
|
|
13
|
+
if (!config.botsDataSource) {
|
|
14
|
+
throw new Error("config.botsDataSource is mandatory");
|
|
15
|
+
}
|
|
16
|
+
if (!config.intentsFinder) {
|
|
17
|
+
throw new Error("config.intentsFinder is mandatory");
|
|
18
|
+
}
|
|
19
|
+
if (!config.botId) {
|
|
20
|
+
throw new Error("config.botId is mandatory");
|
|
21
|
+
}
|
|
22
|
+
if (!config.bot) {
|
|
23
|
+
throw new Error("config.bot is mandatory");
|
|
24
|
+
}
|
|
25
|
+
this.botsDataSource = config.botsDataSource;
|
|
26
|
+
this.intentsFinder = config.intentsFinder;
|
|
13
27
|
this.botId = config.botId;
|
|
28
|
+
this.bot = config.bot;
|
|
14
29
|
this.token = config.token;
|
|
15
|
-
this.faq_kb = config.faq_kb;
|
|
16
30
|
this.tdcache = config.tdcache;
|
|
17
31
|
this.APIURL = config.APIURL;
|
|
18
32
|
this.APIKEY = config.APIKEY;
|
|
@@ -20,161 +34,197 @@ class TiledeskChatbot {
|
|
|
20
34
|
this.projectId = config.projectId;
|
|
21
35
|
this.log = config.log;
|
|
22
36
|
}
|
|
23
|
-
|
|
37
|
+
|
|
24
38
|
async replyToMessage(message, callback) {
|
|
25
39
|
return new Promise( async (resolve, reject) => {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
40
|
+
// get bot info
|
|
41
|
+
//let bot;
|
|
42
|
+
let lead = null;
|
|
43
|
+
if (message.request) {
|
|
44
|
+
this.request = message.request;
|
|
45
|
+
lead = message.request.lead;
|
|
46
|
+
}
|
|
29
47
|
|
|
48
|
+
// Checking locked intent
|
|
30
49
|
const locked_intent = await this.currentLockedIntent(this.requestId);
|
|
31
50
|
if (this.log) {console.log("got locked intent", locked_intent)}
|
|
32
51
|
if (locked_intent) {
|
|
33
52
|
const tdclient = new TiledeskClient({
|
|
34
|
-
projectId:
|
|
53
|
+
projectId: this.projectId,
|
|
35
54
|
token: this.token,
|
|
36
55
|
APIURL: this.APIURL,
|
|
37
56
|
APIKEY: this.APIKEY,
|
|
38
57
|
log: false
|
|
39
58
|
});
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
59
|
+
// it only gets the locked_intent
|
|
60
|
+
const faq = await this.botsDataSource.getByIntentDisplayName(this.botId, locked_intent);
|
|
61
|
+
if (this.log) {console.log("locked intent. got faqs", faq)}
|
|
62
|
+
let reply;
|
|
63
|
+
if (faq) {
|
|
64
|
+
reply = await this.execIntent(faq, message, lead);//, bot);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
reply = {
|
|
68
|
+
"text": "An error occurred while getting locked intent:'" + locked_intent
|
|
69
|
+
}
|
|
70
|
+
}
|
|
43
71
|
resolve(reply);
|
|
44
72
|
return;
|
|
45
73
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
// BUT CHECKING ACTION BUTTON...
|
|
74
|
+
|
|
75
|
+
let explicit_intent_name = null;
|
|
76
|
+
// Explicit intent invocation
|
|
77
|
+
if (message.text.startsWith("/")) {
|
|
78
|
+
if (this.log) {console.log("Intent was explicitly invoked:", message.text);}
|
|
79
|
+
let intent_name = message.text.substring(message.text.indexOf("/") + 1);
|
|
80
|
+
if (this.log) {console.log("Invoked Intent:", intent_name);}
|
|
81
|
+
explicit_intent_name = intent_name;
|
|
82
|
+
// if (!message.attributes) {
|
|
83
|
+
// message.attributes = {}
|
|
84
|
+
// }
|
|
85
|
+
// message.attributes.action = intent_name;
|
|
86
|
+
// if (this.log) {console.log("Message action:", message.attributes.action)}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Intent invocation with action
|
|
63
90
|
if (message.attributes && message.attributes.action) {
|
|
64
|
-
|
|
65
|
-
|
|
91
|
+
if (this.log) {console.log("Message has action:", message.attributes.action)}
|
|
92
|
+
explicit_intent_name = message.attributes.action;
|
|
93
|
+
/*let action_parameters_index = action.indexOf("?");
|
|
66
94
|
if (action_parameters_index > -1) {
|
|
67
|
-
|
|
95
|
+
intent_name = intent_name.substring(0, action_parameters_index);
|
|
96
|
+
}*/
|
|
97
|
+
if (this.log) {console.log("Intent was explicitly invoked with an action:", explicit_intent_name);}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Checking Action button
|
|
101
|
+
if (explicit_intent_name) {
|
|
102
|
+
if (this.log) {console.log("Executing explicit intent:", explicit_intent_name)}
|
|
103
|
+
let faq = await this.botsDataSource.getByIntentDisplayName(this.botId, explicit_intent_name);
|
|
104
|
+
let reply;
|
|
105
|
+
if (faq) {
|
|
106
|
+
if (this.log) {console.log("Got a reply from Intent name:", faq);}
|
|
107
|
+
try {
|
|
108
|
+
reply = await this.execIntent(faq, message, lead);//, bot);
|
|
109
|
+
}
|
|
110
|
+
catch(error) {
|
|
111
|
+
console.error("error");
|
|
112
|
+
reject(error);
|
|
113
|
+
}
|
|
68
114
|
}
|
|
69
|
-
|
|
115
|
+
else {
|
|
116
|
+
if (this.log) {console.log("No reply found by direct intent invocation:", explicit_intent_name);}
|
|
117
|
+
reply = {
|
|
118
|
+
"text": "No reply found by direct intent invocation: *" + explicit_intent_name + "*"
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
resolve(reply);
|
|
122
|
+
return;
|
|
70
123
|
}
|
|
71
|
-
|
|
124
|
+
|
|
72
125
|
// SEARCH INTENTS
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
126
|
+
let faqs;
|
|
127
|
+
try {
|
|
128
|
+
faqs = await this.botsDataSource.getByExactMatch(this.botId, message.text);
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
console.error("An error occurred during exact match:", error);
|
|
132
|
+
}
|
|
133
|
+
if (faqs && faqs.length > 0 && faqs[0].answer) {
|
|
134
|
+
if (this.log) {console.log("EXACT MATCH OR ACTION FAQ:", faqs[0]);}
|
|
135
|
+
let reply;
|
|
136
|
+
try {
|
|
137
|
+
reply = await this.execIntent(faqs[0], message, lead);//, bot);
|
|
76
138
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
//resolve(this.execIntent(faqs, this.botId, message, bot)); // bot_token
|
|
139
|
+
catch(error) {
|
|
140
|
+
console.error("error during exact match execIntent():", error);
|
|
141
|
+
reject(error);
|
|
142
|
+
return;
|
|
82
143
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
search_obj["$language"] = this.faq_kb.language;
|
|
92
|
-
}
|
|
93
|
-
query.$text = search_obj;
|
|
94
|
-
//console.debug("fulltext search query", query);
|
|
95
|
-
|
|
96
|
-
mongoproject = { score: { $meta: "textScore" } };
|
|
97
|
-
sort = { score: { $meta: "textScore" } }
|
|
98
|
-
// DA QUI RECUPERO LA RISPOSTA DATO (ID: SE EXT_AI) (QUERY FULLTEXT SE NATIVE-BASIC-AI)
|
|
99
|
-
Faq.find(query, mongoproject).sort(sort).lean().exec(async (err, faqs) => {
|
|
100
|
-
if (this.log) {console.log("Found:", faqs);}
|
|
101
|
-
if (err) {
|
|
102
|
-
console.error("Error:", err);
|
|
103
|
-
}
|
|
104
|
-
if (faqs && faqs.length > 0 && faqs[0].answer) {
|
|
105
|
-
let reply = await this.execIntent(faqs, this.botId, message, bot);
|
|
106
|
-
resolve(reply);
|
|
107
|
-
}
|
|
108
|
-
else {
|
|
109
|
-
// fallback
|
|
110
|
-
const fallbackIntent = await this.getIntentByDisplayName("defaultFallback", bot);
|
|
111
|
-
const faqs = [fallbackIntent];
|
|
112
|
-
let reply = await this.execIntent(faqs, this.botId, message, bot);
|
|
113
|
-
resolve(reply); // bot_token
|
|
114
|
-
}
|
|
115
|
-
});
|
|
144
|
+
resolve(reply);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
else { // NLP
|
|
148
|
+
if (this.log) {console.log("NLP decode intent...");}
|
|
149
|
+
let intents;
|
|
150
|
+
try {
|
|
151
|
+
intents = await this.intentsFinder.decode(this.botId, message.text);
|
|
116
152
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
getIntentByDisplayName(name, bot) {
|
|
122
|
-
return new Promise((resolve, reject) => {
|
|
123
|
-
var query = { "id_project": bot.id_project, "id_faq_kb": bot._id, "intent_display_name": name};
|
|
124
|
-
if (this.log) {console.debug('query', query);}
|
|
125
|
-
Faq.find(query).lean().exec( (err, faqs) => {
|
|
126
|
-
if (err) {
|
|
127
|
-
return reject(err);
|
|
153
|
+
catch(error) {
|
|
154
|
+
console.error("An error occurred:", error);
|
|
128
155
|
}
|
|
129
|
-
if (this.log) {console.
|
|
130
|
-
if (
|
|
131
|
-
|
|
132
|
-
|
|
156
|
+
if (this.log) {console.log("NLP decoded found:", intents);}
|
|
157
|
+
if (intents && intents.length > 0) {
|
|
158
|
+
let faq = await this.botsDataSource.getByIntentDisplayName(this.botId, intents[0].intent_display_name);
|
|
159
|
+
let reply;
|
|
160
|
+
try {
|
|
161
|
+
reply = await this.execIntent(faq, message, lead);//, bot);
|
|
162
|
+
}
|
|
163
|
+
catch(error) {
|
|
164
|
+
console.error("error during NLP decoding:", error);
|
|
165
|
+
reject(error);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
resolve(reply);
|
|
169
|
+
return;
|
|
133
170
|
}
|
|
134
171
|
else {
|
|
135
|
-
|
|
172
|
+
// fallback
|
|
173
|
+
let fallbackIntent = await this.botsDataSource.getByIntentDisplayName(this.botId, "defaultFallback");
|
|
174
|
+
if (!fallbackIntent) {
|
|
175
|
+
resolve(null);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
let reply;
|
|
180
|
+
try {
|
|
181
|
+
reply = await this.execIntent(fallbackIntent, message, lead);//, bot);
|
|
182
|
+
}
|
|
183
|
+
catch(error) {
|
|
184
|
+
console.error("error during defaultFallback:", error);
|
|
185
|
+
reject(error);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
resolve(reply);
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
136
191
|
}
|
|
137
|
-
}
|
|
192
|
+
}
|
|
138
193
|
});
|
|
139
194
|
}
|
|
140
|
-
|
|
141
|
-
async execIntent(faqs, botId, message, bot) {
|
|
142
|
-
answerObj = faqs[0];
|
|
143
|
-
let sender = 'bot_' + botId;
|
|
144
|
-
var answerObj;
|
|
145
|
-
answerObj.score = 100; //exact search not set score
|
|
146
195
|
|
|
147
|
-
|
|
148
|
-
|
|
196
|
+
async execIntent(faq, message, lead) {//, bot) {
|
|
197
|
+
let answerObj = faq; // faqs[0];
|
|
198
|
+
const botId = this.botId;
|
|
199
|
+
let sender = 'bot_' + botId;
|
|
200
|
+
//var answerObj;
|
|
201
|
+
//answerObj.score = 100; // exact search has max score
|
|
149
202
|
if (this.log) {
|
|
150
|
-
console.log("requestId:", requestId)
|
|
203
|
+
console.log("requestId:", this.requestId)
|
|
151
204
|
console.log("token:", this.token)
|
|
152
|
-
console.log("projectId:", projectId)
|
|
205
|
+
console.log("projectId:", this.projectId)
|
|
153
206
|
}
|
|
154
|
-
|
|
155
207
|
if (this.tdcache) {
|
|
156
|
-
const requestKey = "tilebot:" + requestId
|
|
208
|
+
const requestKey = "tilebot:" + this.requestId
|
|
157
209
|
// best effort, do not "await", go on, trust redis speed.
|
|
158
|
-
this.tdcache.setJSON(requestKey,
|
|
210
|
+
this.tdcache.setJSON(requestKey, this.request);
|
|
159
211
|
}
|
|
160
212
|
// /ext/:projectId/requests/:requestId/messages ENDPOINT COINCIDES
|
|
161
213
|
// with API_ENDPOINT (APIRURL) ONLY WHEN THE TYBOT ROUTE IS HOSTED
|
|
162
214
|
// ON THE MAIN SERVER. OTHERWISE WE USE TYBOT_ROUTE TO SPECIFY
|
|
163
215
|
// THE ALTERNATIVE ROUTE.
|
|
164
|
-
let extEndpoint = `${this.APIURL}/modules/tilebot/`;
|
|
165
|
-
if (process.env.TYBOT_ENDPOINT) {
|
|
166
|
-
|
|
167
|
-
}
|
|
168
|
-
const apiext = new ExtApi({
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
});
|
|
172
|
-
//console.log("the form...")
|
|
173
|
-
|
|
174
|
-
// THE FORM
|
|
216
|
+
// let extEndpoint = `${this.APIURL}/modules/tilebot/`;
|
|
217
|
+
// if (process.env.TYBOT_ENDPOINT) {
|
|
218
|
+
// extEndpoint = `${process.env.TYBOT_ENDPOINT}`;
|
|
219
|
+
// }
|
|
220
|
+
// const apiext = new ExtApi({
|
|
221
|
+
// ENDPOINT: extEndpoint,
|
|
222
|
+
// log: this.log
|
|
223
|
+
// });
|
|
224
|
+
// console.log("the form...")
|
|
175
225
|
|
|
176
226
|
let intent_name = answerObj.intent_display_name
|
|
177
|
-
|
|
227
|
+
// THE FORM
|
|
178
228
|
if (intent_name === "test_form_intent") {
|
|
179
229
|
answerObj.form = {
|
|
180
230
|
"cancelCommands": ['annulla', 'cancella', 'reset', 'cancel'],
|
|
@@ -200,15 +250,16 @@ class TiledeskChatbot {
|
|
|
200
250
|
};
|
|
201
251
|
}
|
|
202
252
|
let intent_form = answerObj.form;
|
|
203
|
-
if (
|
|
204
|
-
|
|
253
|
+
if (this.log) {
|
|
254
|
+
console.log("IntentForm.isValidForm(intent_form)", IntentForm.isValidForm(intent_form));
|
|
255
|
+
}
|
|
256
|
+
if (IntentForm.isValidForm(intent_form)) {
|
|
257
|
+
await this.lockIntent(this.requestId, intent_name);
|
|
205
258
|
const user_reply = message.text;
|
|
206
|
-
//const intent_answer = answerObj.answer; //req.body.payload.text;
|
|
207
259
|
let form_reply = await this.execIntentForm(user_reply, intent_form);
|
|
208
|
-
|
|
209
|
-
//if (form_reply_message) {
|
|
260
|
+
console.log("got form reply", form_reply)
|
|
210
261
|
if (!form_reply.canceled && form_reply.message) {
|
|
211
|
-
|
|
262
|
+
console.log("Form replying for next field...");
|
|
212
263
|
if (this.log) {console.log("Sending form reply...", form_reply.message)}
|
|
213
264
|
// reply with this message (ex. please enter your fullname)
|
|
214
265
|
if (!form_reply.message.attributes) {
|
|
@@ -218,24 +269,21 @@ class TiledeskChatbot {
|
|
|
218
269
|
form_reply.message.attributes.splits = true;
|
|
219
270
|
form_reply.message.attributes.markbot = true;
|
|
220
271
|
return form_reply.message;
|
|
221
|
-
//apiext.sendSupportMessageExt(form_reply.message, projectId, requestId, token, () => {
|
|
222
|
-
// if (log) {console.log("FORM Message sent.", );}
|
|
223
|
-
//});
|
|
224
|
-
//return;
|
|
225
272
|
}
|
|
226
273
|
else if (form_reply.end) {
|
|
227
|
-
//console.log("Form end.");
|
|
228
274
|
if (this.log) {
|
|
229
|
-
console.log("
|
|
230
|
-
console.log("
|
|
275
|
+
console.log("FORM end.", );
|
|
276
|
+
console.log("unlocking intent for request:", this.requestId);
|
|
277
|
+
}
|
|
278
|
+
this.unlockIntent(this.requestId);
|
|
279
|
+
if (lead) {
|
|
280
|
+
this.populatePrechatFormAndLead(this.requestId, lead._id);
|
|
231
281
|
}
|
|
232
|
-
this.unlockIntent(requestId);
|
|
233
|
-
this.populatePrechatFormAndLead(message);
|
|
234
282
|
}
|
|
235
283
|
else if (form_reply.canceled) {
|
|
236
284
|
console.log("Form canceled.");
|
|
237
|
-
if (this.log) {console.log("unlocking intent due to canceling, for request", requestId);}
|
|
238
|
-
this.unlockIntent(requestId);
|
|
285
|
+
if (this.log) {console.log("unlocking intent due to canceling, for request", this.requestId);}
|
|
286
|
+
this.unlockIntent(this.requestId);
|
|
239
287
|
if (this.log) {console.log("sending form 'cancel' reply...", form_reply.message)}
|
|
240
288
|
// reply with this message (ex. please enter your fullname)
|
|
241
289
|
if (!form_reply.message.attributes) {
|
|
@@ -244,27 +292,20 @@ class TiledeskChatbot {
|
|
|
244
292
|
form_reply.message.attributes.fillParams = true;
|
|
245
293
|
form_reply.message.attributes.splits = true;
|
|
246
294
|
return form_reply.message
|
|
247
|
-
//apiext.sendSupportMessageExt(form_reply.message, projectId, requestId, token, () => {
|
|
248
|
-
// if (log) {console.log("FORM Message sent.", );}
|
|
249
|
-
//});
|
|
250
|
-
//return;
|
|
251
295
|
}
|
|
252
|
-
//console.log("form_reply is", form_reply)
|
|
253
296
|
}
|
|
254
|
-
|
|
255
297
|
// FORM END
|
|
256
298
|
|
|
257
299
|
const context = {
|
|
258
300
|
payload: {
|
|
259
301
|
botId: botId,
|
|
260
|
-
bot: bot,
|
|
302
|
+
bot: this.bot,
|
|
261
303
|
message: message, // USER MESSAGE (JSON)
|
|
262
304
|
intent: answerObj
|
|
263
305
|
},
|
|
264
306
|
token: this.token
|
|
265
307
|
};
|
|
266
|
-
|
|
267
|
-
//console.log("the static_bot_answer...")
|
|
308
|
+
|
|
268
309
|
const static_bot_answer = { // static design of the chatbot reply
|
|
269
310
|
//type: answerObj.type,
|
|
270
311
|
text: answerObj.answer,
|
|
@@ -276,10 +317,6 @@ class TiledeskChatbot {
|
|
|
276
317
|
if (!static_bot_answer.attributes) {
|
|
277
318
|
static_bot_answer.attributes = {}
|
|
278
319
|
}
|
|
279
|
-
/*let attr = static_bot_answer.attributes;
|
|
280
|
-
if (!attr) {
|
|
281
|
-
attr = {};
|
|
282
|
-
}*/
|
|
283
320
|
var timestamp = Date.now();
|
|
284
321
|
static_bot_answer.attributes['clienttimestamp'] = timestamp;
|
|
285
322
|
if (answerObj && answerObj._id) {
|
|
@@ -289,19 +326,15 @@ class TiledeskChatbot {
|
|
|
289
326
|
// question_payload = clone of user's original message
|
|
290
327
|
let question_payload = Object.assign({}, message);
|
|
291
328
|
delete question_payload.request;
|
|
292
|
-
let clonedfaqs = faqs.slice();
|
|
293
|
-
if (clonedfaqs && clonedfaqs.length > 0) {
|
|
294
|
-
clonedfaqs = clonedfaqs.shift()
|
|
295
|
-
}
|
|
296
329
|
const intent_info = {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
330
|
+
intent_name: answerObj.intent_display_name,
|
|
331
|
+
is_fallback: false,
|
|
332
|
+
confidence: answerObj.score,
|
|
333
|
+
question_payload: question_payload,
|
|
334
|
+
botId: this.botId,
|
|
335
|
+
bot: this.bot
|
|
302
336
|
}
|
|
303
337
|
static_bot_answer.attributes.intent_info = intent_info;
|
|
304
|
-
|
|
305
338
|
static_bot_answer.attributes.directives = true;
|
|
306
339
|
static_bot_answer.attributes.splits = true;
|
|
307
340
|
static_bot_answer.attributes.markbot = true;
|
|
@@ -309,15 +342,8 @@ class TiledeskChatbot {
|
|
|
309
342
|
static_bot_answer.attributes.webhook = answerObj.webhook_enabled;
|
|
310
343
|
|
|
311
344
|
// exec webhook (only)
|
|
312
|
-
const bot_answer = await this.execPipeline(static_bot_answer, message, bot, context, this.token);
|
|
313
|
-
|
|
314
|
-
//bot_answer.text = await fillWithRequestParams(bot_answer.text, requestId); // move to "ext" pipeline
|
|
345
|
+
const bot_answer = await this.execPipeline(static_bot_answer, message, this.bot, context, this.token);
|
|
315
346
|
return bot_answer;
|
|
316
|
-
|
|
317
|
-
/*apiext.sendSupportMessageExt(bot_answer, projectId, requestId, token, () => {
|
|
318
|
-
if (log) {console.log("Message sent");}
|
|
319
|
-
});*/
|
|
320
|
-
|
|
321
347
|
}
|
|
322
348
|
|
|
323
349
|
async lockIntent(requestId, intent_name) {
|
|
@@ -325,7 +351,12 @@ class TiledeskChatbot {
|
|
|
325
351
|
}
|
|
326
352
|
|
|
327
353
|
async currentLockedIntent(requestId) {
|
|
328
|
-
|
|
354
|
+
if (this.tdcache) {
|
|
355
|
+
return await this.tdcache.get("tilebot:requests:" + requestId + ":locked");
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
return null;
|
|
359
|
+
}
|
|
329
360
|
}
|
|
330
361
|
|
|
331
362
|
async unlockIntent(requestId) {
|
|
@@ -371,32 +402,27 @@ class TiledeskChatbot {
|
|
|
371
402
|
return message;
|
|
372
403
|
}
|
|
373
404
|
|
|
374
|
-
async populatePrechatFormAndLead(
|
|
405
|
+
async populatePrechatFormAndLead(leadId, requestId) {
|
|
406
|
+
if (!leadId && !requestId) {
|
|
407
|
+
if (this.log) {console.log("(populatePrechatFormAndLead) !leadId && !requestId");}
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
375
410
|
const tdclient = new TiledeskClient({
|
|
376
411
|
projectId: this.projectId,
|
|
377
412
|
token: this.token,
|
|
378
413
|
APIURL: this.APIURL,
|
|
379
414
|
APIKEY: this.APIKEY
|
|
380
415
|
});
|
|
381
|
-
|
|
382
|
-
const leadId = message.request.lead._id;
|
|
383
|
-
const requestId = message.request.request_id;
|
|
384
|
-
|
|
385
416
|
const parameters_key = "tilebot:requests:" + requestId + ":parameters";
|
|
386
417
|
const all_parameters = await this.tdcache.hgetall(parameters_key);
|
|
387
|
-
if (all_parameters) {
|
|
388
|
-
//console.log("all_parameters['userEmail']", all_parameters['userEmail'])
|
|
389
|
-
//console.log("all_parameters['userFullname']", all_parameters['userFullname']);
|
|
418
|
+
if (all_parameters) {
|
|
390
419
|
tdclient.updateLeadEmailFullname(leadId, null, all_parameters['userFullname'], () => {
|
|
391
|
-
if (this.log) {console.log("
|
|
420
|
+
if (this.log) {console.log("Lead updated.")}
|
|
392
421
|
tdclient.updateRequestAttributes(requestId, {
|
|
393
422
|
preChatForm: all_parameters,
|
|
394
423
|
updated: Date.now
|
|
395
424
|
}, () => {
|
|
396
|
-
if (this.log) {console.log("
|
|
397
|
-
if (callback) {
|
|
398
|
-
callback();
|
|
399
|
-
}
|
|
425
|
+
if (this.log) {console.log("Prechat updated.");}
|
|
400
426
|
});
|
|
401
427
|
});
|
|
402
428
|
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
|
|
2
|
+
let axios = require('axios');
|
|
3
|
+
|
|
4
|
+
class TiledeskIntentsMachine {
|
|
5
|
+
|
|
6
|
+
constructor(config) {
|
|
7
|
+
if (!config.API_ENDPOINT) {
|
|
8
|
+
throw new Error("config.API_ENDPOINT is mandatory");
|
|
9
|
+
}
|
|
10
|
+
this.API_ENDPOINT = config.API_ENDPOINT;
|
|
11
|
+
this.log = config.log;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* intentsFinder Adapter
|
|
16
|
+
* @param {String} text
|
|
17
|
+
* @returns the matching intents' names array
|
|
18
|
+
*/
|
|
19
|
+
async decode(botId, text) {
|
|
20
|
+
return new Promise( (resolve, reject) => {
|
|
21
|
+
if (this.log) {console.log("NLP AI...");}
|
|
22
|
+
const url = `${this.API_ENDPOINT}/model/parse`;
|
|
23
|
+
if (this.log) {console.log("AI URL", url);}
|
|
24
|
+
const HTTPREQUEST = {
|
|
25
|
+
url: url,
|
|
26
|
+
headers: {
|
|
27
|
+
'Content-Type' : 'application/json'
|
|
28
|
+
},
|
|
29
|
+
json: {
|
|
30
|
+
"text": text,
|
|
31
|
+
"botId": botId
|
|
32
|
+
},
|
|
33
|
+
method: 'POST'
|
|
34
|
+
};
|
|
35
|
+
this.myrequest(
|
|
36
|
+
HTTPREQUEST,
|
|
37
|
+
function(err, resbody) {
|
|
38
|
+
if (err) {
|
|
39
|
+
console.error("error:", err)
|
|
40
|
+
reject(err);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
resolve(resbody);
|
|
44
|
+
}
|
|
45
|
+
}, false
|
|
46
|
+
);
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
myrequest(options, callback, log) {
|
|
51
|
+
if (this.log) {
|
|
52
|
+
console.log("API URL:", options.url);
|
|
53
|
+
console.log("** Options:", options);
|
|
54
|
+
}
|
|
55
|
+
axios(
|
|
56
|
+
{
|
|
57
|
+
url: options.url,
|
|
58
|
+
method: options.method,
|
|
59
|
+
data: options.json,
|
|
60
|
+
params: options.params,
|
|
61
|
+
headers: options.headers
|
|
62
|
+
})
|
|
63
|
+
.then((res) => {
|
|
64
|
+
if (this.log) {
|
|
65
|
+
console.log("Response for url:", options.url);
|
|
66
|
+
console.log("Response headers:\n", res.headers);
|
|
67
|
+
//console.log("******** Response for url:", res);
|
|
68
|
+
}
|
|
69
|
+
if (res && res.status == 200 && res.data) {
|
|
70
|
+
if (callback) {
|
|
71
|
+
callback(null, res.data);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
if (callback) {
|
|
76
|
+
callback(TiledeskClient.getErr({message: "Response status not 200"}, options, res), null, null);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
.catch( (error) => {
|
|
81
|
+
console.error("An error occurred:", error);
|
|
82
|
+
if (callback) {
|
|
83
|
+
callback(error, null, null);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
module.exports = { TiledeskIntentsMachine }
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
var Faq_kb = require("./faq_kb");
|
|
2
|
+
|
|
3
|
+
class FaqKbService {
|
|
4
|
+
|
|
5
|
+
async getAll(options) {
|
|
6
|
+
if (!options) {
|
|
7
|
+
options = {
|
|
8
|
+
public: true,
|
|
9
|
+
certified: true
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
console.log("(Service) GET ALL FAQ_KBs");
|
|
13
|
+
return new Promise((resolve, reject) => {
|
|
14
|
+
let query = {public: options.public, certified: options.certified};
|
|
15
|
+
Faq_kb.find(query).lean().exec( (err, bots) => {
|
|
16
|
+
if (err) {
|
|
17
|
+
reject(err);
|
|
18
|
+
}
|
|
19
|
+
resolve(bots);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
var faqKbService = new FaqKbService();
|
|
27
|
+
module.exports = faqKbService;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
var Faq = require("./faq");
|
|
2
|
+
var Faq_kb = require("./faq_kb");
|
|
3
|
+
|
|
4
|
+
class FaqService {
|
|
5
|
+
|
|
6
|
+
async getAll(faq_kb_id) {
|
|
7
|
+
console.log("(Service) GET ALL FAQ OF THE BOT ID (req.query): ", faq_kb_id);
|
|
8
|
+
return new Promise((resolve, reject) => {
|
|
9
|
+
let query = { id_faq_kb: faq_kb_id};
|
|
10
|
+
Faq.find(query).lean().exec( (err, faqs) => {
|
|
11
|
+
if (err) {
|
|
12
|
+
reject(err);
|
|
13
|
+
}
|
|
14
|
+
resolve(faqs);
|
|
15
|
+
});
|
|
16
|
+
})
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
var faqService = new FaqService();
|
|
22
|
+
module.exports = faqService;
|