Ques/Help/Req Аналог проекта Place Reddit в виде Telegram-бота

XakeR

Member
Регистрация
13.05.2006
Сообщения
1 912
Реакции
0
Баллы
16
Местоположение
Ukraine
Многие помнят проект place, запущенный однажды на Reddit и собравший вокруг себя немало поклонников. Суть предельно проста: раз в пять минут можно закрасить один пиксель на поле 1000×1000 пикселей в свой цвет. Я решил попробовать создать бота в телеграмм с точно такой же функцией, а также что-нибудь порисовать…

Вступление​


Статья носит познавательно-обучающий характер, и вот то, что можно из неё извлечь:

  • Библиотека telebot даёт возможность создания телеграм бота а также отслеживания команд с использованием @bot.message_handler(commands=[]) и текста с использованием @bot.message_handler(content_types=[‘text’]).
  • Библиотека telebot даёт возможность отправки сообщений с использованием bot.send_message(message.chat.id, text = «») и фото с помощью bot.send_photo(message.chat.id, img).
  • Библиотека pickle позволяет просто сохранять данные в файле с помощью pickle.dump() и извлекать оттуда используя pickle.load().
  • С помощью pillow можно создавать изображения используя Image.new() и изменять цвет отдельных пикселей используя img.putpixel().
  • Как писать текст с помощью PyAutoGUI.
  • Статья также позволяет изучить работу time.time() и создание простого таймера с её использованием.

Код бота​


Для бота я буду использовать библиотеки (некоторые из них необходимо установить через pip install)(telebot, pillow):

import telebot # для бота import pickle # для открытия файла с цветами поля from pathlib import Path # для удаления неугодного файла from PIL import Image # для отправки холста пользователю import time # для высчитывания времени межу изменениями цвета

Зададим значение переменных:

st = time.time() — 100 # переменная измерения времени и его ограничения l = 100 # ширина и высота поля h = 7 # размер пикселя на изображении

Запишем в data данные из файла, который мы потом создадим (содержит цвета пикселей):

data = [] try: with open(«data.pickle», «rb») as f: data = pickle.load(f) except Exception as ex: print(«Error during unpickling object (Possibly unsupported):», ex)

Запишем токен бота сюда:

bot = telebot.TeleBot(‘токен’)

Как его получить.

Теперь сделаем объяснение работы бота и отправку текущего изображения поля по команде start:

@bot.message_handler(commands=[‘start’]) # отслеживание команды def start(message): # пояснения: bot.send_message(message.chat.id, text=»Вы находитесь в боте для группового рисования картины. В этом боте вы можете внести свой вклад в сетевой холст, на котором рисуют и другие люди. Вы можете изменить цвет одного из пикселей раз в 10 секунд. Так вы можете рисовать свои шедеврыы, но учтите, что их могут изменять другие люди.») bot.send_message(message.chat.id, text = «Чтобы провести все вышеописанные операции, необходимо отправить мне цвет пикселя в формате: x, y, красный, зелёный, синий (через запятую, без пробелов). Причём ширина поля 0-99, длина 0-99, максимальное значение каждого из цветов 255, минимальное 0. Например:») bot.send_message(message.chat.id, text = «0,0,255,255,255») bot.send_message(message.chat.id, text = «Отправь ‘к’ чтобы увидеть полученное изображение.») # берём данные из файла try: with open(«data.pickle», «rb») as f: data = pickle.load(f) except Exception as ex: print(«Error during unpickling object (Possibly unsupported):», ex) # создаём изображение с pillow img = Image.new(«RGB», (l*h, l*h), ‘black’) for i in range(l): # для каждого пикселя поля for j in range(l): # если data[i*l + j] является не нулём try: # рисуем квадрат hхh for i1 in range(h): for j1 in range(h): img.putpixel((i*h +i1, j*h +j1), tuple(data[i*l + j])) # иначе ничего не делаем (имитация бурной деятельности): except TypeError: if j // 2000 == 3: print(«0») bot.send_photo(message.chat.id, img) # отправляем полученное изображение

Далее отслеживаем любой текст от пользователя и в случае необходимости отправляем картинку:

@bot.message_handler(content_types=[‘text’]) # отслеживаем текст def func(message): # если пользователь просит изображение поля if message.text == «к» or message.text == «k» or message.text == «К»: # берём данные из файла (обновляем) try: with open(«data.pickle», «rb») as f: data = pickle.load(f) except Exception as ex: print(«Error during unpickling object (Possibly unsupported):», ex) # создаём изображение с pillow img = Image.new(«RGB», (l*h, l*h), ‘black’) for i in range(l): # для каждого пикселя поля for j in range(l): # если data[i*l + j] является не нулём (изменялся хоть раз) try: # рисуем квадрат hхh for i1 in range(h): for j1 in range(h): img.putpixel((i*h +i1, j*h +j1), tuple(data[i*l + j])) # иначе ничего не делаем (имитация бурной деятельности): except TypeError: if j // 2000 == 3: print(«0») bot.send_photo(message.chat.id, img) # отправляем полученное изображение

