Loading

ELIZA – A Pioneering Natural Language Processing Program

Get The Source

Have you ever heard of ELIZA? If you haven’t, you’re in for a treat! ELIZA is a classic computer program designed to simulate human-like conversation, and it’s a fascinating piece of technology that showcases the beginnings of Natural Language Processing (NLP). In this article, we’ll explore ELIZA in detail, complete with code samples and illustrations to help you understand how it works.

Joseph Weizenbaum created ELIZA at MIT in the 1960s when computer science was in its infancy. The idea of a computer program that could engage in human-like conversation was groundbreaking and set the stage for the development of NLP.

So, how does ELIZA work? ELIZA uses a simple yet effective technique called pattern matching and substitution. The program uses a set of psychobabble patterns and corresponding responses stored in an external file to generate its responses. ELIZA also includes a collection of reflections stored in another file, which allows it to reflect words from the user’s input. Let’s take a closer look at each of these components.

First, let’s examine the psychobabble patterns. These patterns were inspired by the techniques used in client-centered therapy, which involves reflecting on the client’s words and feelings to help them gain insight into their thoughts and emotions. ELIZA’s psychobabble patterns use regular expressions to match the user’s input and generate a response based on the pattern that best matches the input.

Here’s an example of the psychobabble.json file that stores ELIZA’s psychobabble patterns:

[
  [r'I feel (.*)',
   ["Why do you feel {0}?",
    "Do you often feel {0}?",
    "When do you usually feel {0}?",
    "Can you tell me more about why you feel {0}?"]],

  [r'I have (.*)',
   ["Why do you have {0}?",
    "Can you tell me more about having {0}?",
    "Do you enjoy having {0}?",
    "Do you think having {0} is a good thing?"]],

  [r'I (.*) you',
   ["Why do you {0} me?",
    "Do you often {0} people?",
    "Do you {0} anyone else?"]],

  [r'Why (.*)',
   ["Why don't you tell me the reason why {0}?",
    "Can you give me a specific example of why {0}?",
    "What is your opinion on why {0}?"]],

  [r'I want (.*)',
   ["What would it mean to you if you got {0}?",
    "Why do you want {0}?",
    "What would you do if you got {0}?",
    "If you got {0}, then what?"]]
]

As you can see, each pattern is represented as a regular expression, followed by a list of possible responses. ELIZA uses these patterns to match the user’s input and generate a response. For example, if the user inputs “I feel sad,” ELIZA would match the first pattern, “I feel (.*),” and generate one of the possible responses, such as “Why do you feel sad?”

Next, let’s examine the reflections. These reflections allow ELIZA to reflect words from the user’s input, making the conversation more personalized and human-like. The reflections are stored in a separate file called reflections.json.

Here’s an example of the reflections.json file:

{
  "am": "are",
  "was": "were",
  "i": "you",
  "i'd": "you would",
  "i've": "you have",
  "i'll": "you will",
  "my": "your",
  "are": "am",
  "you've": "I have",
  "you'll": "I will",
  "your": "my",
  "yours": "mine",
  "you": "me",
  "me": "you"
}

As you can see, the reflections are stored as key-value pairs, where each key represents a word or phrase, and each value represents the corresponding reflection. During the conversation, ELIZA uses the reflections to generate responses by reflecting words from the user’s input. For example, if the user inputs “I feel sad,” ELIZA would use the reflections to generate a response such as “Why do you feel sad?”

Now that we’ve seen the psychobabble patterns and reflections let’s look at the code that brings it all together. Here’s the complete code for the ELIZA program:

import re
import random
import json

class Eliza:
    def __init__(self, psychobabble_file, reflections_file):
        with open(psychobabble_file, 'r') as f:
            self.psychobabble = json.load(f)
        with open(reflections_file, 'r') as f:
            self.reflections = json.load(f)
        self.regex = re.compile(r'\b%s\b' % '\\b|\\b'.join(self.reflections.keys()))
        
    def reflect(self, match):
        word = match.group()
        reflection = self.reflections.get(word.lower(), word)
        return reflection
    
    def respond(self, input_string):
        input_string = self.regex.sub(self.reflect, input_string.lower())
        for pattern, responses in self.psychobabble:
            match = re.search(pattern, input_string)
            if match:
                response = random.choice(responses)
                response = response.format(*[self.reflect(group) for group in match.groups()])
                return response
        
    def chat(self):
        print("Hello, how are you feeling today?")
        while True:
            input_string = input("You: ")
            if input_string.strip().lower() == "quit":
                break
            response = self.respond(input_string)
            print("ELIZA: " + response)
        print("Goodbye!")

if __name__ == '__main__':
    eliza = Eliza("psychobabble.json", "reflections.json")
    eliza.chat()

The code begins by importing the required libraries, including the re library for regular expression processing, the random library for random selection, and the JSON library for reading and parsing JSON files.

Next, the Eliza class is defined. The __init__ method is the constructor for the class, and it takes two arguments: the names of the psychobabble and reflections JSON files.

In the __init__ method, the psychobabble and reflections are loaded from the JSON files and stored as class variables. The regex variable is also created, a compiled regular expression matching any word in the reflections.

The reflected method takes a regular expression match and returns the corresponding reflection for the matched word.

The response method takes an input string from the user and processes it to generate a response from ELIZA. First, the input string is converted to lowercase, and any words in the reflections are reflected using the regex.sub method.

Next, the input string is matched against each pattern in the psychobabble. If a match is found, a random response is selected from the corresponding list of responses and formatted using the format method. The method returns the final response.

Finally, the chat method is defined to provide the main interface for the user to interact with ELIZA. The method prints a greeting and enters a loop to prompt the user for input. The input_string is obtained from the user using the input function. If the input string is “quit,” the loop is exited, and a goodbye message is printed. Otherwise, the input string is passed to the response method to get a response, which is then printed.

The code concludes with an if __name__ == ‘__main__’ check, which ensures that the code only runs if the script is executed as the main program and not as an imported module. An instance of the Eliza class is created, and the chat method is called to start the conversation.

With this, we have a basic understanding of how the Eliza program works. The program can be easily modified and expanded by using external JSON files for psychobabble and reflections. This classic example of a chatbot demonstrates the power of pattern matching and substitution in simulating human conversation.

Add Comment

Your email address will not be published. Required fields are marked *