Покрокова інструкція: як створити телеграм-бота на Ruby
Мене звуть Володимир, я QA Automation Engineer у компанії Matic. Люблю автоматизувати процеси й постійно пробую нові та цікаві технології. Найцікавіший проєкт, яким я займався останнім часом, — телеграм-бот мовою програмування Ruby. На цей час телеграм налічує понад 200 мільйонів активних користувачів зі всього світу, і все більше людей встановлюють телеграм собі на пристрої та користуються ним щоденно.
Якщо ви думаєте, що під капотом телеграм-бота знаходиться штучний інтелект чи інша надскладна технологія, то хочу вас запевнити, що все не так страшно. У цій статті я навчу вас писати власних ботів, які будуть показувати погоду в різних містах. Надалі ж ви зможете використати ці підходи для написання інших ботів, що нагадуватимуть вам про дні народження, показуватимуть затори на дорогах, надсилатимуть цікаві новини тощо. Тож перейдімо до роботи, бо хтозна, можливо, вам у майбутньому вдасться монетизувати свого бота.
Ця стаття розрахована на людей, що починають свій шлях в ІТ й хотіли б спробувати щось нове, поекспериментувати з технологіями, створити свій власний проєкт. Не переймайтеся, дуже багато часу це не забере. Орієнтовно 15 хвилин на прочитання і 30 — на реалізацію ідеї.
Для того, щоб створити цей телеграм-бот, нам треба:
- Установити Ruby:
- Установити одне із середовищ розробки (Atom, Sublime, Visual Code, RubyMine (його я й використовую), підійде навіть блокнот).
- Створити акаунт в Openweather Api.
- Акаунт у телеграмі.
Наш бот показуватиме погоду в різних містах на основі даних Оpenweather API. Я вибрав саме цей ресурс — він безплатний і простий у користуванні. Також, як ви вже могли здогадатися, для написання цього телеграм-бота ми використаємо мову Ruby: вона одна з найпростіших для сприйняття мов програмування, бо розроблена для людей, а не машин. Ця мова open-source, має велике ком’юніті, а отже більшість рішень уже є в інтернеті, тому не треба придумувати складні алгоритми.
Створення телеграм-бота
Нам треба створити телеграм-бота, звідки ми можемо взяти токен. Детальніше про те, що таке токен, можете прочитати на Вікіпедії — «Токен автентифікації».
Для цього в телеграмі знайдіть і додайте до своїх контактів @BotFather і введіть команду /start.
Тепер напишіть команду /newbot для створення нового бота.
Настав час придумати назву для вашого бота. Це може бути будь-яке ім’я, наприклад: Weather Bot, Super Mega Weather.
Далі придумайте username, за допомогою якого ми зможемо знаходити нашого бота. Username має закінчуватися словом bot (або Bot), це вимога BotFather.
За допомогою цього нікнейма можна знайти й додати вашого бота до своїх контактів. Збережіть токен, який видасть бот, бо він нам знадобиться згодом.
OpenWeather API
Наш бот інтегруватиметься з OpenWeather, але ви можете використовувати будь-який інший сервіс. Отже, щоб інтегруватися з OpenWeather, насамперед вам треба зареєструватися там та прочитати інструкцію з використання.
Реєструємося та створюємо токен для роботи. Цей токен матиме вигляд набору букв і цифр. Збережіть його також, він нам скоро знадобиться.
Зверніть увагу! Для Api calls через Openweather треба зачекати приблизно годину після реєстрації для того, щоб система додала вас і ваш токен для роботи.
Вітаю! Половину роботи вже зроблено! Це було не складно, погодьтеся, залишилося лише написати трішки коду.
Створення проєкту й встановлення бібліотек
Для початку відкрийте Термінал.
- Windows: Запустіть Командний рядок (Win+R, введіть команду cmd).
- macOS, Linux: Введіть у Spotlight слово terminal і відкрийте його.
Створіть новий проєкт. Якщо використовуєте Rubymine, то натисніть File -> New -> Project.
Перейдіть у теку з проєктом, використовуючи Термінал (для навігації використовуйте команду cd folder_name
).
Установіть менеджер бібліотек для мови Ruby bundler командою в Терміналі: gem install bundler
.
Детальніше про bundler можна почитати тут .
Створимо Gemfile в корені проєкту (без розширення). Цей файл допомагає легко зберігати й установлювати бібліотеки (Gems у мові Ruby). Для створення цього файлу використайте таку команду: bundle init
.
Детальніше про Gemfile — тут.
Використаймо дві бібліотеки, а саме: telegram-bot-ruby — для написання телеграм-бота; rest-client — для api calls.
Тобто кінцевий вигляд нашого Gemfile буде такий:
source 'https://rubygems.org' gem 'rest-client' gem 'telegram-bot-ruby'
Для встановлення бібліотек, які ми прописали в Gemfile, використайте таку команду: bundle install
. Ця команда встановить усі потрібні бібліотеки для роботи з Gemfile. У цей момент будуть додані дві бібліотеки, а саме: rest-client і telegram-bot-ruby.
Написання коду
Весь наш код поміститься в одному файлі. Створімо його та назвімо weather.rb.
Для початку додамо бібліотеку для роботи з API. Для цього в першому рядочку напишемо: require 'rest-client'
.
Створюємо клас для роботи з погодою. Клас — це шаблон, з якого створюються інші об’єкти. Використовуємо таку назву класу:
class Weather end
Додамо всередину класу наш OpenWeather токен, який ми дістали в попередньому пункті та лінку для API. Для цього оголосимо такі константи:
API_URL = 'api.openweathermap.org/data/2.5/'.freeze APPID = 'YOUR_OPEN_API_APPID'.freeze
Константи — це значення, що не мінятимуться.
Додаємо до класу кілька методів. Метод — це набір операцій, що повертають значення.
Додамо конструктор. Конструктор — це набір команд, які виконуватимуться при створенні класу:
def initialize(city) @city = city end
У нашому випадку при створенні класу ми створюватимемо об’єкт city (тобто назву міста).
Додамо акцесор. Акцесор — це метод, що дозволяє читати дані, в нашому випадку @city.
attr_reader :city
Додаємо повідомлення для користувача:
def form_message temperature.nil? ? 'City not found' : "In #{city} city today is #{temperature} celsius #{select_icon(temperature)}" end
Не лякайтеся численних символів. У нашому випадку перевіряємо, чи є температура. Якщо її немає, виводимо повідомлення, що міста немає. Якщо вона є, ми повертаємо таке повідомлення: In <назва_міста> city today <температура> celsius <іконка погоди>
, про яку поговоримо згодом>.
Далі інкапсулюватимемо, тобто писатимемо приватні методи. Інкапсуляція дозволяє приховати методи від використання поза межами цього класу, щоб обмежити доступ до них випадкових змін. Для цього напишемо:private
Додамо лінк для перевірки погоди:
def weather_url "#{API_URL}/weather?q=#{city}&APPID=#{APPID}&units=metric" end
Цей лінк складається з URL для API, назви міста, вашого токена, а також використання метричної системи числення.
Тепер додаємо запит (request) на сервер. Відповідь (response) повернеться у форматі JSON — найпопулярнішому форматі серед API. Перетворимо його на хеш методом JSON.parse:
def weather_response @response_body ||= RestClient.get(weather_url).body JSON(@response_body) end
Тут ми посилаємо get запит з нашою згенерованою URL, звідки дістаємо body. Після цього конвертуємо його в JSON.
Дістанемо температуру з нашого response:
def temperature weather = weather_response return nil unless weather weather.dig('main', 'temp').to_i end
Звідси, з попереднього методу ми дістали response і перевіряємо, чи він не пустий. Якщо він пустий — повертаємося з методу й вертаємо nil, тобто нічого.
Додамо ще головний візуальний елемент — іконки для певних градусів температури:
def weather_icons { 40..49 => '🔥', 30..39 => '☀️', 20..29 => '🌤', 10..19 => '⛅️', 0 => '☁️', -10..-1 => '☃️', -20..-11 => '❄️' } end
Ці іконки взяті з телеграму, але можете використовувати свої. Тут застосовується hash, який показує іконки відповідно до температури (хеш — це колекція, що має унікальний ключ і його значення).
Напишемо метод для вибору іконок:
def select_icon(temperature) icon = weather_icons.select { |ico| ico === temperature }.values.first icon = '✨' if icon.nil? icon end
Тут усе просто — дістаємо температуру й шукаємо її іконку в нашому попередньому методі. Якщо не знайшли іконки — показуємо іконку із зірочками.
Кінцевий вигляд класу буде такий:
require 'rest-client' class Weather API_URL = 'api.openweathermap.org/data/2.5/'.freeze APPID = 'YOUR_OPEN_API_APPID'.freeze def initialize(city) @city = city end attr_reader :city def form_message temperature.nil? ? 'City not found' : "In #{city} city today is #{temperature} celsius #{select_icon(temperature)}" end private def weather_url "#{API_URL}/weather?q=#{city}&APPID=#{APPID}&units=metric" end def weather_response @response_body ||= RestClient.get(weather_url).body JSON(@response_body) end def temperature weather = weather_response return nil unless weather weather.dig('main', 'temp').to_i end def weather_icons { 40..49 => '🔥', 30..39 => '☀️', 20..29 => '🌤', 10..19 => '⛅️', 0 => '☁️', -10..-1 => '☃️', -20..-11 => '❄️' } end def select_icon(temperature) icon = weather_icons.select { |ico| ico === temperature }.values.first icon = '✨' if icon.nil? icon end end
На цьому етапі ми можемо дістати JSON з даними, з яких ми дістанемо значення температури в певному місті, а також формуємо повідомлення.
Напишемо клас із нашим телеграм-ботом. Для цього творіть у корені проєкту новий файлик з назвою: telegram_bot.rb
Під’єднуємо бібліотеку з телеграм-ботом. Для цього нам треба написати:
require 'telegram/bot' require_relative 'weather'
Ми також під’єднали наш клас Weather для того, щоб Ruby зміг його знайти.
Створюємо константу, щоб можна було записати наш телеграм-токен, який ми отримали раніше: TOKEN = 'YOUR_TELEGRAM_TOKEN'.freeze
Створимо метод для того, щоб запустити нашого бота:
def run bot.listen do |message| weather_message(message) rescue => e puts e.message end endЦей метод слухає команди користувача й реагує на команду з погодою, яку ми напишемо згодом. Також він надсилає повідомлення з помилкою, якщо раптом щось пішло не так.
Інкапсулюємо такі команди:private
Додаємо метод для запуску бота з нашим токеном:
def bot Telegram::Bot::Client.run(TOKEN) { |bot| return bot } end
Цей метод запускатиме бота через нашу бібліотеку.
А тепер створюємо метод для того, щоб можна було надсилати повідомлення з погодою:
def weather_message(message) return unless message.text.include? '/weather' send_message(message.chat.id, Weather.new(city_name(message.text)).form_message) endЦей метод викликатиметься, якщо повідомлення від користувача міститиме слово
'/weather'
і надсилатиме повідомлення з погодою в чат, з якого надійшло це повідомлення.
Створимо метод, щоб можна було розібрати те, що ввів користувач:
def city_name(text) text.gsub('/weather', '').strip.tr(' ', '+') end
У нашому випадку стираємо /weather і забираємо пробіли, щоб замінити їх на +. Адже так працює апішка OpenWeather з пробілами (якщо вони є).
Створимо метод, щоб можна було надіслати повідомлення з погодою в певний чат з певним текстом.
def send_message(chat_id, message) bot.api.sendMessage(chat_id: chat_id, text: message) end
Згрупуємо наші методи. Для цього напишемо такий код:
class TelegramBot # наш код end
Створимо цей клас і запустимо нашого бота: TelegramBot.new.run
.
У нашому випадку створюємо об’єкт класу й викликаємо з нього метод run.
Кінцевий вигляд буде такий:
require 'telegram/bot' require_relative 'weather' class TelegramBot TOKEN = 'YOUR_TELEGRAM_TOKEN'.freeze def run bot.listen do |message| weather_message(message) rescue => e puts e.message end end private def bot Telegram::Bot::Client.run(TOKEN) { |bot| return bot } end def weather_message(message) return unless message.text.include? '/weather' send_message(message.chat.id, Weather.new(city_name(message.text)).form_message) end def city_name(text) text.gsub('/weather', '').strip.tr(' ', '+') end def send_message(chat_id, message) bot.api.sendMessage(chat_id: chat_id, text: message) end end
Залишилося лише створити клас для запуску нашого телеграм-бота. Почнемо зі створення нового класу, з якого запускатимемо нашого бота.
run_bot. rb
Сюди запишемо такий код:
require_relative 'telegram_bot' TelegramBot.new.run
Бот готовий. Ви впоралися, з чим я вас вітаю! Залишилося тільки запустити нашого бота.
Для цього напишемо в Терміналі таку команду: ruby run_bot.rb
.
Знаходимо й додаємо нашого телеграм-бота. Переходимо в наш канал з ботом і, використовуючи команду /weather <city_name>
, запитуємо про погоду.
У відповідь ми отримаємо таке повідомлення:
Висновки
Отже, сьогодні ви познайомилися з Ruby, а також навчилися писати простенького телеграм-бота. Надіюся, ця стаття надихне вас написати його й додати новий функціонал, а можливо, зробити щось своє.
Дякую, що прочитали мою статтю та випробували свої можливості. Сподіваюся, вам було цікаво! Буду вдячний за фідбек і ваші запитання в коментарях.
Також можете знайти код на Github.
9 коментарів
Підписатись на коментаріВідписатись від коментарів Коментарі можуть залишати тільки користувачі з підтвердженими акаунтами.