Давно уже было желание сделать что-то простое и полезное в Telegram, но чтобы не пришлось постоянно за этим следить. И вот пришла гениальная идея: чтобы быть всегда замотивированным, можно написать бота, который будет (с какой то периодичностью) сам отправлять мотивационные цитаты в канал?
Этот бот берёт случайные цитаты известных людей из интернета, переводит их на русский язык и отправляет в Telegram-канал по расписанию. Например, утром, днём, вечером и ночью. Звучит просто, правда? Но внутри этого проекта есть всё, что нужно для обучения: чистая архитектура, работа с API, планировщик задач и даже деплой на облачную платформу Railway.
Весь код писать сюда будет довольно избыточно поэтому, это не пошаговое руководство, а просто обзор проекта. Ещё хочу сказать, что мне нравиться как генерирует изображение ChatGPT и я даже поставил на обложку. Раньше, конечно, качество изображений оставляло желать лучшего.
Что в итоге получилось и код проекта можно найти по этим ссылкам.
1. Архитектура проекта
Чтобы проект был удобным для разработки, тестирования и поддержки, я решил использовать чистую архитектуру . Это подход, который помогает разделить код на слои, чтобы каждый выполнял свою задачу, не мешая другим. Давайте разберёмся, как это работает в моём проекте.
Я выделил четыре основных слоя:
Entities (Сущности):
Это базовые структуры данных, например, Quote (цитата). Они описывают, как выглядят данные в программе.
Пример: цитата состоит из текста и автора.
Use Cases (Бизнес-логика):
Здесь находится "сердце" приложения — логика работы с данными.
Например, получение цитаты, её перевод и отправка в Telegram.
Interfaces (Интерфейсы):
Это абстракции для взаимодействия с внешними системами. Например, интерфейс для работы с API цитат или Telegram Bot API.
Интерфейсы позволяют легко менять реализацию без изменения остального кода.
Adapters (Адаптеры):
Реализация интерфейсов. Например, адаптер для ZenQuotes API или Telegram Bot API.
Эти модули "общаются" с внешним миром, но скрывают детали от остальной программы.
Такое разделение делает проект гибким, поскольку позволяет заменять отдельные компоненты, например, источник цитат, без переписывания всего кода; тестируемым, так как каждый слой можно проверять независимо от других; и поддерживаемым, потому что чёткая структура помогает быстро разобраться в коде, даже если вы вернулись к проекту спустя время.
2.Создание Telegram-бота
Чтобы создать Telegram-бота, выполните следующие шаги:
Откройте Telegram и найдите бота @BotFather .

Начните диалог с ним и используйте команду /newbot, чтобы создать нового бота.

Следуйте инструкциям:
Придумайте имя бота (например, MotivatorBot).
Укажите username бота (например, motivator_bot).
После создания бота вы получите токен, который выглядит примерно так:

