PageRenderTime 45ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/nltk/chat/util.py

https://github.com/BrucePHill/nltk
Python | 120 lines | 95 code | 5 blank | 20 comment | 3 complexity | 06d8558b072094397d027dcaeb3893d1 MD5 | raw file
Possible License(s): Apache-2.0
  1. # Natural Language Toolkit: Chatbot Utilities
  2. #
  3. # Copyright (C) 2001-2013 NLTK Project
  4. # Authors: Steven Bird <stevenbird1@gmail.com>
  5. # URL: <http://www.nltk.org/>
  6. # For license information, see LICENSE.TXT
  7. # Based on an Eliza implementation by Joe Strout <joe@strout.net>,
  8. # Jeff Epler <jepler@inetnebr.com> and Jez Higgins <jez@jezuk.co.uk>.
  9. from __future__ import print_function
  10. import re
  11. import random
  12. from nltk import compat
  13. reflections = {
  14. "i am" : "you are",
  15. "i was" : "you were",
  16. "i" : "you",
  17. "i'm" : "you are",
  18. "i'd" : "you would",
  19. "i've" : "you have",
  20. "i'll" : "you will",
  21. "my" : "your",
  22. "you are" : "I am",
  23. "you were" : "I was",
  24. "you've" : "I have",
  25. "you'll" : "I will",
  26. "your" : "my",
  27. "yours" : "mine",
  28. "you" : "me",
  29. "me" : "you"
  30. }
  31. class Chat(object):
  32. def __init__(self, pairs, reflections={}):
  33. """
  34. Initialize the chatbot. Pairs is a list of patterns and responses. Each
  35. pattern is a regular expression matching the user's statement or question,
  36. e.g. r'I like (.*)'. For each such pattern a list of possible responses
  37. is given, e.g. ['Why do you like %1', 'Did you ever dislike %1']. Material
  38. which is matched by parenthesized sections of the patterns (e.g. .*) is mapped to
  39. the numbered positions in the responses, e.g. %1.
  40. :type pairs: list of tuple
  41. :param pairs: The patterns and responses
  42. :type reflections: dict
  43. :param reflections: A mapping between first and second person expressions
  44. :rtype: None
  45. """
  46. self._pairs = [(re.compile(x, re.IGNORECASE),y) for (x,y) in pairs]
  47. self._reflections = reflections
  48. self._regex = self._compile_reflections()
  49. def _compile_reflections(self):
  50. sorted_refl = sorted(self._reflections.keys(), key=len,
  51. reverse=True)
  52. return re.compile(r"\b({0})\b".format("|".join(map(re.escape,
  53. sorted_refl))), re.IGNORECASE)
  54. def _substitute(self, str):
  55. """
  56. Substitute words in the string, according to the specified reflections,
  57. e.g. "I'm" -> "you are"
  58. :type str: str
  59. :param str: The string to be mapped
  60. :rtype: str
  61. """
  62. return self._regex.sub(lambda mo:
  63. self._reflections[mo.string[mo.start():mo.end()]],
  64. str.lower())
  65. def _wildcards(self, response, match):
  66. pos = response.find('%')
  67. while pos >= 0:
  68. num = int(response[pos+1:pos+2])
  69. response = response[:pos] + \
  70. self._substitute(match.group(num)) + \
  71. response[pos+2:]
  72. pos = response.find('%')
  73. return response
  74. def respond(self, str):
  75. """
  76. Generate a response to the user input.
  77. :type str: str
  78. :param str: The string to be mapped
  79. :rtype: str
  80. """
  81. # check each pattern
  82. for (pattern, response) in self._pairs:
  83. match = pattern.match(str)
  84. # did the pattern match?
  85. if match:
  86. resp = random.choice(response) # pick a random response
  87. resp = self._wildcards(resp, match) # process wildcards
  88. # fix munged punctuation at the end
  89. if resp[-2:] == '?.': resp = resp[:-2] + '.'
  90. if resp[-2:] == '??': resp = resp[:-2] + '?'
  91. return resp
  92. # Hold a conversation with a chatbot
  93. def converse(self, quit="quit"):
  94. input = ""
  95. while input != quit:
  96. input = quit
  97. try: input = compat.raw_input(">")
  98. except EOFError:
  99. print(input)
  100. if input:
  101. while input[-1] in "!.": input = input[:-1]
  102. print(self.respond(input))