Create your ELIZA Chatbot in 20 minutes with Regular Expressions (Day 6)

Eliza was created by Joseph Weizenbaum in 1966 at MIT AI Lab. It is the first known chatbot that passed the Turing test. Eliza mocked human communication through pattern matching and substitution. It generated natural dialogs with the help of pre-written scripts. These scripts were able to handle different dialog inputs to respond accordingly. However any question that is not being addressed by these scripts will make Eliza talk dumb. One such script made Eliza a beloved bot among people, which made her act as a psychiatrist. Many people spend time talking to Eliza and admitted they felt relief by doing it.

act humanly #

Although Eliza's inner working did nothing but simple pattern matching, It appeared intelligent to those who interacted with her. This proves the capability of machines to act humanly (footnote #1) through different approaches that fall into pattern matching. Anyway, we already are looking into one such simple technique called regex. With the power of regex., we are going to build our own version of Eliza bot, which will handle a couple of dialogs elegantly and will fail gorgeously! And for sure, there's a lot of room for improvement.

I believe you are ready to launch. Are you? #

The rule is simple. Think of possible utterances that a person might make to Eliza. Generalize them into seperate categories (classification) and define rules for pattern matching (modelling) - if I were you, will be remembering these tiny rules until the end of this entire blog series.

Now I can introduce you an example pattern below, to get some intuition on this. Below scenes represent different utterances that a user might make to express the same feeling.

scene #1

Me: Eliza I think I like you.

Eliza: Perhaps in your fantasy, we like each other.

---❤---

scene #2

Me: Eliza, I love you.

Eliza: Perhaps in your fantasy, we love each other.

---❤---

scene #3

Me: I admit I think of you.

Eliza: Perhaps in your fantasy, we think of each other.

---❤---

scene #4

Me: Hey, I miss you.

Eliza: Perhaps in your fantasy, we miss each other.

---?---

scene #5

Me: I will move mountains for you.

Eliza: Perhaps in your fantasy, we will move mountains for each other.

--- meh? ---

scene #6

Me: What?? Now I think I wanna kill you.

Eliza: Perhaps in your fantasy, we wanna kill each other.

---Yeah! dumb.---

​ In the above example, we could see a common pattern and we want to match it. Can you think of a single regex. to match all of the above the utterances made to Eliza? Of cause, you do: /(.*)?I (.*) you(.*)?/, we've learned it last day. Now that we have created a pattern that will classify utterances like above into one category, we also need to extract useful words in those utterances. Let's call it a useful entity. In this case, we find anything that lies between I and you, as a useful entity. So, we will substitute our template answer with this entity - Perhaps in your fantasy, we $2 each other. $2 is used to emphasize that we are substituting the second match here.

This way, we could write as many rules that Eliza could use to classify user utterances and fetch useful entities.

making of Eliza #

We will use Javascript language to program our own clone of Eliza bot. For now, this bot will use a handful of examples that I have collected from the internet. It's not enough. You can tweak the code and add more patterns to make Eliza even smarter. The patterns and resulting utterances to be made are kept as a Javascript object. For each pattern stored as a key will have an array of resulting utterances to be chosen at random. Here it is:

