ChatBots to Automate Business

Way back in 1986 when I was 10 years old, and the proud owner of an Amstrad CPC-464 I found a book in the local library on a computer program with listings called 'Eliza'. It was an attempt to simulate a natural conversation with a computer. Whilst interesting, it definitely had its limitations, and whilst clever, it wasn't intelligent because it couldn't learn or adapt. It simply scanned the user input for keywords, potentially prioritising them, and constructing an output based on that input.

There is now a rapid transformation in the way computers interact with people, and more and more it is done with voice and natural language. With software integrations to chatbots, it's possible to build powerful virtual assistants that can perform complex operations.

Building a chatbot

The first step is to choose a chatbot engine. The engine will do all of the hard work of parsing input, and understanding meaning and context. Also the engine will typically have a graphical interface to allow bots to be built without programming language (and ideally they wouldn't be built by programmers!).

Popular Chatbot Engines
  1. IBM Watson
  2. Microsoft Bot Framework
  3. Facebook Messenger Platform

In this case, let's use IBM Watson, but before we do it's worth knowing some of the terminologies.

"Intent": An Intent is what the user is trying to do.
"Entity": An Entity refers to something physical.
"Dialog": A response to the user based on recognised Intents and Entities.
"Context": A memory of what we are talking about.
"Variable": A way of holding and referring to information supplied by the user.

It's also important to know what the purpose of your chatbot is going to be before you start to build it. It's not going to be possible to build something that you can have a conversation with about anything, but it is certainly possible to make something that provides specialist help and information.

For this example, I am going to create a chatbot called Marvin that provides help and information to our customers with the aim that finds out what a customer is looking for, and provides them with high-level information and puts them in contact with the right person.

  1. Go to the IBM Watson Assistant IBM Watson Assistant page.
  2. Press 'Create' at the bottom of the page.
  3. Press the 'Launch Tool' button.
  4. Create a Workspace

I've already created one called Marvin, but IBM have provided an excellent example called "Customer Service Sample".

There is a 'try it out' button in the top right of the page which opens a window that allows you to test the chatbot, and to retrain it if its responses are not quite right.

I created an number of Intents, that I thought people who are enquiring about our business would use.

In the case of careers, I have provided Watson with the following examples of what I think someone enquiring about a career with us might ask:

And configured the Dialog to prompt the user to send their CV when it detects a question about careers:

Now if we provide it with input it's not seen before, but relating to careers, such as "What vacancies do you have at your company?"

We can see that it thinks I am asking about the company. So within this window i'll retrain it to recognise it as a career enquiry.

And after the training has completed:

Now that we have built the chat bot, it remains to interface it with the outside world, so there is some technical work to do.

Setting up a chatbot server

As a starting point I have a fresh Ubuntu server with Python 3 installed. We want to make use of the various Watson API services, so we install:

pip install --upgrade watson-developer-cloud  

The following simple Python script will send the message 'Hello' to the Marvin chatbot, and display the JSON response.

from watson_developer_cloud import AssistantV1  
import json  
import os

# constants
WORKSPACE_ID = 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'

assistant = AssistantV1(  
    username='XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX',
    password='XXXXXXXXXXXX',
    version='2017-04-21')

assistant.set_http_config({'timeout': 100})

def processInput(input):  
    response = assistant.message(workspace_id=WORKSPACE_ID, input={'text': input})
    print(json.dumps(response, indent=2))


processInput('hello')  

After running it in the command line, the JSON response is:

  "entities": [],
  "intents": [
    {
      "confidence": 1,
      "intent": "Hello"
    }
  ],
  "output": {
    "text": [
      "Hi, i'm Marvin, what's your name?"
    ],
    "log_messages": [],
    "nodes_visited": [
      "node_1_xxxxxxxxxxxxxxxx",
      "handler_10_xxxxxxxxxxxxxxxx",
      "slot_8_xxxxxxxxxxxxxxxx"
    ]
  },
  "context": {
    "conversation_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "system": {
      "dialog_turn_counter": 1,
      "dialog_stack": [
        {
          "state": "in_progress",
          "dialog_node": "slot_8_xxxxxxxxxxxxxxx"
        }
      ],
      "_node_output_map": {},
      "dialog_request_counter": 1
    }
  },
  "input": {
    "text": "hello"
  }
}

Whilst I'm sure that all of this information is useful, right now I am only interested in the output. So I'm going to change the processInput function to just return the text response.

def processInput(input):  
    response = assistant.message(workspace_id=WORKSPACE_ID, input={'text': input})
    return response['output']['text']

So nearly there, the final step is to integrate this with a slackbot.
The first step here is to configure a Slackbot within Slack. That is done here.

Make a note of the Bot User OAuth Access Token. We will need that later.

Now we have a Slackbot, the next job is to write some code that links it to our Watson chatbot.

The official slackclient API helper library built by Slack can be used to send and receive messages from a Slack channel. Install the slackclient library with the pip command:

pip install slackclient  

The following Python script communicates with the chatbot via the Slack RTM (real-time messaging) API.

import os  
import time  
import re  
from slackclient import SlackClient


# instantiate Slack client
slack_client = SlackClient(os.environ.get('SLACK_BOT_TOKEN'))  
# starterbot's user ID in Slack: value is assigned after the bot starts up
starterbot_id = None

# constants
RTM_READ_DELAY = 1 # 1 second delay between reading from RTM  
EXAMPLE_COMMAND = "do"  
MENTION_REGEX = "^<@(|[WU].+?)>(.*)"

def parse_bot_commands(slack_events):  
    """
        Parses a list of events coming from the Slack RTM API to find bot commands.
        If a bot command is found, this function returns a tuple of command and channel.
        If its not found, then this function returns None, None.
    """
    for event in slack_events:
        if event["type"] == "message" and not "subtype" in event:
            user_id, message = parse_direct_mention(event["text"])
            if user_id == starterbot_id:
                return message, event["channel"]
    return None, None

def parse_direct_mention(message_text):  
    """
        Finds a direct mention (a mention that is at the beginning) in message text
        and returns the user ID which was mentioned. If there is no direct mention, returns None
    """
    matches = re.search(MENTION_REGEX, message_text)
    # the first group contains the username, the second group contains the remaining message
    return (matches.group(1), matches.group(2).strip()) if matches else (None, None)

def handle_command(command, channel):  
    """
        Executes bot command if the command is known
    """
    # Default response is help text for the user
    default_response = "Not sure what you mean. Try *{}*.".format(EXAMPLE_COMMAND)

    # Finds and executes the given command, filling in response
    response = None
    # This is where you start to implement more commands!
    if command.startswith(EXAMPLE_COMMAND):
        response = "Sure...write some more code then I can do that!"

    # Sends the response back to the channel
    slack_client.api_call(
        "chat.postMessage",
        channel=channel,
        text=response or default_response
    )

And then it's just a matter of merging the two scripts!
Testing is very easy because it's just a matter of talking to Marvin via Slack.

Next Steps

Marvin the support chatbot at the moment is just a quick proof of concept. Much more fleshing out is required in the areas of context recognition and integrating with the rest of our systems. It does however show how quickly useful chatbots can be built!