ITСooky

IT-рецепты съедобные и не очень!

Telegram bot увеличивающий и улучшающий фотки нейро сетью GFPGAN на видео карте с CUDA!

дата 18.06.2022

Первоночальная идея была такая — Telegram bot сохраняет все фотки что ему кидают, потом раз в пару минут запускается обработка папки с фотками и рассылается всем результат. Имя получателя будет в имени файла… вроде бы просто всё, но эт оказалось очень сложно сделать — надо вникать в асинхронность, и вообще… Так что все будет просто и линейно, получил фотку, пошел сразу обрабатывать, а остальные пусть ждут! А и все в этот раз будет на Python, не зря я прослушал(ну и домашки все сделал) бесплатный курс CS50’s Introduction to Programming with Python, а прошлый раз(4 года назад Ма́мма Mia!) все было на node.js Добавляем в умный дом TelegramBot на Node.js

Помогать с запускам бота мне будет Каран Батра Part 1: How to create a Telegram Bot in Python in under 10 minutes

О железе
У меня получился колосс на глиняных ногах. Все еще хорошая для игр видео карта GIGABYTE GeForce RTX 2070 MINI ITX 8 Gb и мать ASRock J3355M интегрированная с процом Intel® Celeron® J3355 которые «не стоят и куляра» видеокарты! Ну и 4Gb памяти… но это все неважно потому что считать буюдет видеокарта! И CUDA тест Geekbench5 это подтверждает, выдает теже окло 99000 что и на Ryzen 7 3700x!

Кстати ноунейм БП на 350W видеокарту не потянул, поставил Zalman 600W

И еще замечаю что на всех ПК перед запуском задач для CUDA(будь то DeeFaceLab или GFPGAN) она как бы подвисает на минуту, инициализируется чтоли, а потом быстро все счиатет одну фотку за другой…

Инициализируем telegram bot’а
Создаем botа через botfather для этого надо быть в Telegram’е! Делаем как тут core.telegram.org/bots#6-botfather

И я это делаю через веб версию, потому что надо будет копировать токен. Начинаем с
/newbot

Придумываем название, имя и нам дают токен

Первый запуск Telegram бота на Python
Python или стоит или нет, проверю
python -V

Python 3.9.10

Стоит уже конечно, куда без него, сейчас пайтон везде! Хотя, местами, прям очень странный язык — самое странное в нем для меня это форматирование пробелами, пробелы — это такие пустые штуки невидемые человечскому глазу и если вместо 4 поставить 3 то все к чертям перестанет работать! Поэтому жизненно необходимо кодить в проге которая знает про эти пробелы, я беру Visual Studio Code бесплтаная у Microsoft! Тут надо доустановить Remote-SSH находится он тут же в Extensions Marketplace

После установки, слева внизу жмем конектимся, открывается новое окно, тут главное включить во View > Terminal и в нем уже как по обычному SSH лазеем по своему серверу. Не обычно тут что срабатывает команда VSС для создания нового файла
code main.py

Тааак с кривым форматированием (по програмерски — конкатенация) в python разобрались, но в VSC оно тоже есть — вот он любит за тебя закрывать открытые скобки, но это такая мелочь на фоне первого что даже копать не хочется где это отключается!

Как ставить настраивать видеокарту и GFPGAN описывал тут уже Увеличиваем улучшаем старые фотки с GFPGAN на Windows через WSL2 и картой с CUDA(можно и без)!. Тут мы без Conda как бы но она нужна для GFPGAN, но мы python запускаем не в Conda!

Для телеграм бота потребуется вот эта штука github.com/python-telegram-bot ставим её через пипку там же в терминале VSC!
pip install python-telegram-bot

В файл main.py добавляю сокрашенный код от Карана, он конечно стандартный

from telegram.ext import Updater, CommandHandler, MessageHandler, Filters

# Define a few command handlers. These usually take the two arguments update and
# context. Error handlers also receive the raised TelegramError object in error.
def privet(update, context):
    """Send a message when the command /start is issued."""
    update.message.reply_text('What ho!')

def echo(update, context):
    """Echo the user message."""
    update.message.reply_text(update.message.text)

def main():
    """Start the bot."""
    # Create the Updater and pass it your bot's token.
    # Make sure to set use_context=True to use the new context based callbacks
    # Post version 12 this will no longer be necessary
    updater = Updater("TUT VASH TOKEN OT BOTFATHER", use_context=True)

    # Get the dispatcher to register handlers
    dp = updater.dispatcher

    # on different commands - answer in Telegram
    dp.add_handler(CommandHandler("privet", privet))
  
    # on noncommand i.e message - echo the message on Telegram
    dp.add_handler(MessageHandler(Filters.text, echo))

    # Start the Bot
    updater.start_polling()

    # Run the bot until you press Ctrl-C or the process receives SIGINT,
    # SIGTERM or SIGABRT. This should be used most of the time, since
    # start_polling() is non-blocking and will stop the bot gracefully.
    updater.idle()

if __name__ == '__main__':
    main()

TUT VASH TOKEN OT BOTFATHER — меняем на токен полученный от botfather

Что еще хорошо в VSC он сам записывает сразу все изменения!

Запускам бот в VSC
python main.py

Ищю свой бот в телеграме по имяни ITCookyFoto и вот он!

Что он сейчас умеет
— Повторят все сообщения за пользователям
— на команду /privet отвечать как Бэрти Вустер

Спасибо Катар, дальше я сам!

Чтобы остановить main.py пару раз нажмем [Ctrl] + [c]

…через неделю (эт перерыв просто был а не время ушедшее на кодирование)

Выкладываю работающий код

Создаем файл
vi /home/alexandr/python/main.py

а в нем код

import os, subprocess
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters

os.chdir("/home/alexandr/python/")

