tf_chatbot



In [1]:
# things we need for NLP
import nltk
from nltk.stem.lancaster import LancasterStemmer
stemmer = LancasterStemmer()

# things we need for Tensorflow
import numpy as np
import tflearn
import tensorflow as tf
import random


hdf5 is not supported on this machine (please install/reinstall h5py for optimal experience)

In [2]:
# import our chat-bot intents file
import json
with open('intents.json') as json_data:
    intents = json.load(json_data)

In [3]:
words = []
classes = []
documents = []
ignore_words = ['?']
# loop through each sentence in our intents patterns
for intent in intents['intents']:
    for pattern in intent['patterns']:
        # tokenize each word in the sentence
        w = nltk.word_tokenize(pattern)
        # add to our words list
        words.extend(w)
        # add to documents in our corpus
        documents.append((w, intent['tag']))
        # add to our classes list
        if intent['tag'] not in classes:
            classes.append(intent['tag'])

# stem and lower each word and remove duplicates
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)


27 documents
9 classes ['goodbye', 'greeting', 'meaningoflife', 'thanks', 'turn_off_lights', 'turn_on_lights', 'whoami', 'whoru', 'worlddomination']
52 unique stemmed words ["'s", 'am', 'anyon', 'ar', 'bright', 'bye', 'dark', 'day', 'destroy', 'do', 'evil', 'ex', 'going', 'good', 'goodby', 'hello', 'help', 'her', 'hi', 'how', 'hum', 'i', 'in', 'is', 'it', 'lat', 'lif', 'light', 'mean', 'my', 'of', 'off', 'on', 'ov', 'purpos', 'rac', 'see', 'skynet', 'switch', 'tak', 'thank', 'that', 'the', 'ther', 'to', 'turn', 'what', 'who', 'why', 'wil', 'world', 'you']

In [4]:
# create our training data
training = []
output = []
# create an empty array for our output
output_empty = [0] * len(classes)

# training set, bag of words for each sentence
for doc in documents:
    # initialize our bag of words
    bag = []
    # list of tokenized words for the pattern
    pattern_words = doc[0]
    # stem each word
    pattern_words = [stemmer.stem(word.lower()) for word in pattern_words]
    # create our bag of words array
    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])

# shuffle our features and turn into np.array
random.shuffle(training)
training = np.array(training)

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

In [5]:
training[0][1]


Out[5]:
[0, 1, 0, 0, 0, 0, 0, 0, 0]

In [6]:
# reset underlying graph data
tf.reset_default_graph()
# Build neural network
net = tflearn.input_data(shape=[None, len(train_x[0])])
net = tflearn.fully_connected(net, 8)
net = tflearn.fully_connected(net, 8)
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')


Training Step: 3999  | total loss: 0.08494 | time: 0.006s
| Adam | epoch: 1000 | loss: 0.08494 - acc: 0.9559 -- iter: 24/27
Training Step: 4000  | total loss: 0.07949 | time: 0.007s
| Adam | epoch: 1000 | loss: 0.07949 - acc: 0.9603 -- iter: 27/27
--
INFO:tensorflow:/home/spock/py_space/tf_nbs/model.tflearn is not in all_model_checkpoint_paths. Manually adding it.

In [8]:
def clean_up_sentence(sentence):
    # tokenize the pattern
    sentence_words = nltk.word_tokenize(sentence)
    # stem each word
    sentence_words = [stemmer.stem(word.lower()) for word in sentence_words]
    return sentence_words

# return bag of words array: 0 or 1 for each word in the bag that exists in the sentence
def bow(sentence, words, show_details=False):
    # tokenize the pattern
    sentence_words = clean_up_sentence(sentence)
    # bag of words
    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))

In [9]:
p = bow("Are you Evil?", words)
print (p)
print (classes)


[0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1]
['goodbye', 'greeting', 'meaningoflife', 'thanks', 'turn_off_lights', 'turn_on_lights', 'whoami', 'whoru', 'worlddomination']

In [10]:
print(model.predict([p]))


[[  3.12493711e-08   1.42307682e-02   6.80323597e-03   5.17977378e-06
    1.22651670e-06   8.87794101e-07   1.33351500e-06   1.68149509e-02
    9.62142408e-01]]

In [28]:
# create a data structure to hold user context
context = {}

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

def response(sentence, userID='123', show_details=False):
    results = classify(sentence)
    if results[0][0] == 'turn_on_lights':
        print ('Placeholder for Lights ON')
    elif results[0][0] == 'turn_off_lights':
        print ('Placeholder of Lights OFF')
    # 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)

In [26]:
classify('Lights')


Out[26]:
[('turn_on_lights', 0.38387546)]

In [30]:
response('Lights ON')


Placeholder for Lights ON
Your wish is my command

In [ ]: