Haiku
This commit is contained in:
+84
-1
@@ -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 <SOM>
|
||||
#Start with <SOM>
|
||||
chain = [self.START_OF_MESSAGE]
|
||||
|
||||
#Go through the chain:
|
||||
@@ -328,3 +329,85 @@ class Chatbot(object):
|
||||
#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 <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)
|
||||
|
||||
Reference in New Issue
Block a user