This commit is contained in:
JP
2018-11-26 21:41:43 +01:00
parent 00de2706c0
commit 85a26da108
+84 -1
View File
@@ -4,6 +4,7 @@ from discord.ext import commands
import numpy as np import numpy as np
import random import random
from datetime import datetime from datetime import datetime
import re
class Chatbot(object): class Chatbot(object):
"""Een heuse chatbot. Under construction...""" """Een heuse chatbot. Under construction..."""
@@ -274,7 +275,7 @@ class Chatbot(object):
responsePairDict = wordDict['responsePairs'] responsePairDict = wordDict['responsePairs']
#TODO store in global variable to minimise IO? #TODO store in global variable to minimise IO?
#Wtart with <SOM> #Start with <SOM>
chain = [self.START_OF_MESSAGE] chain = [self.START_OF_MESSAGE]
#Go through the chain: #Go through the chain:
@@ -328,3 +329,85 @@ class Chatbot(object):
#yield from ctx.channel.send(' '.join(chain)) #yield from ctx.channel.send(' '.join(chain))
return ' '.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 <SOM>
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)