Source code for nltk.chat.util

# Natural Language Toolkit: Chatbot Utilities
#
# Copyright (C) 2001-2019 NLTK Project
# Authors: Steven Bird <stevenbird1@gmail.com>
# URL: <http://nltk.org/>
# For license information, see LICENSE.TXT

# Based on an Eliza implementation by Joe Strout <joe@strout.net>,
# Jeff Epler <jepler@inetnebr.com> and Jez Higgins <jez@jezuk.co.uk>.
from __future__ import print_function

import re
import random

from six.moves import input


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


[docs]class Chat(object): def __init__(self, pairs, reflections={}): """ Initialize the chatbot. Pairs is a list of patterns and responses. Each pattern is a regular expression matching the user's statement or question, e.g. r'I like (.*)'. For each such pattern a list of possible responses is given, e.g. ['Why do you like %1', 'Did you ever dislike %1']. Material which is matched by parenthesized sections of the patterns (e.g. .*) is mapped to the numbered positions in the responses, e.g. %1. :type pairs: list of tuple :param pairs: The patterns and responses :type reflections: dict :param reflections: A mapping between first and second person expressions :rtype: None """ self._pairs = [(re.compile(x, re.IGNORECASE), y) for (x, y) in pairs] self._reflections = reflections self._regex = self._compile_reflections() def _compile_reflections(self): sorted_refl = sorted(self._reflections.keys(), key=len, reverse=True) return re.compile( r"\b({0})\b".format("|".join(map(re.escape, sorted_refl))), re.IGNORECASE ) def _substitute(self, str): """ Substitute words in the string, according to the specified reflections, e.g. "I'm" -> "you are" :type str: str :param str: The string to be mapped :rtype: str """ return self._regex.sub( lambda mo: self._reflections[mo.string[mo.start() : mo.end()]], str.lower() ) def _wildcards(self, response, match): pos = response.find('%') while pos >= 0: num = int(response[pos + 1 : pos + 2]) response = ( response[:pos] + self._substitute(match.group(num)) + response[pos + 2 :] ) pos = response.find('%') return response
[docs] def respond(self, str): """ Generate a response to the user input. :type str: str :param str: The string to be mapped :rtype: str """ # check each pattern for (pattern, response) in self._pairs: match = pattern.match(str) # did the pattern match? if match: resp = random.choice(response) # pick a random response resp = self._wildcards(resp, match) # process wildcards # fix munged punctuation at the end if resp[-2:] == '?.': resp = resp[:-2] + '.' if resp[-2:] == '??': resp = resp[:-2] + '?' return resp
# Hold a conversation with a chatbot
[docs] def converse(self, quit="quit"): user_input = "" while user_input != quit: user_input = quit try: user_input = input(">") except EOFError: print(user_input) if user_input: while user_input[-1] in "!.": user_input = user_input[:-1] print(self.respond(user_input))