By Parham Negahdar

Pretty little trees: how to write a Bob Ross Markov chain in python

I was going through my Github Gists recently and I stumbled on a funny one. It reminded why I loved python so much and how expressive it can be. With just a few lines of code you can get a decent Bob Ross markov chain going.

Before you ask "why!?", let me give some context.

  • Bob Ross is effin awesome
  • Bob Ross said the coolest things
  • Bob Ross is a legend

But more specifically I was working at Kensho and the DC office happened to name one of their suped up machine learning nodes "Bob Ross" with even a beautiful figurine of him in there. So while visiting I was inspired to write a Bob Ross slack bot that said Bob Ross things.

So how do we do it?

  1. Capture the great words of Bob Ross

  2. import markovify

  • Q: "But why not use X AI lib that was released 2 days ago with an amazing paper that's supposed to change humanity?"
  • A: I wanted to get back to work. And Markov chains are kinda funny.
  1. Generate chain

There might be a transcript archive Bob Ross sermons somewhere in the world that I don't know of (frankly there should be). But thanks to the kind people running this YouTube channel we have access to a ton of his videos AND Youtube exposes an API to get closed captions of them!

Here's how we do it:

from pytube import YouTube
import requests

# https://console.developers.google.com/apis/credentials/wizard?api=youtube.googleapis.com
YT_API_KEY = ''

def get_caption_body(video_id):
    video = YouTube('v={}'.format(video_id))
    caption_obj = video.captions.get_by_language_code('en')
    captions = caption_obj.generate_srt_captions()
    split_capts = captions.split('\n')
    # I don't recall why I did the following... code comments would've been helpful!
    return ' '.join([split_capts[i] for i in range(2, len(split_capts), 4)])

def get_ross_videos(count=200):
    results = {}
    page_token = None
    while len(results) <= count:
        params={'part': 'snippet',
                'maxResults': 50,
                'playlistId': 'UUxcnsr1R5Ge_fbTu5ajt8DQ',
                'key': YT_API_KEY,
        }
        if page_token:
            params['pageToken'] = page_token
        channel = requests.get('https://www.googleapis.com/youtube/v3/playlistItems', params=params)
        channel.raise_for_status()
        for x in channel.json()['items']:
            results[x['snippet']['title']] = x['snippet']['resourceId']['videoId']
            page_token = channel.json().get('nextPageToken')
            if not page_token:
                break
    return results

Now lets fetch the data:

bobs_good_word = {}
videos = get_ross_videos(50) # Lets only do 50 videos

for title, video_id in videos.items():
    if video_id in bobs_good_word:
        continue
        print "Already have video {}".format(video_id)
    try:
        bobs_good_word[video_id] = get_caption_body(video_id)
        print "Downloaded video {}".format(video_id)
    except Exception as e:
        print "Failed on video {} with err {}".format(video_id, e)

Make our markov chain:

import markovify
text_model = markovify.Text(' '.join(bobs_good_word.values()))

And boom that's all we need! Lets print some samples out

for i in range(100):
    print text_model.make_sentence()

Here are our results:

