Samurai robot. How to teach a telegram bot to write haiku

Hey! Haven’t written anything for a long time. I finished the bot promised in the last article, the project turned out to be quite complicated, but experience and knowledge have noticeably increased. That means it’s time to start a new project! This time, inspired by the deepest thoughts of Japanese poets-philosophers, we will make a bot that not only posts haiku, but also writes and selects a picture on the topic. Strictly speaking, the bot does not invent hockey, but forms new ones from existing ones, but it doesn’t get any worse, as it seems to me, from this. I will leave the final code on my GitHuband you can follow the work of the bot in this Telegram channel. Subscribe, I really want this channel to gain an audience.

Finished result

How it works?

The first step is to create a haiku database from which our bot will take lines of his poems. To do this, I had to study several hundred haiku and choose the right ones. We paste everything into a text document so that we always have the opportunity to add lines. There are 1903 lines in total, since haiku always consist of three lines, this set is enough for about as many options:

As you might have guessed, our bot will take 3 random strings from the list and form haiku from them. It would seem that something completely meaningless should turn out, but given the specifics of the genre, even the most crazy combinations will have a (very deep) meaning. We will do the same with the names of the authors, and we will generate a random year from 0 to 2022 (AD or BC).

The code

As a result, we have such a function:

def hokky_bot():
    f = open('hokky.txt', 'r', encoding='UTF-8')  # Открываем файл с хокку
    all_hokky = f.read().split('\n')  # Записываем каждую строчку в отдульный элемент списка
    f.close()

    f = open('names.txt', 'r', encoding='UTF-8')  # То же самое для файла с именами
    all_names = f.read().split('\n')
    f.close()
    j = 0
    print('Power on!')   
    while j < 10000:
        a = randint(0,1)  # генерируем случайное число для вставки н.э или до н.э.
        if a == 1:
            era="до н.э."
        else: 
            era="н.э"
        i =0 
        name = [1, 2, 3]
        text = [1, 2, 3]
        while i<=2: 
            name[i] = all_names[randint(1, len(all_names)-1)]  # Формируем списки из 3 строчек хокку и 3-х имён
            text[i] = all_hokky[randint(1, len(all_hokky)-1)] 
            i += 1
        message = (f'{text[0]}\n{text[1]}\n{text[2]}\n\n     - {name[0].title()} {name[1].title()} {name[2].title()}, {randint(0, 2022)} г. {era}')
        j += 1
        search = text[randint(0,2)] 
        print(f'Японская живопись {search}')
        picture(message, search)
        time.sleep(randint(28800, 57600))

More about the last 4 lines below.

Now our bot is able to output haiku if we write message inside bot.send_message. More or less like this:

But since this is not enough for us, let’s teach the bot to send us a picture, preferably in the same style and with the appropriate theme.

Alternatively, it would be possible to find several images by hand and display them in random order. But in this way we will not be able to make the pictures correspond in meaning to the haiku text. Therefore, we will search (parse) our pictures in Yandex search. The request library and a magical algorithm written by a close friend of mine for a long time come to our aid here.

def request_photo(message):
    req = requests.get("https://yandex.ru/images/search?text="+message)
    ph_links = list(filter(lambda x: '.jpg' in x, re.findall('''(?<=["'])[^"']+''', req.text)))
    ph_list = []
    for i in range(len(ph_links)):
        if (ph_links[i][0] == "h"):
            ph_list.append(ph_links[i])
    del ph_links
    return ph_list[randint(0, len(ph_list))]

So, we look for pictures in the search, extract the link from the page code and voila, the bot inserts a random picture. To make its content match our poems, we send a search query in the form ‘Japanese painting + {line from haiku}’. That is, in the 28th line of the hokky_bot function, we send such a request to the picture function (about it later), from where we send our request to the request_photo function.

Shtosh, we managed to make the bot display what we need.

This result is already more than satisfactory for me, but how about making a full-fledged image containing haiku from the picture. This will allow us to remove text from the posts and improve the overall look of the images. For this we need the picture function.

def picture(message, search):
    # Код для вставки своего хокку в изображение из request_photo

    im = requests.get(request_photo('японcкая живопись'))  
    out = open("img.jpg", "wb")
    out.write(im.content)
    out.close()
    image = Image.open('img.jpg')

    # Создаем объект со шрифтом
    font = ImageFont.truetype('font.name', size= int(image.width/15))
    draw_text = ImageDraw.Draw(image)
    draw_text.text(
        (int(image.width/50), int(image.height/4)),
        message,
        # Добавляем шрифт к изображению
        font=font,
        fill="#d60000") # Цвет

In this solution, we write the found request to the img.jpg file, after which we open it for editing (Pillow library), where we insert our message.

As a result, after setting up and selecting different fonts, the best that I got looks like this:

But here you can’t guess what kind of image we will have, dark or light, and filters, etc. do not want to insert. Therefore, we will leave this option for other projects, but for now we are satisfied with the result.

Everything! Once again, the project code can be found at GitHub.

Telegram channel with haiku. Subscribe, I will be very pleased.

If you have any ideas on how to improve the bot, share it in the comments. Bye everyone, see you in the next article!

Similar Posts

Leave a Reply