7669

Як створити телеграм-бота на Python

Боти в Telegram надають бізнесу ще один ефективний канал комунікації з аудиторією та автоматизують великий обсяг одноманітної роботи, звільняючи час найманого персоналу для виконання найважливіших завдань. Доступність та висока швидкість розробки ботів зробила їх надзвичайно популярними у різних галузях бізнесу.

У цій статті поговоримо про те, як створити телеграм-бота на Python, а саме за допомогою бібліотеки python-telegram-bot. Це офіційна оболонка для API від месенджера Телеграм, яка повністю сумісна з Python 3.6+, за допомогою якої можна зручно і досить швидко написати потрібного бота.

Створення бота

Насамперед для початку роботи потрібно встановити python-telegram-bot. Для цього можна скористатись безкоштовною документацією бібліотеки.

Bot

$ pip install python-telegram-bot upgrade

Після цього можна приступати до створення робота. Для цього виконуємо кілька простих дій:

  • Перейти в Telegram.
  • Знайти бота @BotFather, який відповідає за реєстрацію нових ботів.
  • Почати спілкуватися з ботом, використовуючи команду /newbot.
  • Ввести ім'я та юзернейм створюваного бота.

За допомогою @BotFather можна також виконувати багато інших важливих дій, наприклад, встановити зображення нового бота.

Далі потрібно визначитися з тим, яке саме завдання вирішуватиме проект. Як приклад ми створимо робота, що надає інформацію про біоритми людини. Однак, використовуючи цю інструкцію, ви зможете розробляти ботів будь-якої спрямованості, орієнтованих на потреби конкретного бізнесу.

Програмування робота за допомогою Python

Як уже говорилося, пакет python-telegram-bot складається з оболонки API Telegram, проте крім цього він оснащений модулем telegram.ext, який суттєво полегшить програмування бота.

Сам модуль telegram.ext включає безліч класів, з яких можна виділити два основні:

  • Telegram.ext.Updater – отримує оновлення від Telegram і передає їх у Dispatcher.
  • Telegram.ext.Dispatcher — відправляє всі види оновлень зареєстрованим обробникам.

Тепер можна приступити безпосередньо до написання коду:

# mastrobot_example.py
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters
# function to handle the /start command
def start(update, context):
    update.message.reply_text('start command received')
# function to handle the /help command
def help(update, context):
    update.message.reply_text('help command received')
# function to handle errors occured in the dispatcher 
def error(update, context):
    update.message.reply_text('an error occured')
# function to handle normal text 
def text(update, context):
    text_received = update.message.text
    update.message.reply_text(f'did you said "{text_received}" ?')
def main():
    TOKEN = "insert here your token and don't share it with anyone!"
    # create the updater, that will automatically create also a dispatcher and a queue to 
    # make them dialoge
    updater = Updater(TOKEN, use_context=True)
    dispatcher = updater.dispatcher
    # add handlers for start and help commands
    dispatcher.add_handler(CommandHandler("start", start))
    dispatcher.add_handler(CommandHandler("help", help))
    # add an handler for normal text (not commands)
    dispatcher.add_handler(MessageHandler(Filters.text, text))
    # add an handler for errors
    dispatcher.add_error_handler(error)
    # start your shiny new bot
    updater.start_polling()
    # run the bot until Ctrl-C
    updater.idle()
if __name__ == '__main__':
    main()

Зауважте, що для функції main() ми створили клас Updater. Згодом він згенерував новий об'єкт Dispatcher, який став доступним через .dispatcher-властивості Updater.

Тепер додамо кілька обробників:

  • Команда користувача /start викличе функцію start(), яка надішле людині інформаційне повідомлення щодо подальшої роботи з ботом.
  • Команда користувача /help викличе функцію help(), яка надішле повідомлення-інструкцію з відповідями на популярні запитання.
  • У разі виникнення помилки під час надсилання повідомлення викликається функція error().
  • При введенні некоректної команди або символів, які не є командою, буде викликана функція text(). Вона згенерує повідомлення у відповідь з тим же текстом, який ввів користувач.

На даний момент у коді описані функції зворотного виклику, які реагують на введені користувачем дані і генерують відповідні відповіді.

Тестування бота

На цьому етапі вже можна приступити до тестування проекту, щоб переконатися, що всі описані обробники працюють коректно. Для цього запускаємо бот та відправляємо команду /start.

Запускаємо

$ python mastrobot_example.py

Незважаючи на те, що робота працює коректно, це ще не кінець. Тепер, щоб він виконував поставлене завдання - надавав людині інформацію про біоритми, потрібно змінити функцію команди /start таким чином, щоб вона запитувала особисті дані користувача, наприклад: рік, місяць та день народження. Крім того, створимо нову функцію з командою /biorhythm, яка на підставі отриманої інформації генеруватиме відповідь з біоритмом.

Насамперед змінимо функцію start(), для цього пишемо такий код:

def start(update, context):
    first_name = update.message.chat.first_name
    update.message.reply_text(f"Hi {first_name}, nice to meet you!")
    start_getting_birthday_info(update, context)

У параметрі update буде міститься корисна інформація про користувача, наприклад, його ім'я або логін в Telegram. На початку скрипту створимо нову змінну STATE, і поки що залишимо її порожньою. Вона буде потрібна для того, щоб зрозуміти, на яке запитання відповідає користувач:

STATE = None
BIRTH_YEAR = 1
BIRTH_MONTH = 2
BIRTH_DAY = 3

Далі реалізуємо функцію start_getting:_birthday_info(), яка буде викликатись за допомогою /start. Таким чином, після запуску ми зможемо отримати дані про день народження користувача.

def start_getting_birthday_info(update, context):
    global STATE
    STATE = BIRTH_YEAR
    update.message.reply_text(f"I would need to know your birthday, so tell me what year were you born in...")

Також для змінної STATE ми встановили BIRTH_YEAR. Це допоможе користувачеві зрозуміти, що питання стосуватиметься року його народження. Після цього йому надсилається повідомлення з відповідним запитом.

Тут ми маємо на увазі, що користувач дасть відповідь текстовим значенням, яке не буде командою. 

Тому, для коректної роботи робота нам також необхідно змінити функцію text().

def text(update, context):
    global STATE
    if STATE == BIRTH_YEAR:
        return received_birth_year(update, context)
    if STATE == BIRTH_MONTH:
        return received_birth_month(update, context)
    if STATE == BIRTH_DAY:
        return received_birth_day(update, context)

Використовуючи змінну STATE, ми дозволяємо боту зрозуміти, на яке саме питання відповів користувач.

Далі нам залишається лише викликати функцію, яка виконуватиме обробку кожної відповіді користувача. 

У коді це можна записати так:

def received_birth_year(update, context):
    global STATE
    try:
        today = datetime.date.today()
        year = int(update.message.text)
        
        if year > today.year:
            raise ValueError("invalid value")
        context.user_data['birth_year'] = year
        update.message.reply_text(f"ok, now I need to know the month (in numerical form)...")
        STATE = BIRTH_MONTH
    except:
        update.message.reply_text("it's funny but it doesn't seem to be correct...")
def received_birth_month(update, context):
    global STATE
    try:
        today = datetime.date.today()
        month = int(update.message.text)
        if month > 12 or month < 1:
            raise ValueError("invalid value")
        context.user_data['birth_month'] = month
        update.message.reply_text(f"great! And now, the day...")
        STATE = BIRTH_DAY
    except:
        update.message.reply_text("it's funny but it doesn't seem to be correct...")
def received_birth_day(update, context):
    global STATE
    try:
        today = datetime.date.today()
        dd = int(update.message.text)
        yyyy = context.user_data['birth_year']
        mm = context.user_data['birth_month']
        birthday = datetime.date(year=yyyy, month=mm, day=dd)
        if today - birthday < datetime.timedelta(days=0):
            raise ValueError("invalid value")
        context.user_data['birthday'] = birthday
        STATE = None
        update.message.reply_text(f'ok, you born on {birthday}')
    except:
        update.message.reply_text("it's funny but it doesn't seem to be correct...")

При отриманні відповіді від користувача необхідно перевірити допустимість введеного значення. Якщо дані коректні, вони записуються масив context.user_data[].

Тепер залишається аналогічним чином отримати від користувача решту даних. Для цього ми можемо просто змінювати значення змінної STATE та ставити людині відповідні питання.

Після отримання останньої відповіді додаємо змінну дати, яка буде виходити автоматично, та зберігаємо її у словник context.user_data[].

При цьому завдяки функції text() ми захищаємо дані від некоректного введення. Якщо буде отримано неприпустиму відповідь, система автоматично поверне користувачеві його повідомлення, і він фактично «застрягне» на цьому питанні поки не надасть правильну інформацію.

Створюємо логіку основної команди

Отримавши від користувача всю необхідну інформацію, бот повинен її обробити, і надати людині дані про його біоритми. Для цього налаштуємо роботу команди / biorhythm.

Насамперед додамо в функцію main() новий обробник команд:

dispatcher.add_handler(CommandHandler("biorhythm", biorhythm))

Потім опишемо логіку розрахунку біоритму. Для цього створимо дві окремі функції: перша відповідатиме за обробку команди /biorhythm, а друга виконуватиме безпосередні математичні обчислення. 

У коді це виглядатиме так:

# This function is called when the /biorhythm command is issued
def biorhythm(update, context):
    user_biorhythm = calculate_biorhythm(
        context.user_data['birthday'])
    update.message.reply_text(f"Phisical: {user_biorhythm['phisical']}")
    update.message.reply_text(f"Emotional: {user_biorhythm['emotional']}")
    update.message.reply_text(f"Intellectual: {user_biorhythm['intellectual']}")
def calculate_biorhythm(birthdate):
    today = datetime.date.today()
    delta = today - birthdate
    days = delta.days
    phisical = math.sin(2*math.pi*(days/23))
    emotional = math.sin(2*math.pi*(days/28))
    intellectual = math.sin(2*math.pi*(days/33))
    biorhythm = {}
    biorhythm['phisical'] = int(phisical * 10000)/100
    biorhythm['emotional'] = int(emotional * 10000)/100
    biorhythm['intellectual'] = int(intellectual * 10000)/100
    biorhythm['phisical_critical_day'] = (phisical == 0)
    biorhythm['emotional_critical_day'] = (emotional == 0)
    biorhythm['intellectual_critical_day'] = (intellectual == 0)
    return biorhythm

Після закінчення розробки, як і будь-який програмний продукт, бот потрібно остаточно протестувати, і в разі необхідності зробити налагодження. Після цього він буде готовим до релізу.

Вивчення Python у SpaceLAB

Python — це одна з найбільш широко використовуваних мов програмування, яку підтримує Google. З його допомогою можна створювати не лише телеграм-ботів, а й веб-сценарії, штучний інтелект, Data Science-проекти та багато іншого.

В лабораторії SpaceLAB ви можете вивчити мову Python безкоштовно, з перспективою подальшого працевлаштування. Курс містить потужну теоретичну частину, але переважно орієнтований виконання практичних завдань під кураторством досвідчених менторів.