Customer Satisfaction in OmniChannel Using NodeJS, Firebase, Google Cloud NLP API & Dialogflow

OmniChannel is not a buzzword any more. It means that you have a way to deal with customers who use different channels - Web, telephone, Voice BOT or CHAT BOT to reach out to you for support.

Customer Satisfaction in OmniChannel Using NodeJS, Firebase, Google Cloud NLP API & Dialogflow

OmniChannel is not a buzzword any more. If you haven't heard about it yet, then it is a cross channel strategy to engage with customers. Which effectively means that you have a way to deal with customers who use different channels - Web, telephone, Voice BOT or CHAT BOT to reach out to you for support. While it is fairly easy to build or implement a strategy across channels with the so many tools & technologies available, it becomes difficult to when users switch channels. User will switch channels when he or she feels that no one is addressing their concern. Someone needs to keep tab on these escalations as they pass through the channels. We need to identify and address such incidents before they are blown out of proportions. Imagine a customer who is very disappointed as he or she didn't get a response from any channels as a supervisor it shows up on your dashboard before blows out.

I decided a build a small Proof-Of-Concept involving some key channels. In place of Web interface, I built a small web page to capture customer query. For the sake of POC, I picked firebase as the DB to store all the analytics and JIRA for ticket creation & tracking.

Omnichannel Flow

Email

  • Set up a small RPA bot that reads a mail as it arrives
  • The text on the mail is analyzed using Google text analytics for sentiment
  • The text as well as sentiment score is sent to a central DB and stored against the customer id & Ticket id?

Messenger Chat

  • We can log all chat responses and conduct text analytics in real time using Google text analytics for sentiment
  • The text as well as sentiment score is sent to a central DB and stored against the customer id & Ticket id?

Voice BOT

  • We can use Alexa or Dialogflow (telephone integration module) to log all the spoken text/words over a conversation and do a real time analytics using Google API
  • The text as well as sentiment score is sent to a central DB and stored against the customer id & Ticket id?

Web Interface

  • We can set up a web page that pulls all the text & sentiment score against specific customer or ticket (as stored) and aggregates on the page
  • The basic aggregate score can be overall sentiment across all channels/text.

In the below code snippet, callmapi() function reads the email from the designated mailbox and then calls crtjiratkt function that creates a JIRA ticket and then getsent function is called which sends the text to Google Speech analytics to get the sentiment score.

const notifier = require('mail-notifier');
var Imap = require('imap'),
    inspect = require('util').inspect;
var fs = require('fs'), fileStream;
var cmd = require('node-cmd');
const request = require('request');
const firebase = require('firebase');
const admin = require('firebase-admin');


var imap1 = {
    user: "your-mailbox@gmail.com",
    password: "mailpassword",
    host: "imap.gmail.com",
    port: 993, // imap port
    tls: true,// use secure connection
    tlsOptions: { rejectUnauthorized: false }
};

var config = {
    apiKey: "your-key-goes-here",
    authDomain: "yourdb.firebaseapp.com",
    databaseURL: "https://yourdb.firebaseio.com",
    projectId: "your-projectid",
    storageBucket: "yourdb.appspot.com",
    messagingSenderId: "000000000"
  };
firebase.initializeApp(config);

admin.initializeApp({
    credential: admin.credential.cert({
      projectId: 'your-projectid',
      clientEmail: 'firebase-adminsdk-0000@your-projectid.iam.gserviceaccount.com',
      privateKey: '-----BEGIN PRIVATE KEY----------END PRIVATE KEY-----\n'
    }),
    databaseURL: 'https://your-projectid.firebaseio.com'
  });

