cx/spark/server.js (171 lines of code) (raw):
const express = require('express');
const request = require('request');
const app = express();
app.use(express.json());
// Uncomment and insert your values here
// const sparkAccessToken = "1234567898-ABCdfghTtaD8dfghdfgh-45sdf65467M";
// const targetUrl = 'https://example.com';
// const projectId = 'my-project';
// const locationId = 'global';
// const agentId = 'my-agent';
// const languageCode = 'en';
// Imports the Google Cloud Some API library
const {SessionsClient} = require('@google-cloud/dialogflow-cx');
/**
* Example for regional endpoint:
* const locationId = 'us-central1'
* const client = new SessionsClient({apiEndpoint: 'us-central1-dialogflow.googleapis.com'})
*/
const client = new SessionsClient({apiEndpoint: locationId + '-dialogflow.googleapis.com'});
// Upon start a webhook is registered with spark
// Upon closure the webhook is removed from spark
const listener = app.listen(process.env.PORT, async function() {
await init();
console.log('Your Spark integration server is listening on port ' +
listener.address().port);
});
app.post('/', async function(req, res) {
const message = await retrieveMessage(req.body.data.id);
if (message == null) {
res.sendStatus(200);
}
const dialogflowResponse = await detectIntentText(message);
const sparkMessage = detectIntentToSparkMessage(dialogflowResponse, message);
sendMessage(sparkMessage);
res.sendStatus(200);
});
process.on('SIGTERM', () => {
listener.close(async ()=>{
console.log('Closing http server.');
await deleteWebhooksByUrl(targetUrl);
process.exit(0);
});
});
async function init() {
await deleteWebhooksByUrl(targetUrl);
registerWebhook();
}
// Converts Spark message to a detectIntent request.
function sparkToDetectIntent(message, sessionPath) {
const request = {
session: sessionPath,
queryInput: {
text: {
text: message.text,
},
languageCode,
},
};
return request;
}
// Converts detectIntent response to a Spark text message.
function detectIntentToSparkMessage(response, message) {
agentResponse = '';
for (const message of response.queryResult.responseMessages) {
if (message.text) {
agentResponse += `${message.text.text}\n`;
};
};
if (agentResponse.length != '') {
const request = {
toPersonEmail: message.email,
text: agentResponse,
};
return request;
};
};
/**
* This function calls Dialogflow CX API to retrieve the response
* https://cloud.google.com/dialogflow/cx/docs/quick/api
*/
async function detectIntentText(message) {
const sessionId = message.payload.personId;
const sessionPath = client.projectLocationAgentSessionPath(
projectId,
locationId,
agentId,
sessionId,
);
console.info(sessionPath);
const request = sparkToDetectIntent(message, sessionPath);
const [response] = await client.detectIntent(request);
return response;
}
function sendMessage(message) {
request.post('https://api.ciscospark.com/v1/messages', {
auth: {
bearer: sparkAccessToken,
},
json: message,
}, (err, resp, body) => {
if (err) {
console.error('Failed to send message :' + err);
}
});
}
function registerWebhook() {
request.post('https://api.ciscospark.com/v1/webhooks', {
auth: {
bearer: sparkAccessToken,
},
json: {
'name': 'test',
'targetUrl': targetUrl,
'resource': 'messages',
'event': 'created',
},
}, (err, resp, body) => {
if (err) {
console.error('Failed to create Webhook :' + err);
}
});
}
async function deleteWebhooksByUrl(targetUrl) {
const webhooks = await listWebhooks(targetUrl);
for (webhook of webhooks) {
if (webhook.id) {
await deleteWebhookById(webhook.id);
}
}
}
function deleteWebhookById(webhookId) {
return new Promise((resolve, reject) =>{
request.delete(
'https://api.ciscospark.com/v1/webhooks/' +
webhookId, {
auth: {
bearer: sparkAccessToken,
},
}, (err, resp, body) => {
if (err) {
console.error('Failed to delete webhook :' + err);
reject(err);
}
resolve();
});
});
}
function listWebhooks(targetUrl) {
return new Promise((resolve, reject) =>{
request.get('https://api.ciscospark.com/v1/webhooks?max=100', {
auth: {
bearer: sparkAccessToken,
},
}, (err, resp, body) => {
if (err) {
console.error('Failed to check webhooks :' + err);
reject(err);
}
let webhooks = JSON.parse(resp.body).items;
if (Array.isArray(webhooks)) {
webhooks = webhooks.filter((value, index, arr)=> {
return value.targetUrl===targetUrl;
});
resolve(webhooks);
}
resolve([]);
});
});
}
function retrieveMessage(messageId) {
return new Promise((resolve, reject) =>{
request.get('https://api.ciscospark.com/v1/messages/' + messageId, {
auth: {
bearer: sparkAccessToken,
},
}, (err, resp, body) => {
if (err) {
console.error('Failed to retrieve message :' + err);
reject();
}
// checks to make sure the message is not from itself
if (!((JSON.parse(resp.body).personEmail).includes('webex.bot'))) {
const personEmail = JSON.parse(resp.body).personEmail;
const messageText= JSON.parse(resp.body).text;
const payload = JSON.parse(resp.body);
resolve({text: messageText, email: personEmail, payload: payload});
} else {
resolve(null);
}
});
});
}
module.exports = {sparkToDetectIntent, detectIntentToSparkMessage};