Этот токен понадобится для взаимодействия с Telegram Bot API.
Важно: Не делитесь токеном с другими людьми и не публикуйте его в открытом доступе!
3.Создание Telegram-канала
Откройте Telegram и нажмите на значок меню (три полоски).
Выберите "Новый канал".
Укажите название канала (например, "Мотиватор") и добавьте описание.
Установите тип канала: "Публичный" или "Приватный".
Чтобы бот мог отправлять сообщения в канал, его нужно сделать администратором:
Откройте настройки канала.
Перейдите в раздел "Администраторы".
Нажмите "Добавить администратора".
Найдите вашего бота по имени (например, motivator_bot) и добавьте его.
3. Как получить CHAT_ID
CHAT_ID — это уникальный идентификатор канала, который нужен для отправки сообщений.
Добавьте бота @userinfobot в свой Telegram.
Отправьте ему любое сообщение из созданного канала.
Бот ответит информацией о chat_id вашего канала. Для каналов этот ID обычно начинается с -100.
Пример CHAT_ID:
-1001234567890Важно: Сохраните CHAT_ID — он понадобится для настройки бота.
Итого
Теперь у вас есть всё необходимое для начала разработки:
Создан Telegram-бот и получен его токен.
Создан канал, добавлен бот в администраторы и получен CHAT_ID.
В следующем разделе мы перейдём к реализации логики бота.
4. Разработка бота
4.1. Структура проекта
Чтобы проект был организован логично и удобен для разработки, я разделил его на несколько папок и файлов. Вот как выглядит структура:
telegram-quotes-bot/
├── go.mod # Файл для управления зависимостями Go Modules.
├── go.sum # Список контрольных сумм для зависимостей.
├── cmd/ # Директория с точкой входа в приложение.
│ └── main.go # Главный файл, где запускается бот.
├── internal/ # Внутренние пакеты проекта.
│ ├── config/ # Конфигурация приложения.
│ │ └── config.go # Загрузка переменных окружения.
│ ├── adapters/ # Адаптеры для работы с внешними сервисами.
│ │ ├── telegram_adapter.go # Адаптер для Telegram Bot API.
│ │ ├── zenquotes.go # Адаптер для ZenQuotes API (получение цитат).
│ │ └── mymemory.go # Адаптер для MyMemory API (перевод текста).
│ ├── usecases/ # Бизнес-логика приложения.
│ │ ├── fetch_quote.go # Получение цитаты.
│ │ ├── translate.go # Перевод текста.
│ │ └── send_quote.go # Отправка цитаты в Telegram.
│ └── interfaces/ # Интерфейсы для ��заимодействия с внешними системами.
│ ├── api.go # Общие интерфейсы для API.
└── Dockerfile # Файл для сборки Docker-образа.cmd/main.go: Это точка входа в программу. Здесь инициализируется всё приложение: загружаются конфигурации, создаются адаптеры и запускается планировщик Cron.
internal/config: Здесь находится код для работы с переменными окружениями. Это позволяет легко управлять настройками проекта.
internal/adapters: Адаптеры — это модули, которые "общаются" с внешними сервисами (например, Telegram, ZenQuotes, MyMemory). Если что-то изменится в API, нужно будет править только этот слой.
internal/usecases: Здесь находится бизнес-логика приложения. Например, получение цитаты, её перевод и отправка в Telegram.
internal/interfaces: Интерфейсы описывают, как должны работать адаптеры. Это делает код более гибким: можно заменить реализацию адаптера, не трогая остальной код.
Dockerfile: Этот файл нужен для сборки Docker-образа, чтобы запустить бота на облачной платформе, например, Railway.
Такая организация помогает держать код в порядке, особенно если проект будет расти или меняться.
4.2. Бизнес-логика
Бизнес-логика — это сердце приложения, где происходят все основные действия: получение цитат, их перевод и отправка в Telegram.
Получение цитат
Чтобы получить случайную цитату, бот отправляет HTTP-запрос к ZenQuotes API. Вот как это работает:
Ссылка для запроса:
https://zenquotes.io/api/randomЭтот запрос возвращает JSON с одной случайной цитатой.
Пример ответа:
[
{
"q": "The best way to predict the future is to create it.",
"a": "Peter Drucker"
}
]Обработка ответа:
Бот извлекает текст цитаты (q) и имя автора (a).
Если что-то пошло не так (например, API недоступен), бот логирует ошибку и пробует снова.
Перевод текста
Цитаты на английском нужно перевести на русский язык. Для этого используется MyMemory API.
Ссылка для запроса:
https://api.mymemory.translated.net/get?q=текст&langpair=en|ruЗдесь текст — это текст цитаты, который нужно перевести.
Пример ответа:
{
"responseData": {
"translatedText": "Одна ошибка и ты ошибся"
}
}Обработка ошибок перевода:
Если API вернул пустой перевод или произошла ошибка, бот отправляет оригинальный текст цитаты.
Логируются все проблемы, чтобы можно было разобраться с ними позже.
Отправка сообщений
После того как цитата переведена, её нужно отправить в Telegram-канал. Для этого используется Telegram Bot API.
Форматирование сообщений с эмодзи:
Чтобы сообщения выглядели красиво, я добавил эмодзи:
📖 Одна ошибка и ты ошибся.
— Сократ ✍️Отправка сообщения:
Бот использует метод sendMessage Telegram Bot API.
Пример запроса:
{
"chat_id": "-1001234567890",
"text": "📖 Одна ошибка и ты ошибся.\n\n— Сократ ✍️"
}Обработка ошибок:
Если сообщение не отправилось (например, из-за проблем с интернетом), бот повторяет попытку.
Все ошибки логируются, чтобы можно было быстро найти проблему.
Как это всё работает вместе?
Бот запрашивает случайную цитату у ZenQuotes API.
Полученный текст отправляется в MyMemory API для перевода на русский язык.
Переведённая цитата форматируется с эмодзи и отправляется в Telegram-канал через Telegram Bot API.
Если что-то пошло не так (например, API недоступен), бот обрабатывает ошибку и продолжает работу.
Так устроена бизнес-логика бота. В следующем разделе рассмотрим, как настроить планировщик задач Cron, чтобы бот отправлял цитаты в определённое время.
4.3. Планировщик задач
Чтобы бот отправлял цитаты в Telegram-канал по расписанию, я использовал планировщик задач Cron. Этот инструмент позволяет запускать определённые действия в заданное время. Разберём, как настроить Cron и как логировать его работу.
Настройка Cron
Cron работает с помощью специальных выражений, которые задают время выполнения задачи. В нашем случае бот отправляет цитаты утром, днём, вечером и ночью — это можно настроить с помощью Cron-выражения.
Формат Cron-выражения:
┌──────────── минуты (0–59)
│ ┌────────── часы (0–23)
│ │ ┌──────── день месяца (1–31)
│ │ │ ┌────── месяц (1–12)
│ │ │ │ ┌──── день недели (0–6, где 0 — воскресенье)
│ │ │ │ │
* * * * *Пример Cron-выражения для нашего бота:
Если мы хотим отправлять цитаты в 8:00, 12:00, 18:00 и 22:00 UTC, выражение будет выглядеть так:
0 8,12,18,22 * * *0: Минута (в начале часа).8,12,18,22: Часы (8:00, 12:00, 18:00, 22:00 UTC).*: Любой день месяца.*: Любой месяц.*: Любой день недели.
Если вы хотите, чтобы бот отправлял цитаты каждые 30 минут, используйте следующее Cron-выражение:
*/30 * * * *Как перевести время в UTC? Если ваше время отличается от UTC (например, самарское время опережает UTC на 4 часа), нужно перевести расписание:
8:00 SAMT → 4:00 UTC
12:00 SAMT → 8:00 UTC
18:00 SAMT → 14:00 UTC
22:00 SAMT → 18:00 UTC
Тогда Cron-выражение для самарского времени будет:
0 4,8,14,18 * * *Чтобы следить за работой планировщика, я добавил логирование всех ключевых шагов: при запуске задачи бот записывает в лог сообщение [INFO] Задача отправки цитаты запущена, при ошибках (например, недоступность API или сбой отправки) фиксируется проблема в формате [ERROR] Ошибка при получении цитаты: таймаут запроса, а при успешной отправке цитаты логируется информация вида [INFO] Цитата успешно отправлена: "Одна ошибка и ты ошибся.". Для удобства анализа я использую библиотеку log/slog из стандартной библиотеки Go, которая позволяет форматировать логи в JSON.
Как это работает вместе?
Cron запускает задачу отправки цитаты в указанное время.
Бот выполняет все шаги: получает цитату, переводит её и отправляет в Telegram.
Все действия записываются в логи для дальнейшего анализа.
5. Безопасность и переменные окружения
Для безопасной работы бота важно правильно хранить данные, такие как токен Telegram-бота и ID канала. Эти данные не должны попадать в открытый доступ, например, в репозиторий GitHub. Разберём, как организовать их хранение и загрузку.
Хранение данных
Для ло��альной разработки я использую файл .env, который хранит все переменные окружения. Вот пример такого файла:
BOT_TOKEN=123456789:AAFwz3QxYzZzZzZzZzZzZzZzZzZzZzZz
CHAT_ID=-1001234567890Файл .env добавляется в .gitignore, чтобы он не попал в репозиторий. Для загрузки переменных из .env используется библиотека github.com/joho/godotenv.
Настройка переменных окружения на Railway
Когда проект развёрнут на Railway, переменные окружения настраиваются через веб-интерфейс.
Безопасная загрузка переменных в код
Чтобы избежать проблем с отсутствием переменных окружения, я добавил проверки и обработку ошибок:
1. Проверка наличия переменных:
Перед использованием переменных бот проверяет, что они существуют. Если какая-то переменная отсутствует, программа завершается с ошибкой:
botToken := os.Getenv("BOT_TOKEN")
chatIDStr := os.Getenv("CHAT_ID")
if botToken == "" || chatIDStr == "" {
logger.Error("Необходимые переменные окружения отсутствуют", "BOT_TOKEN", botToken, "CHAT_ID", chatIDStr)
os.Exit(1)
}2.Обработка ошибок:
Если значение переменной (например, CHAT_ID) не может быть преобразовано в нужный формат, бот также завершает работу с логированием ошибки:
chatID, err := strconv.ParseInt(chatIDStr, 10, 64)
if err != nil {
logger.Error("Ошибка преобразования CHAT_ID в int64", "error", err)
os.Exit(1)
}3.Логирование:
Все действия с переменными окружениями логируются для удобства отладки:
logger.Info("Переменные окружения загружены", "BOT_TOKEN", botToken, "CHAT_ID", chatID)7. Деплой на Railway
Railway — это облачная платформа для развёртывания приложений, которая позволяет ��ыстро запускать проекты без необходимости настройки серверов. Она поддерживает автоматический деплой из GitHub, что делает процесс максимально простым. Railway идеально подходит для небольших проектов, таких как Telegram-бот, благодаря удобному интерфейсу, бесплатному тарифу и встроенной поддержке Docker.
Шаги деплоя
1. Создание проекта на Railway
Зарегистрируйтесь на Railway или войдите в свой аккаунт.
Нажмите "New Project" и выберите "Deploy from GitHub Repo".
Выберите репозиторий с вашим проектом.
2. Настройка переменных окружения
Перейдите в раздел "Variables" вашего проекта на Railway.
Добавьте переменные окружения:
BOT_TOKEN=ваш_токен_бота
CHAT_ID=ваш_chat_id3. Dockerfile для сборки образа
FROM golang:1.20-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o bot ./cmd
FROM alpine:latest
COPY --from=builder /app/bot /bot
CMD ["/bot"]Railway автоматически найдёт Dockerfile и соберёт образ.
4. Автоматический деплой через GitHub
Свяжите Railway с вашим GitHub-репозиторием.
Настройте автоматический деплой при каждом обновлении кода.
После первого коммита Railway соберёт и запустит проект.
Итоги
Получился Telegram-бота, который автоматически отправляет мотивационные цитаты в канал по расписанию. В процессе разработки мы научились работать с Telegram Bot API для отправки сообщений, использовали внешние API (ZenQuotes и MyMemory) для получения и перевода цитат, реализовали планировщик задач с помощью Cron и освоили развёртывание приложения на облачной платформе Railway. Этот проект помог нам приобрести важные навыки: работу с API, чистую архитектуру, логирование, безопасное хранение данных и деплой приложений. Теперь у вас есть готовый инструмент, который можно дорабатывать и адаптировать под свои нужды, а также база для создания новых Telegram-ботов.
