Genesys Cloud Third Party ChatBot integration
With the introduction of the WebChat APIs in Genesys Cloud it is now possible to integrate your external ChatBot with the Genesys platform offering an interesting user experience for users. By taking advantage of the WebChat APIs you can, for example, develop your own ChatBot that welcomes users with the possibility of switching between ChatBot and real Agent on Genesys Cloud, also making the history of the conversation that the user had with the BOT available to the agent.
Here we will experiment with this type of integration by creating our own ChatBot with the help of the Microsoft Bot Framework Emulator and Javascript code available online. Obviously we will need access to the Genesys Cloud platform, configuring a queue with a registered agent who will interact via chat with the user once this has been transferred from our ChatBot to the queue.
The following figure shows (in a very simplified way) the architectural scheme.
What we need
To create a simple test case we need:
- A valid login to Genesys Cloud, with WebCaht APIs enabled
- A queue to transfer the contact to
- Microsoft Bot Framework Emulator
- Microsoft Bot Framework SDK
- Node.js
- The example javascript code for the ChatBot
Genesys Cloud Configuration
First, let’s make sure we have everything set up on the Genesys Cloud platform, with API access enabled, a queue and an agent available on the queue. In my test case I have the ChatAssistant queue configured and my User in the queue ready to accept a contact.
Microsoft Bot Framework Emulator
With the Microsoft Bot Framework SDK we can build our ChatBot and using the Bot Framework Emulator we can test it locally on our laptop.
I used the SDK to build a bot in JavaScript following the Microsoft documentation. I set up the environment by installing the various modules for Node.js and then created an echo bot.
PS C:\temp\simplebot> yo botbuilder
Welcome to the Microsoft Bot Builder generator v4.20.0.
Detailed documentation can be found at https://aka.ms/botbuilder-generator
? What's the name of your bot? my-chat-bot
? What will your bot do? Demonstrate the core capabilities of the Microsoft Bot Framework
? What programming language do you want to use? JavaScript
? Which template would you like to start with? Echo Bot - https://aka.ms/bot-template-echo
? Looking good. Shall I go ahead and create your new bot? Yes
simplebot
my-chat-bot
Your bot should be in a directory named my-chat-bot
I'll automatically create this folder.
create my-chat-bot\package.json
create my-chat-bot\.gitignore
create my-chat-bot\.env
create my-chat-bot\.eslintrc.js
create my-chat-bot\README.md
create my-chat-bot\deploymentTemplates\deployUseExistResourceGroup\parameters-for-template-AzureBot-with-rg.json
create my-chat-bot\deploymentTemplates\deployUseExistResourceGroup\parameters-for-template-BotApp-with-rg.json
create my-chat-bot\deploymentTemplates\deployUseExistResourceGroup\readme.md
create my-chat-bot\deploymentTemplates\deployUseExistResourceGroup\template-AzureBot-with-rg.json
create my-chat-bot\deploymentTemplates\deployUseExistResourceGroup\template-BotApp-with-rg.json
create my-chat-bot\deploymentTemplates\deployWithNewResourceGroup\parameters-for-template-AzureBot-new-rg.json
create my-chat-bot\deploymentTemplates\deployWithNewResourceGroup\parameters-for-template-BotApp-new-rg.json
create my-chat-bot\deploymentTemplates\deployWithNewResourceGroup\readme.md
create my-chat-bot\deploymentTemplates\deployWithNewResourceGroup\template-AzureBot-new-rg.json
create my-chat-bot\deploymentTemplates\deployWithNewResourceGroup\template-BotApp-new-rg.json
create my-chat-bot\index.js
create my-chat-bot\bot.js
I'm all done. Running npm install for you to install the required dependencies. If this fails, try running the command yourself.
Well, now we have a ready-to-use echo bot that we can launch on the emulator, but we’re actually interested in modifying it to integrate with Genesys Cloud using the WebChat Guest API. The source code to integrate the bot with Genesys is available for free on BitBucket repository and for our purpose we just need to take the files *** bot.js***, index.js and purecloud-chat.js, re-adapting them a little. Let’s see how.
In the bot.js file we remove all references to Watson.
We also edit the index.js file like this.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
const path = require('path');
const dotenv = require('dotenv');
// Import required bot configuration.
const ENV_FILE = path.join(__dirname, '.env');
dotenv.config({ path: ENV_FILE });
const restify = require('restify');
// Import required bot services.
// See https://aka.ms/bot-services to learn more about the different parts of a bot.
const {
CloudAdapter,
ConversationState,
UserState,
MemoryStorage,
ConfigurationServiceClientCredentialFactory,
createBotFrameworkAuthenticationFromConfiguration
} = require('botbuilder');
// This bot's main dialog.
const { EchoBot } = require('./bot');
// Create HTTP server
const server = restify.createServer();
server.use(restify.plugins.bodyParser());
server.listen(process.env.port || process.env.PORT || 3978, () => {
console.log(`\n${ server.name } listening to ${ server.url }`);
console.log('\nGet Bot Framework Emulator: https://aka.ms/botframework-emulator');
console.log('\nTo talk to your bot, open the emulator select "Open Bot"');
});
const credentialsFactory = new ConfigurationServiceClientCredentialFactory({
MicrosoftAppId: process.env.MicrosoftAppId,
MicrosoftAppPassword: process.env.MicrosoftAppPassword,
MicrosoftAppType: process.env.MicrosoftAppType,
MicrosoftAppTenantId: process.env.MicrosoftAppTenantId
});
const botFrameworkAuthentication = createBotFrameworkAuthenticationFromConfiguration(null, credentialsFactory);
// Create adapter.
// See https://aka.ms/about-bot-adapter to learn more about adapters.
const adapter = new CloudAdapter(botFrameworkAuthentication);
// Catch-all for errors.
const onTurnErrorHandler = async (context, error) => {
// This check writes out errors to console log .vs. app insights.
// NOTE: In production environment, you should consider logging this to Azure
// application insights.
console.error(`\n [onTurnError] unhandled error: ${ error }`);
// Clear out state
await conversationState.clear(context);
// Save state changes.
await conversationState.saveChanges(context);
// Send a trace activity, which will be displayed in Bot Framework Emulator
await context.sendTraceActivity(
'OnTurnError Trace',
`${ error }`,
'https://www.botframework.com/schemas/error',
'TurnError'
);
// Send a message to the user
await context.sendActivity('The bot encountered an error or bug.');
await context.sendActivity('To continue to run this bot, please fix the bot source code.');
};
// Set the onTurnError for the singleton CloudAdapter.
adapter.onTurnError = onTurnErrorHandler;
// Define a state store for your bot. See https://aka.ms/about-bot-state to learn more about using MemoryStorage.
// A bot requires a state store to persist the dialog and user state between messages.
let conversationState;
let userState;
// For local development, in-memory storage is used.
// CAUTION: The Memory Storage used here is for local bot debugging only. When the bot
// is restarted, anything stored in memory will be gone.
const memoryStorage = new MemoryStorage();
conversationState = new ConversationState(memoryStorage);
userState = new UserState(memoryStorage);
// Create the main dialog.
const myBot = new EchoBot(conversationState, userState);
// Listen for incoming requests.
server.post('/api/messages', async (req, res) => {
// Route received a request to adapter for processing
await adapter.process(req, res, (context) => myBot.onTurn(adapter, context));
});
Let’s modify the purecloud-chat.js file, inserting the data required for the Genesys integration.
const organizationId = ""; // organizationId
const deploymentId = ""; // deploymentId from PureCloud org definition
const queueName = "ChatAssistant"; // queueName where Chat will be routed
const env = ''; // PureCloud environment (mypurecloud.com / mypurecloud.ie / mypurecloud.de)
- organizationId is the identifier of the Genesys Cloud subscription
- deploymentId is the Deployment Key of the Contact Center Integration Widget
- queueName is the queue to transfer the chat to
- env is the PureCloud region on which your subscription is active (in my case mypurecloud.de)
In the same file we change the startChat function like this.
function startChat(_adapter, _context, _conversationState) {
let myBody = {
"organizationId": organizationId,
"deploymentId": deploymentId,
"routingTarget": {
"targetType": "QUEUE",
"targetAddress": queueName
},
"memberInfo": {
"displayName": "Steve Jobs",
"profileImageUrl": "https://banner2.kisspng.com/20181201/xes/kisspng-call-centre-customer-service-clip-art-computer-ico-homepage-vacuum-5c02fa4fe698b1.3075985415436990239445.jpg",
"customFields": {
"firstName": "Steve",
"lastName": "Jobs"
}
}
};
let options = {
url: 'https://api.' + env + '/api/v2/webchat/guest/conversations',
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(myBody)
};
request(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
var info = JSON.parse(body);
webSocket = new WebSocket(info.eventStreamUri);
webSocket.on('open', function () {
//Connection is open. Start the subscription(s)
console.log('WebSocket opened');
});
webSocket.on('message', function (message) {
var data = JSON.parse(message);
// we do not care about channel.metadata informations. Ignore them
if (data.topicName == 'channel.metadata') {
return;
}
try {
if (!_conversationState.purecloud || !_conversationState.purecloud.agentId) {
// do only once after chat session initated. Save participant data and other required informations
_conversationState.purecloud = {};
_conversationState.purecloud.conversationId = data.eventBody.conversation.id;
if (data.eventBody.hasOwnProperty('member')) {
_conversationState.purecloud.agentId = data.eventBody.member.id;
console.log('agentId', _conversationState.purecloud.agentId);
}
_conversationState.purecloud.botConversationId = _context.conversation.id;
_conversationState.purecloud.chatId = info.jwt;
console.log('conversationId', _conversationState.purecloud.conversationId);
// Send history
sendMessageToPureCloud(buildHistory(_conversationState.history), _conversationState.purecloud);
}
// new message from purecloud received
if (data.metadata.type == 'message') {
// We do not want to display message from the bot again (echo)
// display only messages where senderId is different than current botId
if (data.eventBody.sender.id != _conversationState.purecloud.agentId) {
console.log('msg from pc', data.eventBody.body);
sendMessageToBot(_adapter, _context, data.eventBody.body);
}
// member-change event (detect DISCONNECT event)
} else if (data.metadata.type == 'member-change' && data.eventBody.member.id == _conversationState.purecloud.agentId && data.eventBody.member.state == 'DISCONNECTED') {
console.log('# chat disconnected, clear bot session');
_conversationState.purecloud = undefined;
sendMessageToBot(_adapter, _context, '[purecloud disconnected]');
}
} catch (error) {
console.log(error);
}
});
}
});
};
Finally we change the sendMessageToBot function like this.
// send message to the bot
async function sendMessageToBot(_adapter, _context, _msg) {
await _adapter.continueConversationAsync( "fakeid", _context, async (proactiveTurnContext) => {
await proactiveTurnContext.sendActivity(_msg);
});
}
Testing the scenario
At this point we can test the local ChatBot and the integration with Genesys Cloud. First let’s launch the new ChatBot.
PS C:\temp\simplebot\my-chat-bot> npm start
> my-chat-bot@1.0.0 start
> node ./index.js
(node:11544) [DEP0111] DeprecationWarning: Access to process.binding('http_parser') is deprecated.
(Use `node --trace-deprecation ...` to show where the warning was created)
restify listening to http://[::]:3978
Get Bot Framework Emulator: https://aka.ms/botframework-emulator
To talk to your bot, open the emulator select "Open Bot"
Start the Bot Emulator and connect it to our ChatBot, selecting Open Bot, enter the URL of the local Bot http://localhost:3978/api/messages and then click on ** Connect**.
Now we are connected with the local ChatBot and can interact with it.
Following the flow of the ChatBot, by typing “transfer” the conversation is transferred to the Genesys queue, and when the agent accepts the contact, he will receive the entire history of the chat conversation between the user and the ChatBot, and this is exactly what happens as you can see in the following images.
If you want to have fun with the ChatBot you can modify the dialogue flow in the bot.js file.