function callmapi() {
    notifier(imap1)
    .on('mail', mail => {
        console.log('from : ' + mail.from[0].address);
        console.log('subject : ' + mail.subject);
        //console.log(mail);
        crtjiratkt(mail.text, function(key){
        getsent(mail.text, function(score){ 
            console.log(mail.text + " = " + score)
            admin.database().ref('scores/').push({
                channel: 'email',
                cname: mail.from[0].name,
                cscore: score,
                ctext: mail.text,
                cmail: mail.from[0].address,
                tdesc: mail.subject,
                ticket: key
              }, function(error) {
                  console.log(error);
              });
        })
      })
    })
    .on('error', err => {
        console.log(err);
    })
    .on('end', () => n.start())
    .start();

function getsent (tline, callback) {
    let options1 = { method: 'POST',
    url: 'https://language.googleapis.com/v1beta2/documents:analyzeSentiment?key=your-key-goes-here',
    headers:
        {   'cache-control': 'no-cache',
            'content-type': 'application/json' },
    body:
        {
          'document':{
          'type':'PLAIN_TEXT',
          'content': tline
        }
      },
    json: true };

    request(options1, function (error, response, body) {
    //console.log(response);
    if (body.error != 'undefined') {
      callback(body.documentSentiment.score);
    } else {
      callback(0);
    }


  });
}

function crtjiratkt(tline, callback) {
  var options = { method: 'POST',
  url: 'https://test.atlassian.net/rest/api/2/issue/',
  headers: 
   { 'Postman-Token': 'a4536d1b-ff9c-4de7-a9c7-6a30417f61a2',
     'Cache-Control': 'no-cache',
     Authorization: 'Basic xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
     'Content-Type': 'application/json' },
  body: 
   { fields: 
      { project: { key: 'RPA' },
        summary: tline,
        description: 'Instance Name : DevInstanceforTesting\nImages              : Cirros\nFlavor               : m1.small\nRequester         : test@test.com',
        issuetype: { name: 'Task', Assignee: 'BOT' } } },
  json: true };

  request(options, function (error, response, body) {
    if (error) throw new Error(error);
    if (body.error != 'undefined') {
      callback(body.key);
      console.log(body);
    } else {
      callback(0);
    }
  });  
}

In the below code snippet which is inserted in the dialogflow 'Webhook', intercepts the chat responses in exports.chatbot which in turn polled to Google Speech analytics for a sentiment score (getsent).

const request = require('request');
const admin = require('firebase-admin');

admin.initializeApp({
    credential: admin.credential.cert({
      projectId: 'your-projectid',
      clientEmail: 'firebase-adminsdk-0000@your-projectid.iam.gserviceaccount.com',
      privateKey: '-----BEGIN PRIVATE KEY----------END PRIVATE KEY-----\n'
    }),
    databaseURL: 'https://your-projectid.firebaseio.com'
  });


exports.chatbot = (req, res) => {
  /*let message = req.query.message || req.body.message || 'Hello World!';
  res.status(200).send(message);*/
  //console.log(req.body.queryResult.intent);
  if (req.body.queryResult.intent.displayName == "Default Welcome Intent - custom - yes - custom - custom") {
     getsent(req.body.queryResult.queryText, function(score){
             admin.database().ref('scores/').push({
                channel: 'chat',
                cname: 'prakash',
                cscore: score,
                ctext: req.body.queryResult.queryText,
                cmail: 'test mail',
                tdesc: 'test subject',
                ticket: 'abc234'
              }, function(error) {
                  console.log(error);
              });
         console.log(req.body.queryResult.queryText + ":" + score);
     })
  }
  else if (req.body.queryResult.intent.displayName == "Default Welcome Intent - custom - yes - custom") {
    console.log("ticket no: " + req.body.queryResult.queryText);
  }
};

function getsent (tline, callback) {
    let options1 = { method: 'POST',
    url: 'https://language.googleapis.com/v1beta2/documents:analyzeSentiment?key=AIzaSyCh-H9fxZXaR43dQQgg4FIwLWpAX2L5C7E',
    headers:
        {   'cache-control': 'no-cache',
            'content-type': 'application/json' },
    body:
        {
          'document':{
          'type':'PLAIN_TEXT',
          'content': tline
        }
      },
    json: true };

    request(options1, function (error, response, body) {
    //console.log(response);
    if (body.error != 'undefined') {
      callback(body.documentSentiment.score);
    } else {
      callback(0);
    }


  });
}

https://cloud.google.com/natural-language/

I have interests in Alexa, Angular / AngularJS, NodeJS, Ethereum Blockchain, ChatBOTS and many more. Read more at http://www.dudistan.com/