var model = {
    ".*hello .*": [
        "How do you do. Please state your problem."
        ],
    "(.*)? computer(.*)?": [
        "Do computers worry you?",
        "What do you think about machines?",
        "Why do you mention computers?",
        "What do you think machines have to do with your problem?",
        ],
    "(.*)? name(.*)?": [
        "I am not interested in names",
        ],
    "(.*)?sorry(.*)?": [
        "Please don't apologize",
        "Apologies are not necessary",
        "What feelings do you have when you apologize",
        ],
    "(.*)?I remember (.*)?": [
        "Do you often think of $2?",
        "Does thinking of $2 bring anything else to mind?",
        "What else do you remember?",
        "Why do you recall $2 right now?",
        "What in the present situation reminds you of $2?",
        "What is the connection between me and $2?",
        ],
    "(.*)?do you remember (.*)?": [
        "Did you think I would forget $2?",
        "Why do you think I should recall $2 now?",
        "What about $2?",
        "You mentioned $2",
        ],
    "(.*)?I want (.*)?": [
        "What would it mean if you got $2?",
        "Why do you want $2?",
        "Suppose you got $2 soon."
        ],
    "(.*)?if (.*)?": [
        "Do you really think it's likely that $2?",
        "Do you wish that $2?",
        "What do you think about $2?",
        "Really--if $2?"
        ],
    "(.*)?I dreamt (.*)?": [
        "How do you feel about $2 in reality?",
        ],
    "(.*)? dream (.*)?": [
        "What does this dream suggest to you?",
        "Do you dream often?",
        "What persons appear in your dreams?",
        "Don't you believe that dream has to do with your problem?",
        ],
    "(.*)?my mother (.*)?": [
        "Who else in your family $2?",
        "Tell me more about your family",
        ],
    "(.*)?my father (.*)?": [
        "Your father?",
        "Does he influence you strongly?",
        "What else comes to mind when you think of your father?",
        ],
    "(.*)?I am glad(.*)?": [
        "How have I helped you to be $2?",
        "What makes you happy just now?",
        "Can you explain why you are suddenly $2?",
        ],
    "(.*)?I am sad(.*)?": [
        "I am sorry to hear you are depressed",
        "I'm sure it's not pleasant to be sad",
        ],
    "(.*)? are like (.*)?": [
        "What resemblence do you see between $1 and $2?",
        ],
    "(.*)? is like (.*)?": [
        "In what way is it that $1 is like $2?",
        "What resemblence do you see?",
        "Could there really be some connection?",
        "How?",
        ],
    "(.*)? alike (.*)?": [
        "In what way?",
        "What similarities are there?",
        ],
    "(.*)? same (.*)?": [
        "What other connections do you see?",
        ],
    "(.*)?no(.*)?": [
        "Why not?",
        "You are being a bit negative.",
        "Are you saying 'No' just to be negative?"
        ],
    "(.*)?I was (.*)?": [
        "Were you really?",
        "Perhaps I already knew you were $2.",
        "Why do you tell me you were $2 now?"
        ],
    "(.*)? was I (.*)?": [
        "What if you were $2?",
        "Do you think you were $2?",
        "What would it mean if you were $2?",
        ],
    "(.*)?I am (.*)?": [
        "In what way are you $2?",
        "Do you want to be $2?",
        ],
    "(.*)?am I (.*)?": [
        "Do you believe you are $2?",
        "Would you want to be $2?",
        "You wish I would tell you you are $2?",
        "What would it mean if you were $2?",
        ],
    "(.*)? am (.*)?": [
        "Why do you say 'AM?'",
        "I don't understand that"
        ],
    "(.*)?are you (.*)?": [
        "Why are you interested in whether I am $2 or not?",
        "Would you prefer if I weren't $2?",
        "Perhaps I am $2 in your fantasies",
        ],
    "(.*)?you are (.*)?": [
        "What makes you think I am $2?",
        ],
    "(.*)?because (.*)?": [
        "Is that the real reason?",
        "What other reasons might there be?",
        "Does that reason seem to explain anything else?",
        ],
    "(.*)?were you (.*)?": [
        "Perhaps I was $2?",
        "What do you think?",
        "What if I had been $2?",
        ],
    "(.*)?I can't (.*)?": [
        "Maybe you could $2 now",
        "What if you could $2?",
        ],
    "(.*)?I feel (.*)?": [
        "Do you often feel $2?"
        ],
    "(.*)?I felt (.*)?": [
        "What other feelings do you have?"
        ],
    "(.*)?I (.*)? you (.*)?z": [
        "Perhaps in your fantasy we $2 each other",
        ],
    "(.*)?why don't you (.*)?": [
        "Should you $2 yourself?",
        "Do you believe I don't $2?",
        "Perhaps I will $2 in good time",
        ],
    "(.*)?yes(.*)?": [
        "You seem quite positive",
        "You are sure?",
        "I understand",
        ],
    "(.*)? someone (.*)?": [
        "Can you be more specific?",
        ],
    "(.*)? everyone (.*)?": [
        "Surely not everyone",
        "Can you think of anyone in particular?",
        "Who, for example?",
        "You are thinking of a special person",
        ],
    "(.*)? always (.*)?": [
        "Can you think of a specific example?",
        "When?",
        "What incident are you thinking of?",
        "Really--always?",
        ],
    "(.*)?what (.*)?": [
        "Why do you ask?",
        "Does that question interest you?",
        "What is it you really want to know?",
        "What do you think?",
        "What comes to your mind when you ask that?",
        ],
    "(.*)?perhaps (.*)?": [
        "You do not seem quite certain",
        ],
    "(.*)?are (.*)?": [
        "Did you think they might not be $2?",
        "Possibly they are $2",
        ]
}

We also will keep some default responses as well. This will help to keep the conversation active even if Eliza didn't understand last user utterance.

var default_model = [
    "Very interesting",
    "I am not sure I understand you fully",
    "What does that suggest to you?",
    "Please continue",
    "Go on",
    "Do you feel strongly about discussing such things?",
    ]

Now we will create a find_match method, to try matching each pattern from stories object until one does. If a match found, corresponding key will be noted down to fetch a random response from it.

function findMatch(msgIn, cbk){
    for (var key in stories) {
        var re = RegExp(key)
        if(re.test(msgIn)){
            cbk(key)
            return
        }
    }
    cbk(null)
    return
}

If no match found, Eliza will utter something randomly from default_model.

The above components power the backbone of Eliza. Rest of the code does some formatting and helpful actions to move query and responses between user interface. You can access the source code from here. Here's our bot, which is ready to talk. Don't forget to tweak the code to teach Eliza more responses.

Congrats! You have created your first. We will see in the upcoming article with more exciting stuff to build upon what we've learned so far. See ya.

footnote:

[#1] Views of AI fall into four categories: thinking humanly, thinking rationally, acting humanly, acting rationally. Turing test falls into the category, acting humanly.

By the end of this article, we believe that, we were able to give you a glimpse of what is meant by a classification task in machine learning. And what does an entity mean for a chatbot developer. In the upcoming article, we will look into more complex algorithms for ML. Although a conversational/NLP perspective is preferred for our examples, you could apply these concepts to other problems as well.

About Author

Jubin Jose

Chatbot Developer at Cedex Technologies LLP | Technology: C, Node JS Hobby: beginner ML & AI + creative coding + Youtuber.


Want to work with us?

Be free to contact us for any of your chatbot development queries. As a company specialized in Chatbot development, we can provide you quality services. We will be happy to provide you a free quote.

Contact Us