ITCooky Recipes

Lets cooky it yammy things!

Telegram bot that augments and enhances photos with the GFPGAN neural network on a CUDA-enabled video card!

дата June 19, 2022

The initial idea was this: the Telegram bot saves all the images that are sent to it, then, every few minutes, it starts processing the images in the folder and the result is sent to everyone. The name of the recipient will be in the name of the file… everything seems to be simple, but it turned out to be very difficult to do: you have to go deeper into asynchrony and, in general… Soo everything will be simple and linear, bot receive a photo, go to process it immediately and let the others wait! And this time I will do it in Python, not in vain I heard (and well, I did all the homework) a free course CS50’s Introduction to Programming with Python, and last time (4 years ago Mamma Mia!) everything was done in node.js Smart house monitoring with TelegramBot in Node.js!

Karan Batra will help me launch the bot Part 1: How to create a Telegram Bot in Python in under 10 minutes

Hardware
I have a colossus with feet of clay. A graphics card, which is still good for gaming, GIGABYTE GeForce RTX 2070 MINI ITX 8 Gb and motherboard ASRock J3355M with integrated CPU Intel® Celeron® J3355 that “doesn’t even cost the cooler” of the graphics card! Well, and 4Gb of memory… but it doesn’t matter because the video card will do all the calculations! And the Geekbench5 CUDA test confirms it, giving the same 99000 as with the Ryzen 7 3700x!

By the way, the naname 350W power supply does not boot with the video card, I installed Zalman 600W

And I also notice that on all PCs, before launching tasks for CUDA (either DeeFaceLab or GFPGAN), it seems to freeze for a minute, initializes maybe, and then everything works quickly one foto after another…

Lets create telegram bot’a
We created a bot through botfather, for this you need to be on Telegram! Doing like here core.telegram.org/bots#6-botfather

And I do it through the web version, because I will have to copy the token. Beginning with
/newbot

We give a name for the bot, another short name and they give us a token

First start of the Telegram bot in Python
Python is already installed or not, I will check
python -V

Python 3.9.10

Of course it’s already installed, now Python is everywhere! Although, in some aspects, it’s a very strange language: the strangest thing for me is formatting with spaces, spaces are empty things invisible to the human eye, and if you put 3 instead of 4, then everything stops working! Therefore, it is vital to code in a program that knows these spaces, I take advantage of Microsoft‘s free Visual Studio Code! Here you need to install Remote-SSH, it’s right there in Extensions Marketplace

After installation, click connect at the bottom left, a new window opens, the main thing is to turn it on in View> Terminal and connect to it as an SSH normal, and you can browse yer server. A VSC command to create a new file works here
code main.py

Yaaa the crooked format (scientifically known as concatenation) is fixed in python, but in VSC it exists too – it likes to close open parentheses for you, but this is such a small insignificance in the context of the former! I don’t even want to dig to find out how to turn it off!

How to configure a video card and GFPGAN I have already described here Resize and enhance old photos with GFPGAN on Windows via WSL2 and a card with CUDA (or without)!. Here we use python without Conda, so to speak, but it is necessary for GFPGAN, but we do not run telegram bot in Conda!

For a Telegram bot you need this thing github.com/python-telegram-bot we install it with pip on VSC!
pip install python-telegram-bot

In the main.py file I add the Karan shortcode, of course it’s standard

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 – change to token received from botfather

Another nice thing about VSC is that it saves all changes itself!

Launching the bot in VSC
python main.py

I’m search for my Telegram bot called ITCookyFoto and here it is!

What can it do now?
– Repeat all user messages
– Respond to the /privet command as Bertie Wooster

Thank you Qatar, I continue by myself!

To stop main.py press [Ctrl] + [c] a couple of times

…it’s been a week (ir wasn’t the time spent on coding)

You have to create a file
vi /home/alexandr/python/main.py

code

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

In the same folder /home/alexandr/python/ I put everything that was in the GFPGAN folder

Code explained

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

– this is a very important thing that tells which directory the script is running from – as long as you run it manually it doesn’t matter at all, and when it will be started by the system it should be told in which folder. Therefore, the rest of the paths are written complete.

gfpgan function: starts a command to process the image and returns successfully or not.

The image_handler function is the main function. Save the photo that the user sends. Execute the gfpgan function, if it worked correctly, send a photo of a known place, and if not, write no. At the end, it deletes all submitted and processed photos.

More in detail

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

– this code saves the sent photo… It’s funny – if you put 0 instead of -1 then for some reason it will make and save a very small photo… No? Don’t you think it’s funny? I was very amused to find out about this after a couple of hours of diagnosing GFPGAN, I couldn’t figure out why, after the magnification, the photo bot sent me back is even smaller!

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

– we get under what name the bot saved the photo. By the way, we don’t need the username to send the result to in the scope of this function, we already know who to send it to.

result = gfpgan(filename)

– start photo processing, pass photo name, in response True if good and False if bad

    if result:

– if its True

        update.message.reply_text("Done")

– write that everything is fine

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

– form the path to the processed file in pathres. And then we send a photo as a reply. Here it is necessary to send through document if through photo it will be reduced according to the screen and the complete one will not be downloaded in full size.

        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)

– delete photos

Here is the link to the bot
t.me/ITCookyFotoBot

This is the idial screenshot of bot work

Leo befor…

…and after

Run our python script as a service

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

Add texto

[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

Reload demonios
sudo systemctl daemon-reload

Now we have to make it launchable on boot, and we launch it right now without reboot
sudo systemctl enable telegrambot.service
sudo systemctl start telegrambot.service

Now everything will always start itself.


Leave a Reply

Your email address will not be published. Required fields are marked *