Now let's go up in here, it'll show.
Certainly glad you could actually make these big tree here, so you're to paint.
In short, perspective tells us as things get closer they get further up into the water.
Actually, I just absolutely love the little liner brush.
And there's a little of the brush, I'll go right up in here and there, just to close it off.
You notice I haven't loaded it as dark and light and as I say, they are in the woods in Florida.
I don't know where it goes, we'd have to be a little white, a little floral painting.
For many years ago.
I knew there was some of that brown color and let's go up in here.
Trying to keep that in mind, keep the bottom edge of the land, how you want it.
Maybe there's a little brighter, and we can begin putting in detail.
Let's put a little ridge.
Indian yellow, yellow ochre, some Indian Yellow right up through that lighter color, so pretty.
Gonna smoosh it right down the mountain.
So we're just looking for is the dark colors.
And we'll go right into there.
I'll show you here, today.
It's just a couple.
In here, tell you what, we'll just let them go where it's at, go back with a little bit down.
It comes right on top of that.
Let's take a little brighter, the paint thinner will leave it the same basic thing.
You make the indication of a little bit of water around here.
I'll make it look like a tree.
Lives right out of the colors across the top, and all that, usually it'll dry in about 15 to 30 minutes.
Let's take a very, very easy way of making a tree.
Take a liner brush has oval bristles on it with your own hand than something that might live in the middle.
Soon as we can go back in here, and I don't know, you gotta continually do.
By sickly, I mean, he looks like there's a little yellow ochre here and there.
Pull that paint back in the middle of a few highlights on this because sometimes if your brush to cut off a little of this, certainly with all this misty all over the country who are just using the ole oval brush.
You can get in here somewhere.
Barely touch, just enough to allow it to it very thin, thin coat of black right in there.
And let's go back later and use some phthalo green in there.
Oh yeah, that's nice.
It's just gonna let the bristles into it.
Take my little creatures, and God bless my friend. - Hi, welcome back, glad you could probably have, I don't have that old knife here.
That's basically all we need.
And from all of our painting when you do is take a clean brush here.
But, when you're painting, just transparent enough for what we're looking for.
If you want back here.
Just some little legs so he doesn't cut the barn door.
But isn't that a word?
Then we'll come right in here and get a little more crimson.
All right, let's put a little bit alizarin crimson.
We'll put a big mountain, that lives right there.
I'm gonna put a shed here.
We will use initials, and I've just made some little indications here of some happy little things that are far-far back.
And we'll take, and just beginning to see a lot of work.
OK, this is a canvas here that's too square.
Back over here and there.
It's really all we have here is just a little strange, but that's okay, painters are unique.
But very little, and we can add the, yeah, that's nice. pull it through the dark color, sort of wiggling the knife and just tap a little tree lives right here, just by changing that color.
So, we'll just use this warm brown.
Get our little fan brush today.
Painters are expected to be able to paint birch trees, isn't that a little water line right around like that much crimson.
I like a putty knife, that little rascal, don't want a few old limbs hanging out there somewhere.
I'm gonna start off and take him some hay.
Just to make those.
There, just fill it in.
Well, let's find some white, I'll be scratching a little dark, so if you enjoy it.
Just a little watery sounds when you're at the opening.
Right up here if I don't know, you certainly understand what he's doing, him and blend all that out of ten, there'd be a little roof.
There, don't wanna kill all the different planes, the layers and layers and layers and layers.
So we have liquid white in that.
I know it's interesting, over the top and work down, apply more pressure, and automatically, your tree as you know, in one direction, right through the entire canvas with a clean brush, we'll go up in here.
I want this painting very similar to this.
Little white with it at the bottom than they are at home, doesn't matter.
Hurt your eyes, have to make it sparkle.
Black, blue, crimson, and some yellow, load a lot of the easiest ways of making an old fence down here in all those little noises really do think this one is a different kind of looks like little leaf areas, and allowed the painting and you don't have to push upwards sometimes we push down with a fan brush and a cloud out of it.
There is no editing here.
There's another old big brush, decide what kind of letters from friends all over the top of here we'll just put it in there.
It's very nice, and wanted to and brighten those little trees right back in here.
Make this paint to dry very rapidly.
In your world, don't put too much.
So, we just shake off the excess paint and get lighter and lighter toward the base.
That easy We'll come back and put some of these little critters.
If you have to be very soft brush works so well, let's just make a nice misty effect, right down here in the winter and all of us here, I'd like to paint.
A little roll of paint, and maybe, now we'll just start right at the top corner I just wanna give some little grassy areas all up in here.
This little blender's wonderful for your bravery test.
We'll bright it right in here.
We're still using the top and we're to the top.
K. Maybe put a little happy cloud that lives right there, and they're just hanging there.
I'm just going to enjoy it.
These are too far away.
But more than this.
Let's take, we'll use the other side and go right in there and mist it.
Okay, a little bit that I had a round pull.
All we're looking for is basic shape when I'm doing here is just liquid white on the corner, and begin tapping in some paint thinner.
That dark color here, and it's a nice little painting.
That way you do such a temptation.
While I've got going up or anything.
And your brush downward you'll have immediate success.
That's all there is any.
Like there's all kinds of little different right in the series.
I put a bit of thalo blue in it.
We'll turn it over.
Grab old two-inch brush.
Maybe there's another little bush.
Sometime we push the little painting and God bless, my friend. - Hi, welcome back.
So now I have several of these trees.
Certainly glad you could make as many times as you can just put the least little touch of the waterfall, something about like that, this is very strong.

There you have it. In some ~50 lines of python code we download youtube video transcripts and make a Bob Ross markov chain.