Робот-самурай. Как научить телеграм-бота писать хокку

в 19:32, , рубрики: python, request, requests, telebot, telegram, telegram bots, telegrambot
Робот-самурай. Как научить телеграм-бота писать хокку - 1

Привет! Давно ничего не писал. Обещанного в прошло статье бота закончил, проект оказался довольно сложным, но опыта и знаний заметно прибавилось. А значит время начать новый проект! В этот раз, вдохновившись глубочайшими мыслями японских поэтов-философов, мы будем делать бота, который не просто постит хокку, а сам пишет и подбирает картинку по теме. Строго говоря, бот не придумывает хокку, а формирует новые из уже существующих, но хуже, как мне кажется, он от этого не становится. Итоговый код я оставлю на своём GitHub, а за работой бота можно следить в этом Телеграм канале. Подпишитесь, очень хочу, чтобы этот канал набрал аудиторию.

Робот-самурай. Как научить телеграм-бота писать хокку - 2

Готовый результат

Как это работает?

Первым делом нужно создать базу хокку, из которой наш бот будет брать строчки своих стихов. Для этого пришлось изучить несколько сотен хокку и выбрать подходящие. Вставляем всё в текстовый документ, чтобы у нас всегда была возможность добавить строки. Всего 1903 строки, так как хокку всегда состоят из трёх строк, то такого набора хватит на примерно столько вариантов:

Робот-самурай. Как научить телеграм-бота писать хокку - 3

Как вы уже могли догадаться, наш бот будет брать 3 случайных строки из списка и формировать из них хокку. Казалось бы, должно получиться нечто совсем бессмысленное, но учитывая специфику жанра, даже самые бредовые сочетания будут иметь (очень глубокий) смысл. С именами авторов мы поступим таким же образом, а год будем генерировать случайный от 0 до 2022 года (н.э или до н.э).

Код

В итоге у нас получилась такая функция:

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]}nn     - {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))

Про последние 4 строки подробнее далее.

Теперь наш бот способен выводить хокку, если прописать message внутрь bot.send_message. Примерно так:

Робот-самурай. Как научить телеграм-бота писать хокку - 4

Но так как нам этого мало, давайте научим бота отправлять нам картинку, желательно в той же стилистике и с соответствующей тематике.

Как вариант, можно было бы найти несколько изображений руками и выводить их в случайном порядке. Но так нам не получится сделать так, чтобы картинки соответствовали по смыслу тексту хокку. Поэтому мы будем искать (парсить) наши картинки в поиске Яндекса. На помощь нам тут приходит библиотека request и волшебный алгоритм, написанный давно моим близким другом.

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))]

Итак, ищем картинки в поиске, извлекаем ссылку из кода страницы и вуаля, бот вставляет случайную картинку. Чтобы содержание её соответствовало нашим стихам, посылаем поисковой запрос в форме 'Японская живопись + {строчка из хокку}'. То есть в 28-й строке функции hokky_bot м посылаем такой запрос в функцию picture (о ней далее), откуда мы отправляем наш запрос в функцию request_photo.

Штош, нам удалось сделать, чтобы бот выводил то что нам нужно.

Робот-самурай. Как научить телеграм-бота писать хокку - 5

Такой результат меня уже более чем устраивает, но как насчёт сделать из картинки полноценное изображение, содержащее хокку. Это позволит нам убрать текст из постов и улучшить общий вид изображений. Для этого нам и нужна функция picture.

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') # Цвет

В этом варианте решения мы записываем найденный запрос в файл img.jpg, после чего уже открываем для редактирования (библиотека Pillow), куда вставляем наш message.

В итоге после настройки и подбора разных шрифтов, лучшее что у меня вышло выглядит так:

Робот-самурай. Как научить телеграм-бота писать хокку - 6

Но тут уже не угадаешь, какое у нас будет изображение, тёмное или светлое, а фильтры и т.п. вставлять не хочется. Поэтому этот вариант мы оставим для других проектов, а пока довольствуемся результатом.

Всё! Ещё раз напоминаю, код проекта можно найти на GitHub.

Телеграм канал с хокку. Подпишитесь, мне будет очень приятно.

Если есть идеи, как можно доработать бота, делитесь в комментариях. Всем пока, до встречи в новых статьях!

Автор:
mogilyoy

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js