Введение
В данной статье мы рассмотрим архитектуру и реализацию Telegram-бота Kalorik, написанного на языке программирования Rust. Этот бот предоставляет пользователям возможность анализировать свой рацион питания, получая автоматический расчёт калорий, макроэлементов и индекса массы тела. Особенностью проекта является использование современного стека на основе tokio, sqlx, teloxide, а также продуманная архитектура с учётом масштабируемости.
Задачи, решаемые ботом
Kalorik реализует следующие функции:
-
Обработка текстовых сообщений с описанием приёма пищи
-
Распознавание изображений и голосовых сообщений
-
Подсчёт калорий, БЖУ, ИМТ
-
Хранение истории и профиля пользователя
-
Настройка целей и отслеживание прогресса
Архитектура проекта
Проект состоит из следующих ключевых модулей:
-
main.rs— точка входа, инициализация окружения и запуск бота -
telegram/handlers.rs— обработка входящих сообщений Telegram -
db/queries.rs— доступ к базе данных (PostgreSQL черезsqlx) -
db/models.rs— структура таблиц и моделей -
services/nutrition.rs— логика анализа продуктов и подсчёта нутриентов
Проект построен с использованием OnceLock для глобального пула соединений с базой данных и асинхронного исполнения через tokio.
Пример: Регистрация пользователя
pub async fn register_user(chat_id: i64) -> Result<(), sqlx::Error> { let Some(pool) = DB_POOL.get() else { return Err(sqlx::Error::PoolTimedOut); }; sqlx::query!( r#" INSERT INTO users (chat_id, created_at) VALUES ($1, $2) ON CONFLICT (chat_id) DO NOTHING "#, chat_id, Utc::now() ) .execute(pool) .await?; Ok(()) }
Здесь реализуется вставка пользователя в таблицу, если он отсутствует. Используется UPSERT-подход, обеспечивающий идемпотентность.
Работа с Telegram
match &msg.kind { MessageKind::Common(msg) => match &msg.media_kind { MediaKind::Text { text, .. } => { if text == "/start" { register_user(msg.chat.id).await?; bot.send_message(msg.chat.id, "Введите описание приёма пищи").await?; } else { let result = analyze_food_description(text).await; bot.send_message(msg.chat.id, result).await?; } } MediaKind::Photo { photo, .. } => { // Обработка фото через модель } MediaKind::Voice { voice, .. } => { // Обработка голосовых сообщений } _ => {} } _ => {} }
Здесь представлен разбор варианта обработки текста и мультимедиа. Используется teloxide, который предоставляет удобный API для работы с Telegram Bot API.
Хранение и миграции
let db_url = env::var("DATABASE_URL").expect("DATABASE_URL not set"); let pool = PgPoolOptions::new().connect(&db_url).await?; sqlx::migrate!("./migrations").run(&pool).await?;
Проект использует sqlx с автоматическим применением миграций. Миграции хранятся в отдельной папке и обеспечивают прозрачность в изменениях схемы.
Развёртывание
Бот может быть запущен как systemd-сервис или Docker-контейнер. Пример systemd unit-файла:
[Unit] Description=Kalorik Telegram Bot After=network.target [Service] ExecStart=/usr/local/bin/kalorik WorkingDirectory=/var/www/kalorik Restart=always Environment=DATABASE_URL=postgres://... [Install] WantedBy=multi-user.target
Также возможно подключение GitHub Actions для CI/CD и обновления контейнера при пуше в main ветку.
Заключение
Kalorik демонстрирует, как на Rust можно создать безопасного и надёжного Telegram-бота с использованием производительных и типобезопасных библиотек. Благодаря sqlx, tokio и teloxide, разработка получилась эффективной и лаконичной. Проект легко масштабируется и адаптируется под другие задачи, связанные с пользовательскими данными или обработкой сообщений.
Проект открыт для расширений: можно добавить мини-приложение, авторизацию через Telegram Web App, отчёты по питанию, интеграцию с OpenAI или Hugging Face для анализа описаний еды.
Попробовать бота @kalorikbot
Репозиторий проект, где находится весь код https://github.com/digkill/Kalorik
ссылка на оригинал статьи https://habr.com/ru/articles/910298/
Добавить комментарий