Если пользователь отправил сообщение не меньше минимальной длины запроса на рисование (минимальный — 0,0,0,0,0 — длина 9), проверяем на ошибки:

else: # если длиннее минимального if len(message.text) >= 9: # переменная таймера — глобальная global st # Если с прошлого изменения пикселя прошло не меньше 20 секунд if time.time() — st < 20: bot.send_message(message.chat.id, text = «слишком часто. Промежуток между сообщениями — 20 секунд») else: # преобразуем текст сообщения в массив с координатами и цветом t = message.text x = [] n = «» # с учётом разделителей for i in t: if i != «,»: n += i else: x.append(n) n = «» x.append(n) n = «» # просматриваем корректность цветов и координат: # не вышли ли за край поля, и т.п. a = 0 n = 0 # в случае нарушений n = 1 (флаг) while a <= len(x)-1: try: x[a] = int(x[a]) if a < 2: if x[a] > l: n = 1 else: if x[a] > 255 or x[a] < 0: n = 1 except Exception: n = 1 a += 1

Если не нашли ошибку — отслеживаем координаты рисования и красим пиксель в необходимый цвет, оповещаем пользователя, обновляем таймер:

import pickle # создаём массив data = [] data = [0] * (100 * 100) # сохраняем try: with open(«data.pickle», «wb») as f: pickle.dump(data, f, protocol=pickle.HIGHEST_PROTOCOL) except Exception as ex: print(«Error during pickling object (Possibly unsupported):», ex)

Не забудим запустить работу бота:

bot.polling(none_stop=True)

Вот и весь код!

Не забудем создать «data.pickle» с помощью другого кода. Он нужен единожды и запускается первым. Указываем размер поля и сохраняем (после тот же размер нужно указать в программе бота):

import pickle # создаём массив data = [] data = [0] * (100 * 100) # сохраняем try: with open(«data.pickle», «wb») as f: pickle.dump(data, f, protocol=pickle.HIGHEST_PROTOCOL) except Exception as ex: print(«Error during pickling object (Possibly unsupported):», ex)

Все файлы вы можете найти на GitHub.

Далее запускаем хостинг бота на pythonAnywhere (инструкция). Не забудьте установить необходимые библиотеки. Это делается с помощью обычного pip install в консоли на сайте (в инструкции описана установка библиотеки telebot, вам нужна ещё pillow (pip install pillow))

Бот успешно работает, вы можете опробовать его в телеграмме по ссылке.

Автоматизация​


После написания основного кода я решил автоматизировать скорее не запросы, а преобразование картинки в запросы.

Начнём с импорта библиотеки pillow и создания текстового файла с координатами:

from PIL import Image f = open(«result.txt», «w+»)

Далее откроем изображение (лучше пиксельарт) и спросим у пользователя координаты размещения:

img = Image.open(‘img.jpg’) print(«X:») x = int(input()) print(«Y:») y = int(input())

Для каждого пикселя изображения нужно узнать его будущее местоположение и цвет:

data = [] for i in range(img.size[0]): for j in range(img.size[1]): col = img.getpixel((i, j)) data.append(str(i+x) + «,» + str(j+y) + «,» + str(col[0]) + «,» + str(col[1]) + «,» + str(col[2]))

Записываем полученные координаты в файл:

for i in data: f.write(i + «n») f.close()

Всё! После запуска получаем то, что необходимо отправлять боту.

Автоматизация отправки​


Так как цель тут — скорее изучение Python, то почему бы не использовать библиотеку pyautoGUI (pip install PyAutoGUI)?

Благо, нам необходимо только вписать текст и нажать Enter:

import pyautogui from time import sleep # открываем файл с координатами f = open(«result.txt») # читаем его data = f.readlines() # убираем переходы на следущую строку diction = [] for i in data: a = str(i) diction.append(a[0:len(i)-1]) # вписываем запрос в телеграм и отправляем боту for i in diction: sleep(22) pyautogui.typewrite(i, interval=0.0) pyautogui.press(‘enter’)

После запуска вышеописанного кода в течение 22 секунд необходимо перейти на вкладку telegram с открытым чатом бота и кликнуть в поле ввода сообщения.

Таким образом мы можем почти автоматически рисовать различные изображения на всем доступном холсте!

Я запустил своего бота с полем 300*300, можно попробовать его.

Все программы находятся на github.

Удачных компиляций!
 
198 157Темы
635 128Сообщения
3 618 411Пользователи
Semifistokl22Новый пользователь
Верх