-
Notifications
You must be signed in to change notification settings - Fork 30
/
index.js
216 lines (209 loc) · 7.85 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
const express = require('express');
const bodyParser = require('body-parser');
const { TiledeskChatbotClient } = require('@tiledesk/tiledesk-chatbot-client');
const { TiledeskChatbotUtil } = require('@tiledesk/tiledesk-chatbot-util')
const { TiledeskClient } = require('@tiledesk/tiledesk-client');
const dialogflow = require('dialogflow');
const app = express();
app.use(bodyParser.json());
// this function is referenced by all the tutorials and uses
// Dialogflow client APIs to make agents calls
async function runDialogflowQuery(text, sessionId, language_code, credentials) {
const project_id = credentials.project_id
const sessionClient = new dialogflow.SessionsClient({'credentials':credentials});
const sessionPath = sessionClient.sessionPath(project_id, sessionId);
var request;
request = {
session: sessionPath,
queryInput: {
text: {
text: text,
languageCode: language_code,
}
}
};
const responses = await sessionClient.detectIntent(request);
const result = responses[0].queryResult;
return result;
}
// Tutorial 1 - Basic Dialogflow extarnal endpoint
app.post("/bot/:botid", (req, res) => {
// for cloud apis initialize like the this:
// const tdclient = new TiledeskChatbotClient({request: req})
const cbclient = new TiledeskChatbotClient(
{
request: req,
response: res,
APIKEY: '____APIKEY____'
});
// for on-prem installations specify your endpoint like this:
// const cbclient = new TiledeskChatbotClient(
// {
// request: req,
// response: res,
// APIKEY: '____APIKEY____',
// APIURL: 'YOUR ON-PREM API ENDPOINT'
// });
// const tdclient = new TiledeskChatbotClient({request: req, APIURL: 'YOUR API ENDPOINT'});
const botid = req.params.botid;
const conversation = cbclient.supportRequest
// immediately reply back
res.status(200).send({"success":true});
// reply messages are sent asynchronously
const dialogflow_session_id = conversation.request_id
const lang = 'en-EN' // lang must be the same of the Dialogflow Agent
const credentials = JSON.parse(process.env[botid])
runDialogflowQuery(cbclient.text, dialogflow_session_id, lang, credentials)
.then(function(result) {
console.log("query result: ", JSON.stringify(result))
console.log("is fallback:", result.intent.isFallback)
console.log("confidence:", result.intentDetectionConfidence)
// intentDetectionConfidence
if(res.statusCode === 200) {
const reply_text = result['fulfillmentText']
var msg = {
"text": reply_text
}
cbclient.tiledeskClient.sendMessage(msg, function (err) {
console.log("Message sent.");
})
}
})
.catch(function(err) {
console.log('Error: ', err);
})
})
// Tutorial 2 - Advanced tutorial using 'micro language' to render buttons or images
app.post("/microlang-bot/:botid", (req, res) => {
const tdclient = new TiledeskChatbotClient({APIKEY:'__APIKEY__', request: req});
const botid = req.params.botid;
console.log("botid:", botid)
const conversation = tdclient.supportRequest
// immediately reply back
res.status(200).send({"success":true});
// reply messages are sent asynchronously
const dialogflow_session_id = conversation.request_id
const lang = 'en-EN' // lang must be the same of the Dialogflow Agent
console.log("loading credentials...") //, process.env[botid])
const credentials = JSON.parse(process.env[botid])
runDialogflowQuery(tdclient.text, dialogflow_session_id, lang, credentials)
.then(function(result) {
console.log("query result: ", JSON.stringify(result))
console.log("is fallback:", result.intent.isFallback)
console.log("confidence:", result.intentDetectionConfidence)
// intentDetectionConfidence
if(res.statusCode === 200) {
const reply_text = result['fulfillmentText'];
const parsed_reply = TiledeskChatbotUtil.parseReply(reply_text);
var msg = parsed_reply.message;
// NOTE: you can also use parts of the parsed message, like this
// var reply = {
// "text": msg.text,
// "type": msg.type,
// "attributes": msg.attributes,
// "metadata": msg.metadata,
// "senderFullname": tdclient.botName
// }
tdclient.sendMessage(msg, function (err) {
console.log("Message", msg, "sent.");
})
}
})
.catch(function(err) {
console.log('Error: ', err);
})
})
// Tutorial 3 - Automatic human handhoff based on fallback intent
// In this tutorial the human handoff happens after some consective
// missed replies (fallback)
var consecutive_fallback_count = {};
const MAX_FALLBACKS = 4;
app.post("/bot-fallback-handoff/:botid", (req, res) => {
const tdclient = new TiledeskChatbotClient(
{request: req,
APIURL: 'https://tiledesk-server-pre.herokuapp.com'
});
console.log("tdclient", tdclient)
const botid = req.params.botid;
const supportRequest = tdclient.supportRequest
// immediately reply back
res.status(200).send({"success":true});
// reply messages are sent asynchronously
const dialogflow_session_id = supportRequest.request_id
const lang = 'en-EN' // lang must be the same of the Dialogflow Agent
const credentials = JSON.parse(process.env[botid])
runDialogflowQuery(tdclient.text, dialogflow_session_id, lang, credentials)
.then(function(result) {
if (!consecutive_fallback_count[dialogflow_session_id]) {
// init consecutive fallback count for this conversation
consecutive_fallback_count[dialogflow_session_id] = 0
}
if (result.intent.isFallback) {
consecutive_fallback_count[dialogflow_session_id]++
console.log("fallback of", dialogflow_session_id, "is", consecutive_fallback_count[dialogflow_session_id])
}
else {
// reset fallback on every positive hit.
// here you can also evaluate result.intentDetectionConfidence
// and consider it as a fallback if under some threshold value
consecutive_fallback_count[dialogflow_session_id] = 0
}
if(res.statusCode === 200) {
let msgs = [];
if (consecutive_fallback_count[dialogflow_session_id] == MAX_FALLBACKS) {
consecutive_fallback_count[dialogflow_session_id] = 0
msgs.push({
"text": "I really don't understand your questions, putting you in touch with an operator..."
})
msgs.push({
"text": "\\agent"
// "attributes" : {subtype: "info"} // this message is hidden in the widget
})
}
else {
msgs.push({
"text": result['fulfillmentText']
})
}
msgs.forEach( m => {
tdclient.sendMessage(m, function (err) {
console.log("Message", m.text, "sent.");
})
})
}
})
.catch(function(err) {
console.log('Error: ', err);
})
})
// Tutorial 4 - Ask user for optional Agent handoff
// No code is needed for explicit human handoff!
// Tutorial 5 - Webhook for Bot-to-Agent handoff message based on opening hours
app.post('/dfwebhook/:project_id', (req, res) => {
const fulfillmentText = req.body.queryResult.fulfillmentText
console.log("fulfillmentText:", fulfillmentText)
const languageCode = req.body.queryResult.languageCode
console.log("languageCode:", languageCode)
// replace the following with your prject id
const project_id = req.params.project_id
const intent = req.body.queryResult.intent.displayName.toUpperCase()
if (intent === "TALK TO AGENT") {
if (resbody && resbody.token) {
const tdclient = new TiledeskClient()
tdclient.openNow(function(isopen) {
var df_res = {}
if (isopen) {
df_res['fulfillmentText'] = "We are open! Switching to agent\\agent"
}
else {
df_res['fulfillmentText'] = "I'm sorry but we are closed right now."
}
res.status(200).send(JSON.stringify(df_res));
});
}
}
});
var port = process.env.PORT || 3001;
app.listen(port, () => {
console.log('server started');
});