/nltk/chat/util.py
Python | 120 lines | 95 code | 5 blank | 20 comment | 3 complexity | 06d8558b072094397d027dcaeb3893d1 MD5 | raw file
Possible License(s): Apache-2.0
- # Natural Language Toolkit: Chatbot Utilities
- #
- # Copyright (C) 2001-2013 NLTK Project
- # Authors: Steven Bird <stevenbird1@gmail.com>
- # URL: <http://www.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 nltk import compat
- 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"
- }
- 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
- 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
- def converse(self, quit="quit"):
- input = ""
- while input != quit:
- input = quit
- try: input = compat.raw_input(">")
- except EOFError:
- print(input)
- if input:
- while input[-1] in "!.": input = input[:-1]
- print(self.respond(input))