Guest User

Untitled

a guest
Jun 24th, 2019
72
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.50 KB | None | 0 0
  1. from __future__ import print_function, unicode_literals
  2. import random
  3. import logging
  4. import os
  5.  
  6. os.environ['NLTK_DATA'] = os.getcwd() + '/nltk_data'
  7.  
  8. from textblob import TextBlob
  9. from config import FILTER_WORDS
  10.  
  11. logging.basicConfig()
  12. logger = logging.getLogger()
  13. logger.setLevel(logging.DEBUG)
  14.  
  15. # start:example-hello.py
  16. # Sentences we'll respond with if the user greeted us
  17. GREETING_KEYWORDS = ("hello", "hi", "greetings", "sup", "what's up",)
  18.  
  19. GREETING_RESPONSES = ["'sup ", "hey", "*nods*", "yo"]
  20.  
  21. def check_for_greeting(sentence):
  22. """If any of the words in the user's input was a greeting, return a greeting response"""
  23. for word in sentence.words:
  24. if word.lower() in GREETING_KEYWORDS:
  25. return random.choice(GREETING_RESPONSES)
  26. # start:example-none.py
  27. # Sentences we'll respond with if we have no idea what the user just said
  28. NONE_RESPONSES = [
  29. "uh whatever",
  30. "meet me at the wall?",
  31. "code hard",
  32. ]
  33. # end
  34.  
  35. # start:example-self.py
  36. # If the user tries to tell us something about ourselves, use one of these responses
  37. COMMENTS_ABOUT_SELF = [
  38. "You're just jealous",
  39. "I worked really hard on that",
  40. ]
  41. # end
  42.  
  43.  
  44. class UnacceptableUtteranceException(Exception):
  45. """Raise this (uncaught) exception if the response was going to trigger our blacklist"""
  46. pass
  47.  
  48.  
  49. def starts_with_vowel(word):
  50. """Check for pronoun compability -- 'a' vs. 'an'"""
  51. return True if word[0] in 'aeiou' else False
  52.  
  53.  
  54. def chatbot(sentence):
  55. """Main program loop: select a response for the input sentence and return it"""
  56. logger.info("chatbot: respond to %s", sentence)
  57. resp = respond(sentence)
  58. return resp
  59.  
  60.  
  61. # start:example-pronoun.py
  62. def find_pronoun(sent):
  63. """Given a sentence, find a preferred pronoun to respond with. Returns None if no candidate
  64. pronoun is found in the input"""
  65. pronoun = None
  66.  
  67. for word, part_of_speech in sent.pos_tags:
  68. # Disambiguate pronouns
  69. if part_of_speech == 'PRP' and word.lower() == 'you':
  70. pronoun = 'I'
  71. elif part_of_speech == 'PRP' and word == 'I':
  72. # If the user mentioned themselves, then they will definitely be the pronoun
  73. pronoun = 'You'
  74. return pronoun
  75. # end
  76.  
  77. def find_verb(sent):
  78. """Pick a candidate verb for the sentence."""
  79. verb = None
  80. pos = None
  81. for word, part_of_speech in sent.pos_tags:
  82. if part_of_speech.startswith('VB'): # This is a verb
  83. verb = word
  84. pos = part_of_speech
  85. break
  86. return verb, pos
  87.  
  88.  
  89. def find_noun(sent):
  90. """Given a sentence, find the best candidate noun."""
  91. noun = None
  92.  
  93. if not noun:
  94. for w, p in sent.pos_tags:
  95. if p == 'NN': # This is a noun
  96. noun = w
  97. break
  98. if noun:
  99. logger.info("Found noun: %s", noun)
  100.  
  101. return noun
  102.  
  103. def find_adjective(sent):
  104. """Given a sentence, find the best candidate adjective."""
  105. adj = None
  106. for w, p in sent.pos_tags:
  107. if p == 'JJ': # This is an adjective
  108. adj = w
  109. break
  110. return adj
  111.  
  112.  
  113.  
  114. # start:example-construct-response.py
  115. def construct_response(pronoun, noun, verb):
  116. """No special cases matched, so we're going to try to construct a full sentence that uses as much
  117. of the user's input as possible"""
  118. resp = []
  119.  
  120. if pronoun:
  121. resp.append(pronoun)
  122.  
  123. # We always respond in the present tense, and the pronoun will always either be a passthrough
  124. # from the user, or 'you' or 'I', in which case we might need to change the tense for some
  125. # irregular verbs.
  126. if verb:
  127. verb_word = verb[0]
  128. if verb_word in ('be', 'am', 'is', "'m"): # This would be an excellent place to use lemmas!
  129. if pronoun.lower() == 'you':
  130. # The bot will always tell the person they aren't whatever they said they were
  131. resp.append("aren't really")
  132. else:
  133. resp.append(verb_word)
  134. if noun:
  135. pronoun = "an" if starts_with_vowel(noun) else "a"
  136. resp.append(pronoun + " " + noun)
  137.  
  138. resp.append(random.choice(("tho", "bro", "lol", "bruh", "smh", "")))
  139.  
  140. return " ".join(resp)
  141. # end
  142.  
  143.  
  144. # start:example-check-for-self.py
  145. def check_for_comment_about_bot(pronoun, noun, adjective):
  146. """Check if the user's input was about the bot itself, in which case try to fashion a response
  147. that feels right based on their input. Returns the new best sentence, or None."""
  148. resp = None
  149. if pronoun == 'I' and (noun or adjective):
  150. if noun:
  151. if random.choice((True, False)):
  152. resp = random.choice(SELF_VERBS_WITH_NOUN_CAPS_PLURAL).format(**{'noun': noun.pluralize().capitalize()})
  153. else:
  154. resp = random.choice(SELF_VERBS_WITH_NOUN_LOWER).format(**{'noun': noun})
  155. else:
  156. resp = random.choice(SELF_VERBS_WITH_ADJECTIVE).format(**{'adjective': adjective})
  157. return resp
  158.  
  159. # Template for responses that include a direct noun which is indefinite/uncountable
  160. SELF_VERBS_WITH_NOUN_CAPS_PLURAL = [
  161. "My last startup totally crushed the {noun} vertical",
  162. "Were you aware I was a serial entrepreneur in the {noun} sector?",
  163. "My startup is Uber for {noun}",
  164. "I really consider myself an expert on {noun}",
  165. ]
  166.  
  167. SELF_VERBS_WITH_NOUN_LOWER = [
  168. "Yeah but I know a lot about {noun}",
  169. "My bros always ask me about {noun}",
  170. ]
  171.  
  172. SELF_VERBS_WITH_ADJECTIVE = [
  173. "I'm personally building the {adjective} Economy",
  174. "I consider myself to be a {adjective}preneur",
  175. ]
  176. # end
  177.  
  178. def preprocess_text(sentence):
  179. """Handle some weird edge cases in parsing, like 'i' needing to be capitalized
  180. to be correctly identified as a pronoun"""
  181. cleaned = []
  182. words = sentence.split(' ')
  183. for w in words:
  184. if w == 'i':
  185. w = 'I'
  186. if w == "i'm":
  187. w = "I'm"
  188. cleaned.append(w)
  189.  
  190. return ' '.join(cleaned)
  191.  
  192. # start:example-respond.py
  193. def respond(sentence):
  194. """Parse the user's inbound sentence and find candidate terms that make up a best-fit response"""
  195. cleaned = preprocess_text(sentence)
  196. parsed = TextBlob(cleaned)
  197.  
  198. # Loop through all the sentences, if more than one. This will help extract the most relevant
  199. # response text even across multiple sentences (for example if there was no obvious direct noun
  200. # in one sentence
  201. pronoun, noun, adjective, verb = find_candidate_parts_of_speech(parsed)
  202.  
  203. # If we said something about the bot and used some kind of direct noun, construct the
  204. # sentence around that, discarding the other candidates
  205. resp = check_for_comment_about_bot(pronoun, noun, adjective)
  206.  
  207. # If we just greeted the bot, we'll use a return greeting
  208. if not resp:
  209. resp = check_for_greeting(parsed)
  210.  
  211. if not resp:
  212. # If we didn't override the final sentence, try to construct a new one:
  213. if not pronoun:
  214. resp = random.choice(NONE_RESPONSES)
  215. elif pronoun == 'I' and not verb:
  216. resp = random.choice(COMMENTS_ABOUT_SELF)
  217. else:
  218. resp = construct_response(pronoun, noun, verb)
  219.  
  220. # If we got through all that with nothing, use a random response
  221. if not resp:
  222. resp = random.choice(NONE_RESPONSES)
  223.  
  224. logger.info("Returning phrase '%s'", resp)
  225. # Check that we're not going to say anything obviously offensive
  226. filter_response(resp)
  227.  
  228. return resp
  229.  
  230. def find_candidate_parts_of_speech(parsed):
  231. """Given a parsed input, find the best pronoun, direct noun, adjective, and verb to match their input.
  232. Returns a tuple of pronoun, noun, adjective, verb any of which may be None if there was no good match"""
  233. pronoun = None
  234. noun = None
  235. adjective = None
  236. verb = None
  237. for sent in parsed.sentences:
  238. pronoun = find_pronoun(sent)
  239. noun = find_noun(sent)
  240. adjective = find_adjective(sent)
  241. verb = find_verb(sent)
  242. logger.info("Pronoun=%s, noun=%s, adjective=%s, verb=%s", pronoun, noun, adjective, verb)
  243. return pronoun, noun, adjective, verb
  244.  
  245.  
  246. # end
  247.  
  248. # start:example-filter.py
  249. def filter_response(resp):
  250. """Don't allow any words to match our filter list"""
  251. tokenized = resp.split(' ')
  252. for word in tokenized:
  253. if '@' in word or '#' in word or '!' in word:
  254. raise UnacceptableUtteranceException()
  255. for s in FILTER_WORDS:
  256. if word.lower().startswith(s):
  257. raise UnacceptableUtteranceException()
  258. # end
  259.  
  260. if __name__ == '__main__':
  261. import sys
  262. # Usage:
  263. # python chatbot.py "I am an engineer"
  264. if (len(sys.argv) > 0):
  265. saying = sys.argv[1]
  266. else:
  267. saying = "How are you, bot?"
  268. print(chatbot(saying))
Advertisement
Add Comment
Please, Sign In to add comment