def start(update, context):
    update.message.reply_text('What ho! This bot enhances with GFPGAN (github.com/TencentARC/GFPGAN) and resizes x2 your small fotos! It operates on RTX 2070 video card with CUDA.\n Created by www.itcooky.com', disable_web_page_preview=True)

def gfpgan(filename):
    try:
        subprocess.run(f"/home/alexandr/miniforge3/bin/conda run -n GFPGAN python /home/alexandr/python/inference_gfpgan.py -i /home/alexandr/python/{filename} -o /home/alexandr/python/res -v 1.3 -s 2", shell=True, check=True, stderr=subprocess.DEVNULL)
        return True
    except subprocess.CalledProcessError:
        subprocess.run(f"/usr/bin/rm /home/alexandr/python/{filename}", shell=True, check=True, stderr=subprocess.DEVNULL)
        return False


def image_handler(update, context):
    user = str(update.message.from_user.id)
    file = update.message.photo[-1].file_id
    obj = context.bot.get_file(file)
    obj.download()
    filename =   str(obj.file_path).split('/')[-1]
    #print(filename)
    update.message.reply_text("File received. Wait few minutes for your  resized and enhanced foto!")
    result = gfpgan(filename)
    if result:
        update.message.reply_text("Done")
        pathres = "/home/alexandr/python/res/restored_imgs/" + filename
        update.message.reply_document(document = open(pathres, "rb"))
        subprocess.run(f"/usr/bin/rm /home/alexandr/python/{filename}", shell=True, check=True, stderr=subprocess.DEVNULL)
        subprocess.run(f"/usr/bin/rm /home/alexandr/python/res/cmp/*", shell=True, check=True, stderr=subprocess.DEVNULL)
        subprocess.run(f"/usr/bin/rm /home/alexandr/python/res/cropped_faces/*", shell=True, check=True, stderr=subprocess.DEVNULL)
        subprocess.run(f"/usr/bin/rm /home/alexandr/python/res/restored_faces/*", shell=True, check=True, stderr=subprocess.DEVNULL)
        subprocess.run(f"/usr/bin/rm /home/alexandr/python/res/restored_imgs/*", shell=True, check=True, stderr=subprocess.DEVNULL)
    else:
        update.message.reply_text("Error: Try another image file")

def main():
    """Start the bot."""
    updater = Updater("TUT VASH TOKEN OT BOTFATHER", use_context=True)

    # Get the dispatcher to register handlers
    dp = updater.dispatcher

    dp.add_handler(MessageHandler(Filters.photo, image_handler))
    dp.add_handler(CommandHandler("start", start))

    # Start the Bot
    updater.start_polling()

    # Run the bot until you press Ctrl-C or the process receives SIGINT,
    # SIGTERM or SIGABRT. This should be used most of the time, since
    # start_polling() is non-blocking and will stop the bot gracefully.
    updater.idle()

if __name__ == '__main__':
    main()

В эту же папку /home/alexandr/python/ кладу все что было в папке GFPGAN

По коду

os.chdir("/home/alexandr/python/")

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

Функция gfpgan — запускает команду на обработку картинки, а возврашает удачно или нет.

Функция image_handler — главная функция. Сохраняет фото которое юзер присылает. Запускает функцию gfpgan если она сработала удачно то отсылает из заранее известного места фотку, а если нет пишет что нет. В конце удаляет все происланные и обработанные фотки

Подробнее

    file = update.message.photo[-1].file_id
    obj = context.bot.get_file(file)
    obj.download()

— этот код сохраняет присланную фотку, тут смешно если вместо -1 поставить 0 то он почему то сохранит очень маленькую фотку… вам не смешно? А мне было смешно об этом узнать через пару часов диагностирования GFPGAN не могу понять почему после увеличения у меня присланная в ответ фотка в два раза меньше становится!!!

filename =   str(obj.file_path).split('/')[-1] 

— вытаскиваем под каким имянем bot сохранил фото. Кстати нам совсем не нужно имя пользователя кому отсылать результат в рамках этой функции оно уже известно кому отсылать.

result = gfpgan(filename)

— запускаем обработку фото, передаем имя фотки, в ответ True если гуд и False если бед

    if result:

— если True

        update.message.reply_text("Done")

— пишем что все гуд

        pathres = "/home/alexandr/python/res/restored_imgs/" + filename 
        update.message.reply_document(document = open(pathres, "rb"))

— формируем путь к обработанному файлу в pathres. И далее ответом отсылаем фотку. Тут надо отправлять через как document если через как photo он будет ужимать её под экран и полную не скачать.

        subprocess.run(f"/usr/bin/rm /home/alexandr/python/{filename}", shell=True, check=True, stderr=subprocess.DEVNULL)
        subprocess.run(f"/usr/bin/rm /home/alexandr/python/res/restored_imgs/{filename}", shell=True, check=True, stderr=subprocess.DEVNULL)

— стираем фотки

Вот ссылка на bot
t.me/ITCookyFotoBot

Вот такая в идеале картинка

Вот такой Лев до

И после

Запускаем наш python скрипт как сервис

sudo vi /lib/systemd/system/telegrambot.service

Добавляем текст

[Unit]
Description=Telegram Bot GFPGAN
After=multi-user.target
Conflicts=getty@tty1.service

[Service]
Type=simple
ExecStart=/home/alexandr/miniforge3/bin/python /home/alexandr/python/main.py
StandardInput=tty-force

[Install]
WantedBy=multi-user.target

Перечитываем демоны
sudo systemctl daemon-reload

Ну и делаем чтобы стратовал на загрузке и сейчас тож стартанул
sudo systemctl enable telegrambot.service
sudo systemctl start telegrambot.service

Все теперь сам будет запускаться всегда


Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *