Try to respond to the previous message
This commit is contained in:
+97
-19
@@ -16,7 +16,7 @@ class Chatbot(object):
|
|||||||
np.load('markov_dict.npy')
|
np.load('markov_dict.npy')
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
#If there's no initial file, make a new one:
|
#If there's no initial file, make a new one:
|
||||||
initFile = {'pairs':{self.START_OF_MESSAGE:{'Hoi':1},'Hoi':{self.END_OF_MESSAGE:1}}, 'trairs':{}}
|
initFile = {'pairs':{self.START_OF_MESSAGE:{'Hoi':1},'Hoi':{self.END_OF_MESSAGE:1}}, 'trairs':{}, 'responsePairs':{}}
|
||||||
np.save("markov_dict.npy", initFile)
|
np.save("markov_dict.npy", initFile)
|
||||||
except:
|
except:
|
||||||
print("ERROR! - Could not open or create Markov chat file")
|
print("ERROR! - Could not open or create Markov chat file")
|
||||||
@@ -39,9 +39,9 @@ class Chatbot(object):
|
|||||||
|
|
||||||
#Learn from a human message
|
#Learn from a human message
|
||||||
#Returns an updated dict
|
#Returns an updated dict
|
||||||
def learnFrom(self, wordDict, message: str):
|
def learnFrom(self, wordDictPairs, wordDictTrairs, message: str):
|
||||||
newPairDict = wordDict['pairs']
|
newPairDict = wordDictPairs
|
||||||
newTrairDict = wordDict['trairs']
|
newTrairDict = wordDictTrairs
|
||||||
|
|
||||||
message = self.START_OF_MESSAGE + " " + message + " " + self.END_OF_MESSAGE
|
message = self.START_OF_MESSAGE + " " + message + " " + self.END_OF_MESSAGE
|
||||||
corpus = message.split()
|
corpus = message.split()
|
||||||
@@ -67,7 +67,42 @@ class Chatbot(object):
|
|||||||
else:
|
else:
|
||||||
newTrairDict[word_1] = {word_3 : 1}
|
newTrairDict[word_1] = {word_3 : 1}
|
||||||
|
|
||||||
return {'pairs':newPairDict, 'trairs':newTrairDict};
|
return newPairDict, newTrairDict;
|
||||||
|
|
||||||
|
#Learn to respond to messages
|
||||||
|
#Returns ???
|
||||||
|
def learnResponse(self, wordDictResp, message1: str, message2: str):
|
||||||
|
STOP_WORDS = ["aan", "achter", "al", "ben", "dan", "dat", "de", "die", "dit", "een", "en", "er", "gehad", "had", "heb",
|
||||||
|
"hen", "het", "hun", "in", "is", "kon", "met", "na", "of", "om", "ook", "op", "tot", "van", "was", "wat", "zo",
|
||||||
|
"a", "an", "the", "am", "was", "were", "be", "not", "at"]
|
||||||
|
|
||||||
|
newRespPairDict = wordDictResp
|
||||||
|
|
||||||
|
#Split messages into words and remove stopwords:
|
||||||
|
message1List = []
|
||||||
|
message2List = []
|
||||||
|
for word in message1.split():
|
||||||
|
if word not in STOP_WORDS:
|
||||||
|
message1List.append(word)
|
||||||
|
for word in message2.split():
|
||||||
|
if word not in STOP_WORDS:
|
||||||
|
message2List.append(word)
|
||||||
|
|
||||||
|
#link words of response to words of initial message
|
||||||
|
for word_1 in message1List:
|
||||||
|
for word_2 in message2List:
|
||||||
|
if word_1 in newRespPairDict.keys():
|
||||||
|
if word_2 in newRespPairDict[word_1].keys():
|
||||||
|
newRespPairDict[word_1][word_2] += 1
|
||||||
|
else:
|
||||||
|
newRespPairDict[word_1][word_2] = 1
|
||||||
|
else:
|
||||||
|
newRespPairDict[word_1] = {word_2 : 1}
|
||||||
|
|
||||||
|
return newRespPairDict
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@commands.command(pass_context=True, hidden=True)
|
@commands.command(pass_context=True, hidden=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
@@ -82,30 +117,55 @@ class Chatbot(object):
|
|||||||
wordDict = np.load('markov_dict.npy').item()
|
wordDict = np.load('markov_dict.npy').item()
|
||||||
|
|
||||||
#Iterate through the last x messages from the channel:
|
#Iterate through the last x messages from the channel:
|
||||||
iterator = channel.history(limit=nrOfMessages, before=None, after=None, reverse=False, around=None)
|
messageIterator = channel.history(limit=nrOfMessages, before=None, after=None, reverse=False, around=None)
|
||||||
|
allMessages = []
|
||||||
for i in range(nrOfMessages):
|
for i in range(nrOfMessages):
|
||||||
msg = yield from iterator.next()
|
msg = yield from messageIterator.next()
|
||||||
|
allMessages.append(msg)
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
nextMessageIndex = -10
|
||||||
|
#Note: the loop goes from new to old
|
||||||
|
for msg in allMessages:
|
||||||
messageContent = msg.content.replace('(', '').replace(')', '').replace('"', '')
|
messageContent = msg.content.replace('(', '').replace(')', '').replace('"', '')
|
||||||
messageContent = messageContent.strip()
|
messageContent = messageContent.strip()
|
||||||
|
|
||||||
if messageContent == "":
|
if messageContent == "":
|
||||||
pass #print("-- Bericht is leeg. Negeer.")
|
pass # Bericht is leeg. Negeer.
|
||||||
elif msg.author.bot:
|
elif msg.author.bot:
|
||||||
pass #print("-- Dit is een bot chat. Negeer.")
|
pass # Dit is een bot chat. Negeer.
|
||||||
elif messageContent[0] == "!":
|
elif messageContent[0] == "!":
|
||||||
pass #print("-- Dit is een commando. Negeer.")
|
pass # Dit is een commando. Negeer.
|
||||||
elif "```" in messageContent:
|
elif "```" in messageContent:
|
||||||
pass #print("-- Daar zit een codeblok in. Negeer.")
|
pass # Daar zit een codeblok in. Negeer.
|
||||||
|
elif messageContent[0:7] == "http://" or messageContent[0:8] == "https://":
|
||||||
|
pass # Een link. Negeer. TODO: post af en toe een random link die geen repost is
|
||||||
else:
|
else:
|
||||||
wordDict = self.learnFrom(wordDict, messageContent)
|
# Usable message!
|
||||||
|
wordDict['pairs'], wordDict['trairs'] = self.learnFrom(wordDict['pairs'], wordDict['trairs'], messageContent)
|
||||||
|
|
||||||
|
if (i-nextMessageIndex) == 1 and msg.author != nextMessage.author: #the previous usable messages was the one right after this one and was not from the same author
|
||||||
|
timeDelta = nextMessage.created_at - msg.created_at
|
||||||
|
#TODO check for different author
|
||||||
|
if timeDelta.days == 0 and timeDelta.seconds < 3600: #less than an hour difference
|
||||||
|
#this is counted as a response. learn from it
|
||||||
|
wordDict['responsePairs'] = self.learnResponse(wordDict['responsePairs'], messageContent, nextMessageContent)
|
||||||
|
|
||||||
|
#save for next iteration:
|
||||||
|
nextMessage = msg
|
||||||
|
nextMessageContent = messageContent
|
||||||
|
nextMessageIndex = i
|
||||||
|
i += 1
|
||||||
|
|
||||||
np.save("markov_dict.npy", wordDict)
|
np.save("markov_dict.npy", wordDict)
|
||||||
|
|
||||||
yield from ctx.channel.send("Ik heb weer wat nieuwe woordjes geleerd. :slight_smile:")
|
yield from ctx.channel.send("Ik heb weer wat nieuwe woordjes geleerd. :slight_smile:")
|
||||||
|
|
||||||
|
|
||||||
@commands.command(pass_context=True, hidden=False)
|
@commands.command(pass_context=True, hidden=False)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def reageer(self, ctx):
|
def reageer(self, ctx):
|
||||||
"""UNDER CONSTRUCTION. Laat Stroop iets willekeurigs zeggen.
|
"""UNDER CONSTRUCTION. Laat Stroop ergens op reageren.
|
||||||
Stroop leert van onze gesprekken. Hij kan zich nu voordoen als een van ons. Soort van.
|
Stroop leert van onze gesprekken. Hij kan zich nu voordoen als een van ons. Soort van.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -115,19 +175,30 @@ class Chatbot(object):
|
|||||||
wordDict = np.load('markov_dict.npy').item()
|
wordDict = np.load('markov_dict.npy').item()
|
||||||
wordPairDict = wordDict['pairs']
|
wordPairDict = wordDict['pairs']
|
||||||
wordTrairDict = wordDict['trairs']
|
wordTrairDict = wordDict['trairs']
|
||||||
|
responsePairDict = wordDict['responsePairs']
|
||||||
#TODO store in global variable to minimise IO?
|
#TODO store in global variable to minimise IO?
|
||||||
|
|
||||||
|
#Get previous message to respond to
|
||||||
|
messageIterator = ctx.channel.history(limit=3, before=None, after=None, reverse=False, around=None)
|
||||||
|
messageToRespondTo = yield from messageIterator.next() #this will be the !reageer command. skip
|
||||||
|
messageToRespondTo = yield from messageIterator.next()
|
||||||
|
if messageToRespondTo.content.strip()[0] == '!' or messageToRespondTo.author.bot: #another chance
|
||||||
|
messageToRespondTo = yield from messageIterator.next() #but it's not a huge problem if he responds to himself
|
||||||
|
if messageToRespondTo.content.strip()[0] == '!':
|
||||||
|
wordsToRespondTo = []
|
||||||
|
else:
|
||||||
|
wordsToRespondTo = messageToRespondTo.content.strip().split()
|
||||||
|
#print("respond to: ", wordsToRespondTo)
|
||||||
|
|
||||||
#Delete command
|
#Delete command
|
||||||
try:
|
try:
|
||||||
yield from ctx.message.delete()
|
yield from ctx.message.delete()
|
||||||
except:
|
except:
|
||||||
print("No permission to delete message")
|
pass
|
||||||
|
|
||||||
#print(wordDict)
|
|
||||||
|
|
||||||
#Pick a random first word (Which is not an end-of-message)
|
#Pick a random first word (Which is not an end-of-message)
|
||||||
#Usually, we start with a regular <SOM>, but sometimes we don't
|
#Usually, we start with a regular <SOM>, but sometimes we don't
|
||||||
a = random.randint(1,10)
|
a = random.randint(1,15)
|
||||||
if a == 1:
|
if a == 1:
|
||||||
first_word = np.random.choice(list(wordPairDict.keys()))
|
first_word = np.random.choice(list(wordPairDict.keys()))
|
||||||
while first_word == self.END_OF_MESSAGE:
|
while first_word == self.END_OF_MESSAGE:
|
||||||
@@ -135,8 +206,6 @@ class Chatbot(object):
|
|||||||
else:
|
else:
|
||||||
first_word = self.START_OF_MESSAGE
|
first_word = self.START_OF_MESSAGE
|
||||||
chain = [first_word]
|
chain = [first_word]
|
||||||
#TODO pick a word which responds to the previous message in the channel
|
|
||||||
|
|
||||||
|
|
||||||
#Go through the chain:
|
#Go through the chain:
|
||||||
for i in range(1, MAX_N_WORDS):
|
for i in range(1, MAX_N_WORDS):
|
||||||
@@ -145,6 +214,14 @@ class Chatbot(object):
|
|||||||
|
|
||||||
#Find the possibilities:
|
#Find the possibilities:
|
||||||
pairPossibilities = wordPairDict[chain[-1]].copy()
|
pairPossibilities = wordPairDict[chain[-1]].copy()
|
||||||
|
|
||||||
|
#Increase score if it would be a good response:
|
||||||
|
for userWord in wordsToRespondTo:
|
||||||
|
if userWord in responsePairDict:
|
||||||
|
for goodResponseWord in responsePairDict[userWord]:
|
||||||
|
if goodResponseWord in pairPossibilities.keys():
|
||||||
|
pairPossibilities[goodResponseWord] += responsePairDict[userWord][goodResponseWord]
|
||||||
|
#Increase score for trairs:
|
||||||
if i > 1: #we can only compare trairs if we have at least two words already
|
if i > 1: #we can only compare trairs if we have at least two words already
|
||||||
if chain[-2] in wordTrairDict:
|
if chain[-2] in wordTrairDict:
|
||||||
trairPossibilities = wordTrairDict[chain[-2]].copy()
|
trairPossibilities = wordTrairDict[chain[-2]].copy()
|
||||||
@@ -152,6 +229,7 @@ class Chatbot(object):
|
|||||||
for word2 in pairPossibilities.keys():
|
for word2 in pairPossibilities.keys():
|
||||||
if word2 in trairPossibilities.keys():
|
if word2 in trairPossibilities.keys():
|
||||||
pairPossibilities[word2] += trairPossibilities[word2]
|
pairPossibilities[word2] += trairPossibilities[word2]
|
||||||
|
|
||||||
#Calculate probabilities and pick a next word:
|
#Calculate probabilities and pick a next word:
|
||||||
#https://stackoverflow.com/questions/835092/python-dictionary-are-keys-and-values-always-the-same-order
|
#https://stackoverflow.com/questions/835092/python-dictionary-are-keys-and-values-always-the-same-order
|
||||||
possible_words = list(pairPossibilities.keys())
|
possible_words = list(pairPossibilities.keys())
|
||||||
|
|||||||
Reference in New Issue
Block a user