Як автоматизувати вивчення англійської мови за допомогою Telegram-бота

💡 Усі статті, обговорення, новини про продукти — в одному місці. Приєднуйтесь до Product спільноти!

Вітаю! Мене звати Міша, я .NET Software Engineer у компанії HYS Enterprise. У цій статті хочу поділитися думками й цікавими кейсами, які в мене виникали під час роботи над пет-проєктом English Words🦊. Нетривіальний підхід до створення цього телеграм-бота дав у підсумку круті бенефіти.

Чому це буде цікаво

Тут описані різні проблеми — від технічних нетривіальних та пошуку цільової аудиторії до міграцій на інші хмарні сервіси, коли бот уже мав понад тисячу користувачів; як я працював із зацікавленістю та відтоком користувачів тощо. І все це в рамках одного пет-проєкту в умовах відключень світла.

Яку проблему вирішує бот

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

Тоді мене наче вдарила блискавка: згадав, що я розробник і можу автоматизувати деякі процеси. Отож вирішив зробити бота для зручнішого вивчення нових слів, який не треба завантажувати на телефон чи комп’ютер і який працюватиме одразу для всіх учасників чату. Першими функціями, якими я планував його наділити, були такі:

  • зберігати слова;
  • нагадувати лексику за графіком.

Так почався шлях до версії бота 1.0.

Технічне планування

Маючи досвід комерційної розробки, я одразу спланував архітектуру, середовище розробки, мову програмування. Трохи почитав документацію від телеграму. На той момент мої рішення були такими:

  • Linux
  • AWS
  • Docker
  • .NET 8
  • PostgreSQL
  • Entity Framework Core
  • мікросервісна архітектура.

Далі — коротко про причини такого вибору.

AWS. Є безкоштовний тріал на 1 рік, до того ж я вже мав досвід роботи з ним.

Docker. Хороший для автоматичного деплою за допомогою CI/CD. Плюс з ним я також раніше працював. Не потрібно копіювати файли, легко мігрувати. Свою базу даних тримав так само в контейнері.

PostgreSQL. Натоді мав досвід робити з MS SQL та PostgreSQL. Утім, для запуску MS SQL сервера в контейнері він мусить мати 2 ГБ ОЗУ, а AWS на тріалі дозволяє лише 1 ГБ. Тому вибрав PostgreSQL, помістив базу даних у контейнер.

.NET 8. Тут зрозуміло: я .NET-розробник, мені подобається програмувати на .NET.

Entity Framework Core. Люблю працювати із SQL-кодом напряму (через Dapper, ADO.NET тощо), але хотів ближче ознайомитися з Entity Framework Core. Далі будуть цікаві кейси.

Мікросервісна архітектура. Можна запитати: це ж звичайний пет-проєкт для автоматизації зі зберіганням слів, навіщо так перфекціонувати? Відповім: тут є практична перевага — підтримка сервісів, їхня незалежність один від одного, простота міграцій.

Проблеми та їх вирішення

Перша проблема: я не повністю прочитав документацію Bot.Telegram.Api й одразу почав писати код. Спершу в бота було приблизно 12 команд, з часом взаємодія з ним ставала складнішою: користувачі просто не розуміли, що робити та як усе налаштувати. Особливо це стосувалося нагадувань — їх можна було створювати кілька, але керувати ними без зручного меню було складно.

Потім я почав шукати рішення в інтернеті й натрапив на Inline Keyboard. Вона допомогла зробити інтерфейс бота зручнішим і гнучкішим:

Для цього я використав патерни Factory та Command — вони допомогли налаштувати інтерфейс так, щоб кнопки змінювалися залежно від дій користувача. Це значно спростило взаємодію з ботом, зробило його інтуїтивнішим та дозволило уникнути плутанини з командами. Але найголовніше — якщо розширюється функціональність та з’являються нові розділи, то мені не потрібно нічого додавати на «верхньому рівні». Він буде незмінним, інші команди не будуть змінюватись та жодна команда нічого не знає про інші команди.

Друга проблема: я вирішив додати переклад слів, тому почав шукати API. Розглядав три варіанти:

  • Deepl Translator,
  • ChatGPT,
  • Anthropic — Claude AI.

Спочатку хотів використовувати Deepl Translator, де можна безкоштовно перекласти до 500 тисяч символів на місяць. Але згодом я вирішив додати функціонал із перевіркою граматики та поясненнями, тому цей варіант відкинув.

Потім почав експериментувати з API від штучного інтелекту. Почав з ChatGPT від OpenAI: він перекладав добре, але вартість була зависокою (близько $0,3–0,5 за 500 слів). Оскільки бот безкоштовний, це було невигідно.

Тепер трохи про те, як працює API різних AI-сервісів. Є 1 мільйон токенів на відправку та 1 мільйон токенів на отримання, тобто input / output. Було приблизно так:

AI Service

1 million tokens input, $ price

1 million tokens input, $ price

Chat GPT 4

$15

$15

Claude 3.5 sonnet

$3

$15

Простими словами, якщо ми відправимо слів на 1 мільйон символів, то це коштуватиме $15, але враховуючи видачу — ще додатково $15.

Тому я вибрав API від Anthropic — Claude AI. Трохи цифр та скринів для кращого розуміння цін:

За січень було використано AI на $4,03. Зауважу, що чистих коштів на користування сервісом іншими користувачами тут $2,70, тому що деякі слова я вирішив перекласти заново.

На скрині вище — статистика користування в червні. Тоді я вперше приблизно показав бота аудиторії. Користувачів було небагато.

Зараз аудиторія зросла, але для неї слова вже повторюються. Тобто якщо переклад слова вже раніше ініціювали інші користувачі, воно зберігається в базі, і бот не робить повторного запиту — це заощаджує кошти.

Утім, найбільше витрат іде не на переклад, а на перевірку граматики.

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

Тепер розберемо більш технічно, як це працювало спочатку. Всі застосунки у мене створені за шаблоном Worker Service .NET 8 та лежать у докер-контейнерах.

Я мав такі застосунки:

  • Сам телеграм-бот. Там є точка входу, куди надходять результати дій користувачів бота. Все, що він робить, — це CRUD (Сreate, Read, Update, Delete).
  • MessageSender — сервіс, що переглядає розклади користувачів у БД та надсилає слова за графіком.

Це все працювало з Entity Framework Core. Були деякі проблеми:

  • У телеграм-боті та MessageSender треба було писати функціонал рефрешу контексту, щоб мікросервіси бачили актуальний стан бази, тобто ChangeTracker.
  • Для реєстрації конекшну до БД у DI (Program.cs для Worker Service) треба було робити додаткові налаштування.
  • Робота з датами та супутніми операціями, враховуючи часові пояси, була незручною.

Тому я просто перейшов на Dapper ORM, що значно спростило життя. По-перше, зросла продуктивність бота. По-друге, мені просто зручніше писати SQL-запити вручну, а не розбиратися з особливостями Entity Framework. Я звик працювати з чистим SQL і люблю зберігати складну логіку у функціях або stored procedure :)

Але найбільший плюс у тому, що Dapper споживає менше пам’яті (RAM), що було критично важливо для мого сервера з обмеженими ресурсами. Я спеціально порівняв, скільки пам’яті використовують Dapper і Entity Framework Core — і Dapper виявився ефективнішим.

Ще одна проблема — спочатку я не зробив чергу повідомлень. Через це, коли користувач додавав нове слово, він мав чекати, поки бот отримає переклад. Це було незручно.

Щоб виправити це, я:

  • зробив докер-файл зі зразком RabbitMQ;
  • написав Consumer’и за допомогою MassTransit RabbitMQ — тепер слова автоматично відправляються реквестом у чергу на переклад;
  • оптимізував базу — тепер слово спочатку додається в БД без перекладу, а вже потім запит надходить до API Claude AI.

А ще я додав мікросервіс AIWorker — він інтервально перевіряє таблицю, чи є слова, які потрібно перекласти заново. Наприклад, якщо раніше перекладалося одне слово, а тепер я хочу отримати кілька варіантів значень, AIWorker оновить ці записи.

Інший корисний мікросервіс — TestsWorker. Він створює тести для користувачів і автоматично генерує запитання.

Це працює так: беремо 10 збережених слів користувача та створюємо тест. Шукаємо схожі слова, використовуючи алгоритм Левінштейна — він визначає, наскільки два слова схожі між собою. Що більше схожих літер у словах, то вищий counter, і це збільшує шанси на попадання цього слова у варіанти вибору в тесті. Тест можна отримати або одразу через консюмер, або він автоматично відправляється користувачам за розкладом.

Створення тестів — це найскладніша функціональність бота. Архітектура тестів гнучка і добре організована. Є таблиця з тестами, таблиця зі зв’язком, багато запитань до одного тесту. Є таблиця зі зв’язком один до одного: одна відповідь — одне запитання. Таблиця «Тести» має поля:

Завдяки цим полям я можу гнучко керувати тестами користувачів.

Бот підтримує українську та англійську мови. Раніше була й російська, але зараз її немає (про причини поговоримо далі).

Спочатку я використовував формат JSONB для зберігання перекладів у базі, але потім вирішив перейти на Key-Value формат з прив’язкою до LanguageId, тому в мене є такий клас:

Назва полів збігається з тим, що лежить у базі даних.

Коли мікросервіс запускається, ми реєструємо у DI пакети мов та підставляємо потрібні змінні, де це необхідно. Чим корисний такий підхід: достатньо буде в адмін-боті (такий у мене також є) змінити текст та перезапустити потрібні мікросервіси — код можна не змінювати.

Переїзди на різні хмарні сервіси

Від самого початку мій бот хостився на AWS, я використовував звичайний сервер EC2. Все було у докер-контейнерах, навіть бази даних. Утім, через обмеження ОЗУ (1 ГБ) довелося навіть до закінчення тріального періоду перейти на Google Cloud Platform (GCP), де надавали 4 ГБ ОЗУ (тріал був кращий, але коротший). Окрім того, у GCP були Managed Databases.

Перехід відбувся швидко і зайняв 1–2 години завдяки автоматизації. Я створив сервер на Linux, налаштував мережу для комунікації між сервером та базами даних. Зробив бекап своєї БД на AWS та запустив її. У цьому допомагав Артем Челак — крутий DevOps-інженер і гарний друг.

Нетехнічні проблеми

Тепер поговоримо про рекламні, продуктові та інші кейси, пов’язані з чатботом.

Спочатку бот підтримував російську мову, бо нею спілкуються деякі українці. Але коли я вперше запустив рекламу, помітив цікаву закономірність: деякі користувачі не завершували налаштування бота, коли бачили можливість вибору російської. Я вирішив зробити експеримент: відключив російську під час реєстрації. Результат — кількість таких користувачів суттєво зменшилася. Згодом деякі люди просили повернути російську, і я вручну додавав можливість її обрати.

Одного разу ботом почав користуватись юзер, чий номер містив код регіону РФ, а аватарку «прикрашала» буква Z. Після цього я написав функціонал для блокування певних chatId, повністю вилучив російську мову з бота, а також додав у шапку український прапор:

Але навіть після цього деякі користувачі з РФ намагалися користуватися ботом, бо «в них немає аналогів».

Цікавий кейс про донати. Раз на місяць я закликаю користувачів зробити будь-який внесок, щоб покрити витрати на сервери та AI. Однак що очевидніше я про це пишу, то більше людей блокують бота. Якщо просто вказати команду /donate_info, користувачі майже не зайдуть туди.

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

У зв’язку з цим поговоримо про лінь користувачів. Раніше бот просто нагадував про можливість пройти тест. Це працювало погано — користувачам було лінь заходити в меню та запускати тест. Через деякий час я зрозумів: чому б не надсилати вже готовий тест одразу в повідомленні? Я був здивований, наскільки зросла активність. До тестів долучалися користувачі, які жодного разу їх не проходили, а дехто навіть почав створювати тести самостійно.

Цей проєкт створений під час блекаутів. Я був обмеженим у тестуванні написаного коду, не міг дебажити деякі його великі ділянки. Хоча в мене була зарядна станція, але вона мала обмежений ресурс. І під час запуску проєкту навантаження на комп’ютер зростало — це швидше садило батарею. Тому бувало, що я писав багато коду, а помилки виправляв набагато пізніше, навіть на наступний день. Це навчило мене писати код більш обдумано і не покладатися на IDE.

Пошук цільової аудиторії

Голосуйте в Премії DOU 2025!:star2:

З огляду на весь час роботи над ботом я можу виділити такі методи залучення користувачів:

  • Реклама в телеграм-каналах, де вивчають англійську.
  • Пост у Linkedin (став популярним, отримав багато репостів).
  • Пост у телеграм-каналі із вакансіями (адмін одного популярного IT-каналу побачив бота і поділився ним).

Пробував робити те саме в TikTok, але важко оцінити результати. Не спрацювала і таргетована реклама в інстаграмі за $5 — це не дало результату, бо я не профі у цьому.

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

Що ж до Linkedin, то пост був спробою просто поділитися проєктом, але за щасливим збігом він потрапив у рекомендації. Користувачі тепло відреагували та репостили допис. Саме так, до речі, мені пощастило з DOU :)

Висновки

  • Читайте документацію уважно.
  • Давайте користувачам безпосередньо функціональність, де це можливо, а не просто інформацію про її наявність.
  • Завжди порівнюйте сервіси перед остаточним рішенням.
  • Архітектура важлива, використовуйте шаблони проєктування.
  • Подумайте про підписки та платну функціональність — це краще, ніж заклики про донати.
  • Часті оновлення та патч-ноти зменшують відтік аудиторії.
  • Аналізуйте дії користувачів та адаптуйте функціонал.

Подяки

  • Artem Chelak — за допомогу з DevOps та GCP.
  • Alla Mazur та Inna Tregubenko — за допомогу з тестуванням і виявлення важливих багів.
  • Mariia Vasylieva, Mike Zlatov, Yurii Mymrin та Stanislav Didenko — запропонували багато ідей, які я реалізував.
  • HYS Enterprise — підтримали проєкт усередині компанії на самому початку шляху, а деякі колеги ще й допомогли донатами.
👍ПодобаєтьсяСподобалось25
До обраногоВ обраному12
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Пет-проєкт це круто.
Успіхів.
Пробували шукати вже готовий ведосипед?

Привіт! Дуже цікава стаття та бот — було цікаво оцінити ваш підхід та висновки. Приємно, що я також є автором схожого бота зі схожим стеком, хоча мій значно простіший. Мій чат-бот t.me/PhrasalFlow/14 допомагає вивчати фразові дієслова, працюючи за принципом флеш-карток із простими нагадуваннями. Я прагнув створити бота з мінімальними витратами, тому за допомогою OpenAI API згенерував усі дані наперед, зберіг їх у Blob Storage на Azure та налаштував Azure Functions за розкладом. У результаті мені вдалося досягти вартості всього 4 центи на місяць.

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

Цікаво, як реалізується деплоймент нових версій?

І що сталося з міграціями бази даних після відмови від EF Core? При всій моїй любові до Dapper’а, міграції EF — це, на мою думку, кілєр фіча, яка працює одразу із коробки. Для Dapper’а завжди треба було прикручувати щось стороннє.

Доброго вечора! Дякую за гарні слова

Цікаво, як реалізується деплоймент нових версій?

Ви маєте на увазі оновлення? В мене налаштований CI/CD, тому все по класиці — або якщо мерджу в мастер, то збираться образ та потім використовую на сервері його автоматично. Буває, що без мерджу хочу потестити нову версію на проді, — приблизно такий самий флоу. Також роблю патч-ноути та роблю розсилку, щоб користувачі бачили що вого є

І що сталося з міграціями бази даних після відмови від EF Core?

Та я просто видалив їх. Видалив усе, що було пов’язано з EF. Та доводиться у завжди у коментарях до МР писати запити, та зміни для БД. Тут я костильно це вирішив)

Але найбільший плюс у тому, що Dapper споживає менше пам’яті (RAM), що було критично важливо для мого сервера з обмеженими ресурсами.

В мене бот на .NET 9 та ef core споживає 35 мб ram. Хоститься все на monsterasp.net безкоштовно (база+аппка) які там трабли з ram — я хз.

У телеграм-боті та MessageSender треба було писати функціонал рефрешу контексту, щоб мікросервіси бачили актуальний стан бази, тобто ChangeTracker.

Взагалі не зрозуміло про що мова там і так на кожному реквесті актуальний стан.

Для реєстрації конекшну до БД у DI (Program.cs для Worker Service) треба було робити додаткові налаштування.

Це взагалі лол.

Робота з датами та супутніми операціями, враховуючи часові пояси, була незручною.

В чому незручність?

Для цього я використав патерни Factory та Command — вони допомогли налаштувати інтерфейс так, щоб кнопки змінювалися залежно від дій користувача

Ні, ну якщо так плодити обʼєкти в памʼяті то і 4гб мало буде.
github.com/...​t-state-machine/stateless

В мене бот на .NET 9 та ef core споживає 35 мб ram. Хоститься все на monsterasp.net безкоштовно (база+аппка) які там трабли з ram — я хз.

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

Привіт! Ти проробив велику роботу і за це ти молодець, але твій БОТ немає ніякого сенсу, оскільки він видає слова без ТРАНСКРИПЦІЇ. Ось дивись, я вчу англійську і мені потрібно копіювати кожне нове слово і шукати транскрипцію на інших ресурсах, бо незнаю як правильно воно читається, де ставити наголос. Ну ти мене зрозумів!

Транскрипцію в МФА можна подивитись в будь-якому словнику, наприклад, Словнику Вебстера. А вимову в різних акцентах на Forvo, наприклад. Я б дуже рекомендував вивчити МФА — реально допомагає в освоєнні мов.

бот хостився на AWS... через обмеження ОЗУ (1 ГБ) довелося ... перейти на Google Cloud Platform (GCP), де надавали 4 ГБ ОЗУ (тріал був кращий, але коротший).

Рекомендую одразу на VPS, наприклад Hetzner www.hetzner.com/cloud

2 vCPU, 4 GB RAM, 20 GB SSD, 20 TB traffic = $ 4.59/місяць

Так, це 200 грн на місяць, але це добрі гроші за чесний сервіс. AWS та GCP це гроші на вітер.

Почав з ChatGPT від OpenAI: він перекладав добре, але вартість була зависокою

В мене є випадок, коли у своєму застосунку (LMS допомагає студентам виконувати завдання з програмування) змінив з gpt-4o на gpt-4o-mini, та воно стало давати відповідь швидше і лаконічніше, ніж з повною моделлю. Та і у 2 рази дешевше. У вас може gpt-3 навіть спрацює добре. Окрім цього запити на переклад та результати тестів можна закешувати в БД та не робити повторні запити в AI.

Окремо про корисні функції: я собі в ChatGPT зробив чат, де воно мені на англійське слово або фразу пише визначення, контекст застосування та переклад на українську. Воно мені допомагає читати книги англійською. Тобто не просто переклад, а переклад з варіантами контексту.

Щодо донатів: мабуть треба давати посилання десь одразу після успішної сесії з додатком. Тому що я зайшов закинути вам +1000 грн на сервери та одразу й не побачив посилання на донат.

А так круто, успіхів!

Дякую велике за поради, думки, та за донат! Цей донат найбільший за усю історію бота! Я в шоці, ви тільки поклацали його, а вже такий донат :)

Стосовно серверу, я чомусь не написав що використовую зараз. Використовую contabo.com/en
Starts with 2 vCPU, 6 GB RAM, and 50 GB NVMe.
З серпня почав десь, дуже подобається

Дуже цікаво будет подивитись нові моделі у роботі для бота. Та зрівняти ціни. Зараз поки що задоволений Claude AI, але є нюанси, контекст, до речі там також є

А от стосовно донатів — я не знаю як правильно, мені завжди здавалося, що людям не хочеться так багато налаштувань, як в мене імплементовано зараз, а якщо буду «насипати» про донати у момент реєстрації, то взагалі заблочать)

Дякую, гарна робота! :)
Прорекламую схожий телеграм бот t.me/PocketAnkiBot
Dokku, Python/aiogram, OpenAI (+DeepSeek) для автоматичного створення карток, Spaced Repetition, etc.
Пишу незнайоме слово будь якою мовою і він створює картку, його можна використовувати як перекладач з функцією створення карток для інтервального запам’ятовування

Дякую за коментар, та гарні слова, вже поклацав вашого бота — цікава задумка, сподобались зірочки)

res.cloudinary.com/...​/sx9itw81jbtbgvzjt0n6.png

а де інші таймзони? MST (-7:00) наприклад, і коли настає DST треба змінювати на ±1

треба буде додати
ще недодава, бо не думав, що це зайде кудись))

Топовий бот, убийца Duolingo получается >:)

Ну, Дуолінго — це дно в плані якості. Тому є куди рости.

Підписатись на коментарі