Try to respond to the previous message

This commit is contained in:
JP
2018-07-05 22:22:13 +02:00
parent 0c0703ee33
commit 4f2b32e38a
+97 -19
View File
@@ -16,7 +16,7 @@ class Chatbot(object):
np.load('markov_dict.npy')
except FileNotFoundError:
#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)
except:
print("ERROR! - Could not open or create Markov chat file")
@@ -39,9 +39,9 @@ class Chatbot(object):
#Learn from a human message
#Returns an updated dict
def learnFrom(self, wordDict, message: str):
newPairDict = wordDict['pairs']
newTrairDict = wordDict['trairs']
def learnFrom(self, wordDictPairs, wordDictTrairs, message: str):
newPairDict = wordDictPairs
newTrairDict = wordDictTrairs
message = self.START_OF_MESSAGE + " " + message + " " + self.END_OF_MESSAGE
corpus = message.split()
@@ -67,7 +67,42 @@ class Chatbot(object):
else:
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)
@asyncio.coroutine
@@ -82,30 +117,55 @@ class Chatbot(object):
wordDict = np.load('markov_dict.npy').item()
#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):
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 = messageContent.strip()
if messageContent == "":
pass #print("-- Bericht is leeg. Negeer.")
pass # Bericht is leeg. Negeer.
elif msg.author.bot:
pass #print("-- Dit is een bot chat. Negeer.")
pass # Dit is een bot chat. Negeer.
elif messageContent[0] == "!":
pass #print("-- Dit is een commando. Negeer.")
pass # Dit is een commando. Negeer.
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:
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)
yield from ctx.channel.send("Ik heb weer wat nieuwe woordjes geleerd. :slight_smile:")
@commands.command(pass_context=True, hidden=False)
@asyncio.coroutine
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.
"""
@@ -115,19 +175,30 @@ class Chatbot(object):
wordDict = np.load('markov_dict.npy').item()
wordPairDict = wordDict['pairs']
wordTrairDict = wordDict['trairs']
responsePairDict = wordDict['responsePairs']
#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
try:
yield from ctx.message.delete()
except:
print("No permission to delete message")
#print(wordDict)
pass
#Pick a random first word (Which is not an end-of-message)
#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:
first_word = np.random.choice(list(wordPairDict.keys()))
while first_word == self.END_OF_MESSAGE:
@@ -135,8 +206,6 @@ class Chatbot(object):
else:
first_word = self.START_OF_MESSAGE
chain = [first_word]
#TODO pick a word which responds to the previous message in the channel
#Go through the chain:
for i in range(1, MAX_N_WORDS):
@@ -145,6 +214,14 @@ class Chatbot(object):
#Find the possibilities:
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 chain[-2] in wordTrairDict:
trairPossibilities = wordTrairDict[chain[-2]].copy()
@@ -152,6 +229,7 @@ class Chatbot(object):
for word2 in pairPossibilities.keys():
if word2 in trairPossibilities.keys():
pairPossibilities[word2] += trairPossibilities[word2]
#Calculate probabilities and pick a next word:
#https://stackoverflow.com/questions/835092/python-dictionary-are-keys-and-values-always-the-same-order
possible_words = list(pairPossibilities.keys())