
Приветствую!
Сегодня будем писать бота для хранения истории личных сообщений
Безусловно, идея не уникальная: часть людей уже использует неофициальные клиенты, другая – юзерботов (например, на pyrogram)
Тогда что здесь?
Официальный бизнес-режим бота, не нарушающий TOS, работающий 24/7 и за который не сносят аккаунты (!)
Ближе к делу

Создание бота (Для новичков)
Зайдите в бота @BotFather
Напишите /newbot и как-нибудь обзовите бота, например "Уведомления"
Придумайте ему @юзернейм, подходят только латинские буквы, цифры и нижнее подчеркивание, обязательно напишите "bot" в конце
Бот готов – скопируйте и сохраните токен
Настройте бота:
Напишите /mybots и выберите своего бота
Edit Bot -> Edit Botpic -> Отправьте аватарку для бота
Back to Bot -> Bot Settings -> Business Mode -> Turn On
Написание бота
Стек: python 3.12, aiogram, redis, docker
(Ссылка на GitHub репозиторий внизу статьи)
Для начала придумываем файловую структуру, что-то типа:
.
├── main.py # Запуск бота
├── pyproject.toml # Управление зависимостями Poetry
├── Dockerfile # Инструкции для сборки Docker образа
├── docker-compose.yml # Конфигурация Docker контейнеров (бот + redis)
├── .env # Переменные окружения (токен, настройки)
└── src/
├── bot.py # Основная логика бота, хендлеры
├── keyboards.py # Клавиатуры и коллбэки
└── settings.py # Pydantic парсер .env файлаТеперь нужно установить библиотеки:
poetry add aiogram pydantic pydantic_settings loguru redispyproject.toml должен получится таким:
[tool.poetry]
name = "business-bot"
version = "0.1.0"
description = ""
authors = []
readme = "README.md"
[tool.poetry.dependencies]
python = "^3.12"
aiogram = "^3.13.1"
loguru = "^0.7.2"
redis = "^5.2.0"
pydantic = "^2.9.2"
pydantic-settings = "^2.6.0"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"Далее прописываем конфиг в settings.py, используя pydantic_settings, который парсит .env:
REDIS_HOST,REDIS_PORT,REDIS_PASSWORDпо умолчанию устанавливаются вdocker-compose.yml, но они нужны, если Вы будете запускать бота вне контейнера, используя локальный/облачный редис
from typing import Optional
from pydantic import SecretStr
from pydantic_settings import BaseSettings, SettingsConfigDict
class Environment(BaseSettings):
model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8")
class Redis(Environment):
REDIS_HOST: str = "localhost"
REDIS_PORT: int = 6379
REDIS_PASSWORD: Optional[SecretStr] = None
class Bot(Environment):
TOKEN: SecretStr = SecretStr("7285627548:FaGPjgAJFU8G524HE38hubGrgTcQcrpmbyc")
class Settings(Bot, Redis):
USER_ID: int = 0
settings = Settings()И соответственно настраиваем .env файл:
Токен бота ранее доставали из Bot Father
Свой ID можно получить с помощью @getmyid_bot
TOKEN="7285627548:FaGPjgAJFU8G524HE38hubGrgTcQcrpmbyc"
USER_ID=123456789Прописываем переменные проекта в bot.py:
from aiogram import Bot, Dispatcher
from redis.asyncio import Redis
from .settings import settings
bot = Bot(token=settings.TOKEN.get_secret_value())
dp = Dispatcher()
redis = Redis(
host=settings.REDIS_HOST,
port=settings.REDIS_PORT,
password=(
settings.REDIS_PASSWORD.get_secret_value()
if settings.REDIS_PASSWORD else None
),
)и используем их в main.py для запуска:
from loguru import logger
from src.bot import dp, bot
if __name__ == "__main__":
logger.info("Starting...")
dp.run_polling(
bot,
allowed_updates=[
"callback_query",
"business_message",
"edited_business_message",
"deleted_business_messages",
],
)
Важно! aiogram по умолчанию слушает только следующие хэндлеры:
message,callback_query,errors. Остальные он автоматически не парсит и их нужно добавлять вручную черезallowed_updates.
В файле bot.py сохраняем все новые сообщения в Redis с авто-удалением через 3 недели:
EX_TIME = 60 * 60 * 24 * 21
async def set_message(message: types.Message):
await redis.set(
f"{message.chat.id}:{message.message_id}",
message.model_dump_json(),
ex=EX_TIME,
)
@dp.business_message()
async def message(message: types.Message):
await set_message(message)Теперь нужно как-то красиво сообщать об изменении статуса сообщений. Лучшим вариантом я считаю добавление inline клавиатуры, так не будет редактироваться исходное сообщение.
Первой кнопкой будет статус сообщения – ✏️ или
