def generateBestHaiku(headlines): """ Requires: headlines is a dictionary containing two lists, one that has all viable 5 syllable headlines, and one that has all 7 syllable headlines Effects: Returns a string with the 'best' haiku in it. """ linksFile = open('recentlyUsedLinks.txt', 'r') recentlyUsedLinks = eval(linksFile.read()) # Assume the baseline best score is 0 meaning that there are no 'errors' # with the haiku, but it likely isn't very interesting. bestHaikuScore = 0 # Although it doesn't necesarily make sense to keep track of ALL haiku # objects that are 'best' at some point, this helps massively with debugging bestHaikus = [] # This is not elegant or efficient at all, but it gets the job done and # we are not too concerned about how fast this code runs. # Gets the first line of the haiku from the list of 5 syllable phrases for firstLine in headlines['fiveSyllableLines']: # Gets the second line of the haiku from the list of 7 syllable phrases for secondLine in headlines['sevenSyllableLines']: # Gets the third line of the haiku from the list of 5 syllable phrases for thirdLine in headlines['fiveSyllableLines']: # Instantiation of a haiku object haiku = Haiku(firstLine, secondLine, thirdLine, recentlyUsedLinks) # Calculates the 'score' of the haiku, see class documentation haikuScore = haiku.getScore() # Checks if this haiku has a better score than the current best if haikuScore > bestHaikuScore: # This haiku is now the best, add to list and update score bestHaikus.append(haiku) bestHaikuScore = haikuScore # Returns last haiku in the list with the highest score as a string return bestHaikus[-1]
def test_phrase_splitting_multiple_prons(self): text = 'If you favorite that last tweet of mine you are the scum I called out' haiku = Haiku(text) self.assertEqual( haiku.formatted(), 'If you favorite / that last tweet of mine you are / the scum I called out' )
def __init__(self): # Authenticate to Twitter self.auth = tweepy.OAuthHandler(consumer_key, consumer_secret) self.auth.set_access_token(access_token, access_token_secret) # Create API object self.api = tweepy.API(self.auth, wait_on_rate_limit=True, wait_on_rate_limit_notify=True) self.haiku = Haiku()
def on_data(self, data): tweet = json.loads(data) try: haiku = Haiku(tweet['text']) if haiku.is_valid(): retweet = self._retweet_string(tweet, haiku) twitter.update_status(status=retweet) print retweet stream.disconnect() except Exception as e: print e
def get_haiku(subreddit): (history, num_comments, sentence_avg) = get_history(subreddit, 5000) my_haiku = Haiku(history) my_haiku.generateHaiku() haiku_list = my_haiku.getHaikuList() formatted_haiku = "" if haiku_list: # if list is not empty: for line in haiku_list: formatted_line = "> *" for word in line: formatted_line = "{}{} ".format(formatted_line, word) formatted_line = "{}* \n\n".format(formatted_line[:-1]) formatted_haiku = "{}{}".format(formatted_haiku, formatted_line) return formatted_haiku
class HaikuBot(SlackBot): def __init__(self, slack=None): self.haiku_name = 'Haiku' self.haiku_expr = CaselessLiteral('haiku') + StringEnd() self.haiku_doc = "Generate a random haiku." self.haiku = Haiku() @register(name='haiku_name', expr='haiku_expr', doc='haiku_doc') async def command_haiku(self, user, in_channel, parsed): return MessageCommand(text=self.haiku.generate_haiku(), channel=in_channel, user=user)
def test_formatter(gender, modifier, expected_num_skin_colors, expected_num_genders): """It's pretty hard to test that emojis are generated correctly, but it's easy to test that the formatting works, especially when you choose to force skin color or gender. So we do that here, probabilistically. """ # This is violating a bunch of the expectations of the Haiku class, but we can fix that if it's # a problem later. haiku = Haiku([[police_officer] * 5000], [[]]) emoji, desc = haiku.format(gender, modifier) characters = emoji.split() # There should be lots of different variants produced. assert len(set(characters)) == expected_num_genders * expected_num_skin_colors firsts, seconds = zip(*(c.split('\u200d') for c in characters)) # First part should have the skin color modifiers, so there should be 5 variants. # Probability that there isn't all 5 options out of 1000 tries is pretty low, but I don't want # to put in the effort to quantify it. assert len(set(firsts)) == expected_num_skin_colors # police_officer uses the SIGN gender mode, so splitting on the ZWJ character will give just the # gender options. Should be two. assert len(set(seconds)) == expected_num_genders
def procede(self, tweets, kigo): # Kigo self.kigo = kigo # Reinitializing haiku if self.haiku is None: self.haiku = Haiku(self.kigo) if self.haiku.isComplete(): self.haiku.reinit(self.kigo) # Launching Protocol Loop for tweet in tweets: # Filtering and Cleansing if self.filterTweet(tweet): tweet = self.cleanTweet(tweet) # Tokenization tokens = self.sentence_detector.tokenize(tweet) if self.isHaikuMaterial(tokens): return True return False
def test_formatter(gender, modifier, expected_num_skin_colors, expected_num_genders): """It's pretty hard to test that emojis are generated correctly, but it's easy to test that the formatting works, especially when you choose to force skin color or gender. So we do that here, probabilistically. """ # This is violating a bunch of the expectations of the Haiku class, but we can fix that if it's # a problem later. haiku = Haiku([[police_officer] * 5000], [[]]) emoji, desc = haiku.format(gender, modifier) characters = emoji.split() # There should be lots of different variants produced. assert len( set(characters)) == expected_num_genders * expected_num_skin_colors firsts, seconds = zip(*(c.split('\u200d') for c in characters)) # First part should have the skin color modifiers, so there should be 5 variants. # Probability that there isn't all 5 options out of 1000 tries is pretty low, but I don't want # to put in the effort to quantify it. assert len(set(firsts)) == expected_num_skin_colors # police_officer uses the SIGN gender mode, so splitting on the ZWJ character will give just the # gender options. Should be two. assert len(set(seconds)) == expected_num_genders
class TestHaiku(unittest.TestCase): def setUp(self): self.valid_haiku = Haiku('at the age old pond a frog leaps into water a deep resonance') self.valid_haiku_multiple_prons = Haiku('word word probably {0}'.format('word ' * 12)) self.invalid_haiku = Haiku('at the age old pond') self.tricky_invalid_haiku = Haiku('word word word elephant {0}'.format('word ' * 11)) self.haiku_with_oov = Haiku('at the age old pond a frog GROOOG leaps into water a deep resonance') def test_invalid_haiku(self): self.assertFalse(self.invalid_haiku.is_valid()) def test_valid_haiku(self): self.assertTrue(self.valid_haiku.is_valid()) def test_valid_haiku_multiple_prons(self): self.assertTrue(self.valid_haiku_multiple_prons.is_valid()) def test_right_syllables_wrong_phrasing(self): """ a potential haiku can have 17 syllables but a word that breaks between lines """ self.assertFalse(self.tricky_invalid_haiku.is_valid()) def test_oov_word(self): self.assertFalse(self.haiku_with_oov.is_valid()) def test_phrase_splitting(self): self.assertEqual( self.valid_haiku.formatted(), 'at the age old pond / a frog leaps into water / a deep resonance' ) def test_phrase_splitting_multiple_prons(self): text = 'If you favorite that last tweet of mine you are the scum I called out' haiku = Haiku(text) self.assertEqual( haiku.formatted(), 'If you favorite / that last tweet of mine you are / the scum I called out' )
def generate_haiku(): hk = str(Haiku()) response = hk.replace('\n', '<br>') haistorageadd.put_nowait(response) return {'haiku': response}
class Protocol(Model): ''' The aim of the Protocol class is to create a valid Haiku from the tweets it will receive. It will thus tokenize the tweets, counting their syllable and form the final haiku. ''' # Properties #------------ syl = None kigo = None haiku = None sentence_detector = None punctuation_re = r'[“?!.,;:\-_/()\[\]{}`"]|\'\'|[0-9]' # Tweet Filters filters = [ # Retweets lambda t: True if re.search(r'\bRT\b', t) is None else False # Empty ,lambda t: t.strip() != '' # Mad Hashtaggers ,lambda t: t.count('#') < 4 # Dropping tweets with filthy things such as usernames ,lambda t: True if re.search(r'\b\w[0-9_]+\w*\b', t) is None else False ] # Tweet Cleaners cleaners = [ # Dropping special characters lambda t: re.sub(re.compile('[^'+string.printable+']'), '', t) # Dropping urls, hashtags and addressing ,lambda t: re.sub(r'\bhttps?://.*\b', '', t) # Dropping hashtags and addressing ,lambda t: re.sub(r'#|@[^ ]?|\*', '', t) # Dropping htmlentities ,lambda t: re.sub(r'&.+?;', '', t) # Final Strip ,lambda t: t.rstrip().strip() ] # Constructor #------------ def __init__(self): # Initializing sylli self.syl = SylModule(self.settings.sonorities) # Initializing sentence tokenizer self.sentence_detector = nltk.data.load(self.settings.pickle) def procede(self, tweets, kigo): # Kigo self.kigo = kigo # Reinitializing haiku if self.haiku is None: self.haiku = Haiku(self.kigo) if self.haiku.isComplete(): self.haiku.reinit(self.kigo) # Launching Protocol Loop for tweet in tweets: # Filtering and Cleansing if self.filterTweet(tweet): tweet = self.cleanTweet(tweet) # Tokenization tokens = self.sentence_detector.tokenize(tweet) if self.isHaikuMaterial(tokens): return True return False # Methods #--------- def filterTweet(self, tweet): for filter in self.filters: if not filter(tweet): return False return True def cleanTweet(self, tweet): for cleaner in self.cleaners: tweet = cleaner(tweet) return tweet def isHaikuMaterial(self, tokens): # Looping through sentences for sentence in tokens: for semi_sentence in sentence.split(','): # Counter Init counter = 0 # To words and counting syllables semi_sentence = re.sub(self.punctuation_re, '', semi_sentence) words = nltk.word_tokenize(semi_sentence) # Counting Syllables for word in words: counter += self.countSyllables(word) # Keeping Relevant parts if counter >= 4 and counter < 6: self.haiku.setShortVerse(semi_sentence) else: if counter >= 6 and counter <= 8: self.haiku.setLongVerse(semi_sentence) if self.haiku.isComplete(): return True return False # Helpers #--------- def countSyllables(self, word, dict=None): return len(self.syl.syllabify(word).split('.'))
def test_syllable_return_values(self, string, syllables): """ verfies the expected number of syllables of an input str is returned """ haiku = Haiku(string) self.assertEqual(haiku.return_syllables(), syllables)
def test_input_too_long(self): """ verifies Assertion error is raised when string of 200+ chars is submitted """ long_str = "".join("a" for i in range(0, 201)) # 200 char string haiku = Haiku(long_str) with self.assertRaises(AssertionError): haiku.input_validation()
def test_input_validation(self, value): """ verifies the input validation raises an Assertion error when incorrect input is supplied """ haiku = Haiku(value) with self.assertRaises(AssertionError): haiku.input_validation()
def setUp(self): self.valid_haiku = Haiku('at the age old pond a frog leaps into water a deep resonance') self.valid_haiku_multiple_prons = Haiku('word word probably {0}'.format('word ' * 12)) self.invalid_haiku = Haiku('at the age old pond') self.tricky_invalid_haiku = Haiku('word word word elephant {0}'.format('word ' * 11)) self.haiku_with_oov = Haiku('at the age old pond a frog GROOOG leaps into water a deep resonance')
def __init__(self, slack=None): self.haiku_name = 'Haiku' self.haiku_expr = CaselessLiteral('haiku') + StringEnd() self.haiku_doc = "Generate a random haiku." self.haiku = Haiku()
from __future__ import print_function import json import codecs import sys from haiku import Haiku sys.stdout = codecs.getwriter("utf-8")(sys.stdout) sys.stderr = codecs.getwriter("utf-8")(sys.stderr) for line in open("sample"): if not line.strip(): continue tweet = json.loads(line) if not (tweet.get("lang") and tweet["lang"] == "en"): continue try: haiku = Haiku(tweet["text"]) if haiku.is_valid(): print(haiku.formatted()) except Exception as e: print("error: " + tweet["text"], file=sys.stderr) print(e, file=sys.stderr)
def on_status(self, status): haiku = Haiku() tweeter = status.author.screen_name.encode("utf-8") text = haiku.to_str('. ') + ' @' + tweeter api.update_status(status=text, in_reply_to_status_id=status.id)
class App: def __init__(self): # Authenticate to Twitter self.auth = tweepy.OAuthHandler(consumer_key, consumer_secret) self.auth.set_access_token(access_token, access_token_secret) # Create API object self.api = tweepy.API(self.auth, wait_on_rate_limit=True, wait_on_rate_limit_notify=True) self.haiku = Haiku() def listen_mentions(self): """ This method assigns a thread to listen for incoming mentions """ listener_thread = threading.Thread(target=self.get_mentions()) listener_thread.start() def get_mentions(self): """ This method sits and waits for any new mentions and replies with a haiku """ while (True): # retrieve recently replied to tweet ids with open('../data/recent_mentions.json', 'r') as r: recently_replied_to_mentions = json.load(r)["ids"] # reply to any tweets not already replied to for tweet in tweepy.Cursor(self.api.mentions_timeline).items(): if tweet.id not in recently_replied_to_mentions: self.reply_to_tweet(tweet.text.lower(), tweet.id) recently_replied_to_mentions.append(tweet.id) recently_replied_to_mentions.sort() # keep removing tweets from stored list until only 20 contained while len(recently_replied_to_mentions) > 20: recently_replied_to_mentions.pop() # update stored list with open('../data/recent_mentions.json', 'w') as outfile: to_store = {"ids": recently_replied_to_mentions} json.dump(to_store, outfile) # sleep for 20 seconds time.sleep(20) def reply_to_tweet(self, message, id): """ This method replies to a tweet, reply varies depending on what keywords are found in the message. """ reply_text = "" message = message.replace("@im_a_haiku_bot", "") print(message) if "what is a haiku" in message: reply_text = "A haiku is a short poem containing three phrases following a 5,7,5 syllable pattern." elif "haiku" in message: reply_text = self.get_haiku() else: reply_text = "Hello :)" self.api.update_status(status=reply_text, in_reply_to_status_id=id) def get_haiku(self): """ This method retrieves a haiku from haiku.py and tweets it. """ poem = self.haiku.generate_haiku() return poem def post_haiku_status(self, poem): """ This method retrieves haiku from get_haiku and tweets it """ self.api.update_status(status=poem)
def main(): haiku = Haiku() return render_template('index.html', line_1=haiku.line_generator(), line_2=haiku.line_generator(7), line_3=haiku.line_generator())