Note: this bot was repurposed in 2015. Twitter doesn’t like to verify my phone number, and you need a verified account to use the API, so occasionally once a bot has served its purpose I’ll reuse the authenticated account for something else.

Just finished yet another cool/completely useless Twitter bot, @rap_haiku. It scrapes the lyrics from a given rapper, feeds them into the Marky Markov gem, and spits out a haiku:

an example post from rap haiku bot

First I get a list of songs from Rapgenius using the gem of the same name:

def get_songs
    @songs = RapGenius.search_by_artist(@artist)

Then I run through each line of the songs one at a time, adding them as strings to the temporary Markov dictionary:

 def add_lines_to_dict
    @songs.each do |song|
      song.lines.each do |line|
        @dict.parse_string(line.lyric) if line.lyric[0] != "["

Once we have a temporary dictionary that should theoretically be able to create sentences that sound a lot like the rapper in question, make the beginnings of a haiku by generating three lines, each with a random number of words up to seven.

    line1 = @dict.generate_n_words(rand(1..7))
    line2 = @dict.generate_n_words(rand(1..7))
    line3 = @dict.generate_n_words(rand(1..7))

Finally, we need to make sure each line has the proper number of syllables. We’ll run an until loop that will continue to generate short, random sentences from the temporary dictionary until it comes up with one that is the right number of syllables (as per the ruby_rhymes gem’s syllable detection):

    until line1.to_phrase.syllables == 5
      line1 = @dict.generate_n_words(rand(1..5))

Once we have the 5-7-5 haiku we pass the artist and the three lines to a formatter that makes it look pretty for Twitter (and tags the username of the requester if there was one):

 def self.format_for_twitter(args)
    haiku_array = args[:haiku_array]!{|string| string.downcase}
    artist = "#" + haiku_array.shift.gsub(/\W/, "")
    haiku_array << "\n / #raphaiku / by #{artist}"
    if args[:request]
      haiku_array << "/ requested by @#{args[:request]}"
    return haiku_array.join("\n")

The bot checks on itself every ten minutes. If there are any requests in the last ten minutes it will fill them, and if not it ‘rolls the dice’ to see if it should generate a haiku from a precompiled list of rappers I included:

num = rand(0..13)
      if num == 7
        puts "jackpot!"
        puts "not this time, cowboy"

It still tweets quite a bit but there’s an element of randomness so you never know exactly when it’ll hit you with an excellent rap haiku.

The one problem at this point is the syllable detection I’m using. It has trouble with numbers (“3”), hyphenated words (“Jay-Z”) and nicknames (“MJ”), so occasionally the haikus aren’t quite a perfect 5-7-5. I’m looking into alternate methods of syllable counting so hopefully I can take care of all the edge cases and we’ll get exact 5-7-5 haikus every time.

Check out @rap_haiku on github.