diff --git a/Chatbot.py b/Chatbot.py index e5be78f..3281e74 100644 --- a/Chatbot.py +++ b/Chatbot.py @@ -4,6 +4,7 @@ from discord.ext import commands import numpy as np import random from datetime import datetime +import re class Chatbot(object): """Een heuse chatbot. Under construction...""" @@ -274,7 +275,7 @@ class Chatbot(object): responsePairDict = wordDict['responsePairs'] #TODO store in global variable to minimise IO? - #Wtart with + #Start with chain = [self.START_OF_MESSAGE] #Go through the chain: @@ -327,4 +328,86 @@ class Chatbot(object): #print(' '.join(chain)) #yield from ctx.channel.send(' '.join(chain)) return ' '.join(chain) + + + + + #Try to count the number of syllables in a word + #Used to make Haikus + def countSyllables(self, word: str): + KNOWN_ACRONYMS = ["aub", "svp", "ivm", "nr", "zsm", "mbt", "tmi", "fyi", "afk", "omg", "idk", "coc"] + word = word.lower().strip() + + #for acryonyms, just count the letters: + if word in KNOWN_ACRONYMS or re.match("^([a-z]{1}[.]{1}){2,}$", word) or re.match("^([bcdfghjklmnpqrstvwxz]){2,}$", word): + return len(word.replace(".", "")) + + #count vowels surrounded by consonants + count = len(re.findall("[bcdfghjklmnpqrstvwxyz]{1}[aeiouyëäïöüéèáà]{1,2}[bcdfghjklmnpqrstvwxz]{0,1}|[aeiouyëäïöüéèáà]{1,2}[bcdfghjklmnpqrstvwxz]{1}", word)) + count += len(re.findall("[ëäï]", word)) #ideeën etc + + return max(1, count) + + #Append a message change with a numer of syllables + #If it returns False, it couldn't find anything + #It's recursive, yo + def appendMessageWithNrOfSyllables(self, nrOfSyl: int, chain, wordPairDict): + #Find the possibilities: + if chain[-1] == "\n": + pairPossibilities = wordPairDict[chain[-2]].copy() + else: + pairPossibilities = wordPairDict[chain[-1]].copy() + + for poss in list(pairPossibilities.keys()): + if self.countSyllables(poss) > nrOfSyl or poss == self.END_OF_MESSAGE: #TODO change to constant + del pairPossibilities[poss] + + if len(pairPossibilities) == 0: + return False + + #Calculate probabilities and pick a next word: + possible_words = list(pairPossibilities.keys()) + weights = np.array(list(pairPossibilities.values())) + probs = weights / weights.sum() + chain.append(np.random.choice(possible_words, p=probs)) + #TODO this is duplicate code. reuse the stuff from getResponseForMessage() + + if self.countSyllables(chain[-1]) == nrOfSyl: + return chain + #RECURSION! + return self.appendMessageWithNrOfSyllables( (nrOfSyl-self.countSyllables(chain[-1])) , chain, wordPairDict) + + #Make a nice Haiku + def getHaiku(self): + MAX_N_TRIES = 50 + + #Get dictionary/Markov chain + wordDict = np.load('markov_dict.npy').item() + wordPairDict = wordDict['pairs'] + + #try: + for i in range(1, MAX_N_TRIES): + chain = [self.START_OF_MESSAGE] + + chain = self.appendMessageWithNrOfSyllables(5, chain, wordPairDict) + if chain is not False: + chain.append("\n") + chain = self.appendMessageWithNrOfSyllables(7, chain, wordPairDict) + if chain is not False: + chain.append("\n") + chain = self.appendMessageWithNrOfSyllables(5, chain, wordPairDict) + if chain is not False: + break + + chain = chain[1:] #remove + return ' '.join(chain) + + @commands.command(pass_context=True, hidden=False) + @asyncio.coroutine + def haiku(self, ctx): + """Stroop is een poëet. Laat hem een Haiku maken. + """ + + response = self.getHaiku() + yield from ctx.channel.send(response) \ No newline at end of file