Learn to Code via Tutorials on Repl.it

← Back to all posts
4
Tensorflow chat bot!!
DuncanSykes (3)

Chatbot with TensorFlow and Python

Have you ever felt the need to write a chatbot in python but don't want to mess around with hundreds of IF statements?

Yes?
No?

Well either way, you clicked on this tutorial. Today we are going to look into how we can create a chat bot in python, as well as building an alorigthm that allows some context in conversation.

YOU'LL NEED A 64 BIT PC FOR THIS TO WORK

The requirements:

You'll need to install Anaconda and the Jupyter Notebook system for this to work.

Once you've set up your environment, you'll need to install these packages by running these commands in you command line:

  • pip install pickle
  • pip install numpy
  • pip install tflearn
  • pip install tensorflow
  • pip install json
  • pip install LancasterStemmer

The code

(.JSON file):

For this system we'll use a .JSON (javascript object notation) file to code in keywords that the chatbot will identify as having certain meanings, and hence how to respond.

Open a new file in the Jupyter notebook and name it intents.json and copy this code across. We'll use this as an example in this tutorial.

You can edit this later

{
  "intents": [
    {
      "tag": "StartConvo",

      "patterns": [ "hello", "hi", "hey", "whats up" ],

      "responses": [ "heyy", "helloo", "hi", "wassup" ]
    },

    {
      "tag": "GenQuestions",

      "patterns": [ "how are you" ],

      "responses": [ "I'm good, how are you" ],

      "context_set": "GenQuestion"
    },
    {
      "tag": "GenAnswerPos",

      "patterns": [ "Im good thanks", "Good", "fine", "good", "great", "I'm good" ],

      "responses": [ "That's good", "Good", "cool", "yeah, good" ],

      "context_filter": "GenQuestion"
    },
    {
      "tag": "GenAnswerNeg",

      "patterns": [ "not good", "nah", "bad" ],

      "responses": [ "oh", "what's wrong", "that's not good" ],


      "context_filter": "GenQuestion"

    }
  ]
}

Part one: Setting up

Open a new Python 3 notebook and import the following libraries:

import numpy as np
import tflearn
import tensorflow as tf
import random
import json
import nltk
from nltk.stem.lancaster import LancasterStemmer

Now we need to initiate the LancasterStemmer library:

stemmer = LancasterStemmer()

Also we need to download some datasets for training.
Enter this code in a new cell

nltk.download('punkt') # This will download a text based data set straight into the notebook file

We can now import the .JSON file

with open('intents.json') as json_data:
    intents = json.load(json_data)

If the .JSON file is structured correctly, this should run without any issues.

We now can break down the data in the .JSON file for usage by the neural network by splitting giving each word a place in an array.

words = []
classes = []
documents = []
ignore_words =['?']

for intent in intents['intents']:
    for pattern in intent['patterns']:
        w = nltk.word_tokenize(pattern)
        words.extend(w)
        documents.append((w, intent['tag']))
        if intent['tag'] not in classes:
            classes.append(intent['tag'])
words = [stemmer.stem(w.lower()) for w in words if w not in ignore_words]
words = sorted(list(set(words)))

# remove duplicates
classes = sorted(list(set(classes)))

print (len(documents), "documents")
print (len(classes), "classes", classes)
print (len(words), "unique stemmed words", words)

We can now setup how the model for training:

training = []
output = []
output_empty = [0] * len(classes)

for doc in documents:
   
    bag = []
    pattern_words = doc[0]
    pattern_words = [stemmer.stem(word.lower()) for word in pattern_words]
    for w in words:
        bag.append(1) if w in pattern_words else bag.append(0)

    # output is a '0' for each tag and '1' for current tag
    output_row = list(output_empty)
    output_row[classes.index(doc[1])] = 1

    training.append([bag, output_row])


random.shuffle(training)
training = np.array(training)

# create train and test lists
train_x = list(training[:,0])
train_y = list(training[:,1])

# reset underlying graph data
tf.reset_default_graph()

We have now set the parameters for our neural network.
The next bit of code trains the model for the chat bot:

#Building the Neural Network
net = tflearn.input_data(shape=[None, len(train_x[0])])
net = tflearn.fully_connected(net, 10)
net = tflearn.fully_connected(net, 10)
net = tflearn.fully_connected(net, len(train_y[0]), activation='softmax')
net = tflearn.regression(net)

# Define model and setup tensorboard
model = tflearn.DNN(net, tensorboard_dir='tflearn_logs')
# Start training (apply gradient descent algorithm)
model.fit(train_x, train_y, n_epoch=1000, batch_size=8, show_metric=True)
model.save('model.tflearn')

Once you run the above code, the model will train then save itself as 'model.tflearn'

Part Three: Testing

While in the same jupyter notebook, run this code in a new cell:

pickle.dump( {'words':words, 'classes':classes, 'train_x':train_x, 'train_y':train_y}, open( "training_data", "wb" ) )

Now run this code:

data = pickle.load( open( "training_data", "rb" ) )
words = data['words']
classes = data['classes']
train_x = data['train_x']
train_y = data['train_y']


import json
with open('intents.json') as json_data:
    intents = json.load(json_data)

This reopens the intents file as testing data.
We now need to reload the model we trained earlier:

model.load('./model.tflearn')

For the code to work correctly we need clean our test data

def clean_up_sentence(sentence):
    
    sentence_words = nltk.word_tokenize(sentence)

    sentence_words = [stemmer.stem(word.lower()) for word in sentence_words]
    return sentence_words

# return bag of words array
def bow(sentence, words, show_details=False):

    sentence_words = clean_up_sentence(sentence)
    bag = [0]*len(words)  
    for s in sentence_words:
        for i,w in enumerate(words):
            if w == s: 
                bag[i] = 1
                if show_details:
                    print ("found in bag: %s" % w)

    return(np.array(bag))

You can now run a very simple test that will return binary values as a response.

p = bow("hello", words)
print(p)

You should get a result very similar to this

[0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0]

Part Four: Classifying words

We are now ready to make full use of our Tensorflow model and the training data we prepared. Copy this code into your notebook.

ERROR_THRESHOLD = 0.25
def classify(sentence):
    # generate probabilities from the model
    results = model.predict([bow(sentence, words)])[0]
    # filter out predictions below a threshold
    results = [[i,r] for i,r in enumerate(results) if r>ERROR_THRESHOLD]
    # sort by strength of probability
    results.sort(key=lambda x: x[1], reverse=True)
    return_list = []
    for r in results:
        return_list.append((classes[r[0]], r[1]))
    # return tuple of intent and probability
    return return_list

This next block of code allows some degree of context in a conversation with the bot by utilising the context_filter tag from the .JSON file

def response(sentence, userID='123', show_details=False):
    results = classify(sentence)
    # if we have a classification then find the matching intent tag
    if results:
        # loop as long as there are matches to process
        while results:
            for i in intents['intents']:
                # find a tag matching the first result
                if i['tag'] == results[0][0]:
                    # a random response from the intent
                    return print(random.choice(i['responses']))

            results.pop(0)\

If you now enter a command (example shown below) you should get an actual response.

response('Hello')

Your output should be something like this:
helloo

Try saying something else (one of patterns from the .JSON file)

Wrapping up

I hope this tutorial was clear enough and that it has given you a basis on how to train and test models with Tensorflow