Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Python-Chatbot/conversate.py
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
186 lines (141 sloc)
5.38 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
################################################## | |
# Benjamin Grant - Idea for dictionary in learn(), unlearn() and get_response() from Kelvin Mock my group member, but implementation is entirely my own. | |
import random | |
import namestore | |
import datetime | |
import pickle | |
import quote | |
import exchange | |
# Unlearns a word or category | |
async def unlearn(category=None, word=None): | |
if word == None: #Category being unlearned | |
with open("brain.pck", "rb") as f: | |
brain = pickle.load(f) # Dictionary of category: [words] | |
if category in brain: | |
del brain[category] | |
with open("brain.pck", "wb") as f: | |
pickle.dump(brain, f) | |
elif category == None: #Word being unlearned | |
with open("brain.pck", "rb") as f: | |
brain = pickle.load(f) | |
if category in brain: | |
if word in brain[category]: | |
brain[category].remove(word) #This maintains category while removing word | |
with open("brain.pck", "wb") as f: | |
pickle.dump(brain, f) | |
# Enables the bot to learn new words or categories and save them for later use | |
async def learn(category, word): | |
with open("brain.pck", "rb") as f: | |
brain = pickle.load(f) # Dictionary of category: [words] | |
if category in brain: | |
if word not in brain[category]: | |
if type(word) is str: | |
brain[category].append(word) | |
else: | |
brain[category] = brain[category] + word | |
else: | |
if type(word) is str: | |
brain[category] = [word] | |
else: | |
brain[category] = word | |
with open("brain.pck", "wb") as f: | |
pickle.dump(brain, f) | |
# Gets a random response for a given category | |
async def get_response(category): | |
with open("brain.pck", "rb") as f: | |
map = pickle.load(f) | |
if category in map: | |
return random.choice(map[category]) | |
else: | |
return None #Check for None (invalid category, used for unit tests) | |
# Replaces in-string variables such as %name% | |
async def replacePlaceholders(msg, user): | |
name = await namestore.get_name(user.id) | |
if name == None: | |
ret = msg.replace("%name%", "") | |
else: | |
ret = msg.replace("%name%", name) | |
return ret | |
# Process commands or requests for modules. Return the message to be sent to the user | |
async def processCommands(message, id): | |
tokenised = message.split(" ") #NLTK-less way to split by word (in basic cases) | |
quote_triggers = ("show me a quote", | |
"inspire me", | |
"motivate me", | |
"give me a quote" | |
"quote", | |
"give me wisdom", | |
"send me knowledge") | |
currency_triggers =("what is", "how much is", "exchange", "convert") | |
if message.startswith('my name is'): | |
if len(tokenised) <= 3: | |
return 'Please provide a name.' | |
else: | |
#This for-loop rebuilds the required tokens into a name. This enables spaces in names | |
name="" | |
for i in range(len(tokenised)): | |
if i <= 2: | |
continue | |
name += tokenised[i] + " " | |
await namestore.set_name(id, name.strip()) | |
return 'Hello, ' + name.strip().capitalize() + "." | |
elif message.startswith('what is my name'): | |
name = await namestore.get_name(id) | |
if name == None: | |
return "I don't know your name. Try using `my name is <name>`" | |
else: | |
return 'Your name is ' + name.strip() + "." | |
#Example usage: what is 100 GBP in USD | |
for trigger in currency_triggers[0]: | |
if message.startswith(trigger): | |
words = len(trigger.split(" ")) | |
if tokenised[words+3] == "in": | |
try: #Hacky, rushed way to parse text and split into arguments | |
amount = float(tokenised[words+1]) | |
base_cur = tokenised[words+2].upper() | |
to_cur = tokenised[words+4].upper() | |
return str(amount) + " " + base_cur + " is " + str(round(await exchange.convertCurrency(to_cur, base_cur, amount), 2)) + " " + to_cur | |
except Exception as e: | |
print(e + " - currency exchange error.") | |
break | |
for trigger in quote_triggers: | |
if message.startswith(trigger): | |
genQ = await quote.generateQuote() | |
return genQ | |
return None | |
# Actual processing of message content and response | |
async def processMessage(client, message): | |
if client.user.id == message.author.id or message.content.startswith("!"): | |
return | |
text = message.content.lower() | |
response = await processCommands(text, message.author.id) | |
if response == None: #No command was detected in the text | |
response = "Sorry %name%, I don't know what you mean by '" + message.content + "'. Use !help for information about my functionality." | |
greeting = ("hi", | |
"hello", | |
"yo", | |
"sup", | |
"hey", | |
"suh") | |
states = ("how are you", | |
"how're you", | |
"are you okay", | |
"how do you feel", | |
"what's up", | |
"suh") | |
categories=(greeting, states) | |
matched=False | |
for greet in greeting: | |
if text.startswith(greet): | |
response = await get_response("GREETING") | |
matched=True | |
break | |
if not matched: | |
for state in states: | |
if text.startswith(state): | |
response = await get_response("STATE") | |
matched=True | |
break | |
response = await replacePlaceholders(response, message.author) | |
await client.send_message(message.channel, response) | |
################################################## |