예제 #1
0
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]
예제 #2
0
 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'
     )
예제 #3
0
    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()
예제 #4
0
    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
예제 #5
0
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
예제 #6
0
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)
예제 #7
0
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
예제 #8
0
    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
예제 #9
0
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
예제 #10
0
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'
        )
예제 #11
0
def generate_haiku():
    hk = str(Haiku())
    response = hk.replace('\n', '<br>')
    haistorageadd.put_nowait(response)
    return {'haiku': response}
예제 #12
0
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('.'))
예제 #13
0
 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)
예제 #14
0
 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()
예제 #15
0
 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()
예제 #16
0
 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')
예제 #17
0
    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()
예제 #18
0
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)
예제 #19
0
 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)
예제 #20
0
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)
예제 #21
0
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())