This week, Harry joined our team! He’s hard-working, intelligent and good-natured which has made working with him a delight. He has even tolerated our 6:30 meetings with the patience of a saint. Thank you for being amazing, Harry!
Our first task of the week was to create some chatbots, which was surprisingly fun. After some research I decided the first thing I wanted to work on was an ELIZA.
In 1966 computer scientist Joseph Weizenbaum created ELIZA, an early natural language processing computer program which simulated a Rogerian psychotherapist. Rogerian Therapy uses a non-directive approach - Rogers was known for parroting back to clients what they had just said. ELIZA uses pattern matching and regex to give the illusion of understanding the user’s inputs.
NLTK has a lovely, simple module for creating regex chatbots like ELIZA. You can provide a pair of patterns and responses yourself, or use one provided in nltk.chat.util. I’ll briefly show you how to use this, but it’s very straightforward so I won’t spend long on it:
from nltk.chat.util import Chat, reflections # reflections is a dictionary of phrases that allow ELIZA to repeat the user’s words back to them (e.g. you’re = I’m, I was = you were) PAIRS = ( r"(.*)(Who (.*) you|What (.*) you)(.*)", # This handles questions such as “Who are you?”, “What can you do?” ( "My name is ELIZA. I like to hear about your feelings!", "I like to chat about feelings because I want to help you!", "My name is ELIZA. If you tell me about your feelings, I'll try my best to help!", ), ), ) # you can add as many regex & response pairs as you’d like if __name__ == "__main__": print("What's weighing on your mind?") chatbot = Chat(PAIRS, reflections) chatbot.converse()
It’s that simple.
To get a single response, write
To speak to NLTK’s own ELIZA, use
If you’re curious about how to create your own, or if you’d like some practice with Python’s re module then carry on reading:
Why do we use (.*)? The dot represents any character except a newline. The asterisk allows the RE to match repetitions of the dot.
Below, we want to start by finding a match between the user’s input and our patterns.
re.findall(pattern, message_in, re.IGNORECASE) finds matches such as r"(.) What if (.)" to “What if the wind changes and my face stays like this?”. Then, we choose at random one of the responses (e.g. choosing at random one of the following ("Is it really so bad if %1?", "You're concerned about %1?”)). You can use random.choice(responses) for this. Then we call substitute_pattern.
Now we want to find the “%1” in the response ("Is it really so bad if %1?”). In our PAIRS, there is only ever one %1, so I call response.find(“%”) once.
import re import random from pairs import PAIRS def find_matched_response(message_in, pairs=PAIRS): for pair in pairs: pattern = pair match = re.findall(pattern, message_in, re.IGNORECASE) if match != : response = random.choice(pair) response = substitute_pattern(pattern, response, match) return response def substitute_pattern(pattern, response, message_in): pos = response.find("%") if pos >= 0: response = (response[:pos] + message_in + response[pos + 2:]) return response if __name__=="__main__": print("Hello! My name is ELIZA, I'm a therapist.") print("How can I help you today?") while True: user_response = input("> ") output = find_matched_response(user_response) print(output)
# pairs.py PAIRS = ( ( r"I need (.*)", ( "Why do you need %1?", "Would it really help you to get %1?", "Are you sure you need %1?", ), ), ( r"(.*)(Who (.*) you|What (.*) you)(.*)", ( "My name is ELIZA. I like to hear about your feelings!", "I'm ELIZA. I like to chat about feelings because I want to help you.", "My name is ELIZA. If you tell me about your feelings, I'll try my best to help.", "I'm ELIZA the therapist chatbot. But enough about me, tell me more about yourself.", ), ), ( r"(.*)What if (.*)", ( "What's the worst that could happen?", "Is it really so bad if %1?", "You're concerned about %1?", ), ), ( r"quit|exit|bye|goodbye|cya", ( "Thank you for talking with me.", "Good-bye.", "Bye. Have a good day!", ), ), )