diff --git a/README.en.md b/README.en.md index 19ac620..797cffd 100644 --- a/README.en.md +++ b/README.en.md @@ -18,16 +18,22 @@ The bot speaks Russian. **Status:** personal project, running since 2021 · bot [@chat_abobot](https://t.me/chat_abobot) · over 20,000 users from 45 chats in the bot's database (October 2026) -**Stack:** Python 3.12 · aiogram 3 · pymorphy3 · pyenchant · SpeechRecognition · gTTS · SQLite · Docker +**Stack:** Python 3.10+ · aiogram 3 · PostgreSQL (asyncpg) · pymorphy3 · pyenchant · SpeechRecognition · gTTS · Docker ## Features - **Name mentions.** Words of a message are reduced to their base form (pymorphy3) and compared with members' names, so any grammatical case of a name mentions the right person. A custom name can be set with `/edit`. Names are also found in voice notes up to a minute long. -- **`/all`** mentions every member. +- **`/all`** mentions every member. A long list is split into several messages. +- **Big chats (over 100 members).** + - `/all` is for admins only, at most once in 5 minutes, and only for people who wrote in the last 30 days. + - The same person is mentioned by name at most once a minute. - **All-time and monthly statistics** (`/stat_group`, `/stat_user`): messages, replies, commands, links, - media, stickers, voice and video notes. Monthly numbers reset at the start of each month. + media, stickers, voice and video notes. Months are kept, so `/month 2026-09` shows any month's summary + and `/top` shows the most active members for the month or all time (`/top all`). +- **`/settings`** — per-chat switches: name mentions, names in voice notes (audio goes to Google), text + events, deleting service messages. Admins can change them. - **Wrong keyboard layout.** A message like `ghbdtn` is repeated as «привет». English words are recognized with a dictionary (pyenchant) and left alone. - **Voice.** `/recognize` as a reply to a voice note transcribes it; «Озвучь - текст» turns text into a @@ -39,37 +45,56 @@ The bot speaks Russian. - mock fights; - picture reactions. - Turned off with `/stop_bot`. + Turned off with `/stop_bot` or in `/settings`. - Deleting service messages (joins, leaves, title and photo changes) when the bot is an admin. +- **Tracking the bot in groups.** The bot records which groups it is in and with which rights: Telegram + events plus a check on start and every 6 hours. Changes are kept as history. If the bot is removed, the + group's statistics stay; only the mark that the bot is no longer there changes. ## Running ```bash git clone https://github.com/EDeev/chatping_abobot.git && cd chatping_abobot cp .env.example .env # BOT_TOKEN from @BotFather -docker compose up -d +docker compose up -d # the bot and PostgreSQL ``` Prebuilt image: `docker pull ghcr.io/edeev/chatping_abobot` or `docker pull dcr.deev.su/edeev/chatping_abobot`. -The SQLite databases are created on first start. +Tables are created on first start (`code/schema.sql`). -Without Docker you need Python 3.12, the enchant system library and an English dictionary -(`apt install libenchant-2-2 hunspell-en-us`). Then: `pip install -r requirements.txt` and -`cd code && BOT_TOKEN=… python bot.py`. +Without Docker you need: +- Python 3.10+; +- PostgreSQL; +- the enchant system library with an English dictionary (`apt install libenchant-2-2 hunspell-en-us`). + +Then: `pip install -r requirements.txt` and `cd code && BOT_TOKEN=… DATABASE_URL=postgresql://… python bot.py`. + +Migrating data from the old version (four SQLite databases): +`python scripts/migrate_sqlite.py --sqlite-dir path/to/db --dsn postgresql://…`. The script checks the +totals after the transfer. + +## Deployment + +[@chat_abobot](https://t.me/chat_abobot) runs on a home server as a systemd service: its own venv, settings in +`/etc/abobot.env`, PostgreSQL on the same server. The nightly backup dumps the database, and the statistics +feed a Metabase dashboard. ## How it works ``` -code/bot.py entry point and monthly statistics reset -code/handlers.py message, command, voice and event handlers -code/script.py statistics, name lookup, keyboard layout, text reversal -code/sql.py four SQLite databases: groups, users, all-time and monthly statistics -data/ event pictures and the greeting +code/bot.py entry point, error reports to a tech chat, checking the bot's status in groups +code/handlers/ routers: help, settings, stats, mentions, voice, events, chat (bot in groups, service messages) +code/db.py PostgreSQL queries +code/schema.sql schema: chats, users, members, chat_stats and member_stats by period, bot_status_history +code/nlp.py base forms of names, keyboard layout, reversal, escaping +scripts/ migration from SQLite +data/ event pictures and the greeting ``` -Member statistics live in a separate table per chat — that is how the bot's production databases are -built. Counters are incremented in a single query, so simultaneous messages are not lost. Speech recognition -and synthesis (Google Web Speech and gTTS) run in a separate thread, so the bot never freezes. +All-time and current-month counters grow in a single query (`INSERT … ON CONFLICT DO UPDATE`), so +simultaneous messages are not lost. Database calls are asynchronous and speech recognition and synthesis +(Google Web Speech and gTTS) run in a separate thread, so the bot never freezes. Messages use HTML markup and +user text is escaped. ## Development @@ -78,12 +103,15 @@ pip install -r requirements-dev.txt ruff check --select E9,F,B code tests && pytest ``` -What the tests cover: -- statistics counters; -- mentions and `/all`; -- the monthly reset; -- keyboard layout, reversal and escaping; -- loading of the bot's handlers. +The tests need PostgreSQL (`TEST_DATABASE_URL`). What they cover: +- counters by period; +- mentions and big-chat limits; +- splitting `/all`; +- the bot's status in groups and its history; +- migration from SQLite; +- keyboard layout and escaping. + +CI runs them on Python 3.10 and 3.12. The Docker image is built on `v*` tags and published to GitHub Packages and `dcr.deev.su`. diff --git a/README.md b/README.md index 819b65b..c94ea51 100644 --- a/README.md +++ b/README.md @@ -13,19 +13,25 @@ Telegram-бот для групповых чатов. Он: - распознаёт и озвучивает голосовые; - устраивает шуточные ивенты. -**Статус:** личный проект, работает с 2021 года · бот [@chat_abobot](https://t.me/chat_abobot) · в базе +**Статус:** личный проект, работает с 2021 года, версия 4 · бот [@chat_abobot](https://t.me/chat_abobot) · в базе бота больше 20 000 пользователей из 45 чатов (октябрь 2026) -**Стек:** Python 3.12 · aiogram 3 · pymorphy3 · pyenchant · SpeechRecognition · gTTS · SQLite · Docker +**Стек:** Python 3.10+ · aiogram 3 · PostgreSQL (asyncpg) · pymorphy3 · pyenchant · SpeechRecognition · gTTS · Docker ## Возможности - **Упоминания по имени.** Слова сообщения приводятся к начальной форме (pymorphy3) и сравниваются с именами участников, поэтому участницу Машу позовут и «Маша», и «позови Машу», и «с Машей». Своё имя для упоминаний можно задать командой `/edit`. Имена ищутся и в голосовых до минуты. -- **`/all`** — упомянуть всех участников. -- **Статистика за всё время и за месяц** (`/stat_group`, `/stat_user`): сообщения, ответы, команды, - ссылки, медиа, стикеры, голосовые и кружочки. Месячная обнуляется в начале месяца. +- **`/all`** — упомянуть всех участников. Длинный список делится на несколько сообщений. +- **Большие чаты (больше 100 участников).** + - `/all` — только для администраторов, не чаще раза в 5 минут и только для писавших за 30 дней. + - Одного человека по имени бот зовёт не чаще раза в минуту. +- **Статистика за всё время и по месяцам** (`/stat_group`, `/stat_user`): сообщения, ответы, команды, + ссылки, медиа, стикеры, голосовые и кружочки. Месяцы хранятся, поэтому `/month 2026-09` покажет итоги + любого месяца, а `/top` — самых активных за месяц или за всё время (`/top all`). +- **`/settings`** — переключатели для чата: упоминания по имени, поиск имён в голосовых (голос уходит в + Google), текстовые ивенты, удаление служебных сообщений. Менять могут администраторы. - **Неправильная раскладка.** Сообщение вида `ghbdtn` бот повторит как «привет». Английские слова он отличает по словарю (pyenchant) и не трогает. - **Голос.** `/recognize` ответом на голосовое — расшифровка; «Озвучь - текст» — голосовое из текста. @@ -36,37 +42,56 @@ Telegram-бот для групповых чатов. Он: - «Подраться с …»; - «Чмокнуть» и другие действия с картинками. - Отключаются командой `/stop_bot`. + Отключаются командой `/stop_bot` или в `/settings`. - Удаление служебных сообщений (вход, выход, смена названия и фото) — если у бота права администратора. +- **Учёт бота в группах.** Бот записывает, в каких группах состоит и с какими правами: события Telegram + плюс сверка при запуске и раз в 6 часов. История изменений хранится. Если бота исключили, статистика + группы не удаляется — меняется только отметка, что бота там больше нет. ## Запуск ```bash git clone https://github.com/EDeev/chatping_abobot.git && cd chatping_abobot cp .env.example .env # BOT_TOKEN от @BotFather -docker compose up -d +docker compose up -d # бот и PostgreSQL ``` Готовый образ: `docker pull ghcr.io/edeev/chatping_abobot` или `docker pull dcr.deev.su/edeev/chatping_abobot`. -Базы SQLite создаются при первом запуске. +Таблицы создаются при первом запуске (`code/schema.sql`). -Без Docker нужны Python 3.12, системная библиотека enchant и английский словарь -(`apt install libenchant-2-2 hunspell-en-us`). Затем: `pip install -r requirements.txt` и -`cd code && BOT_TOKEN=… python bot.py`. +Без Docker нужны: +- Python 3.10+; +- PostgreSQL; +- системная библиотека enchant с английским словарём (`apt install libenchant-2-2 hunspell-en-us`). + +Затем: `pip install -r requirements.txt` и `cd code && BOT_TOKEN=… DATABASE_URL=postgresql://… python bot.py`. + +Перенос данных старой версии (четыре базы SQLite): +`python scripts/migrate_sqlite.py --sqlite-dir путь/к/db --dsn postgresql://…`. Скрипт сверяет суммы после +переноса. + +## Развёртывание + +[@chat_abobot](https://t.me/chat_abobot) работает на домашнем сервере как systemd-служба: свой venv, настройки +в `/etc/abobot.env`, база — PostgreSQL на том же сервере. Ночной бэкап снимает дамп базы, статистика +выводится в дашборд Metabase. ## Как устроено ``` -code/bot.py запуск и ежемесячное обнуление статистики -code/handlers.py обработчики сообщений, команд, голосовых и ивентов -code/script.py учёт статистики, поиск имён, раскладка, переворот текста -code/sql.py четыре базы SQLite: группы, пользователи, статистика за всё время и за месяц -data/ картинки ивентов и приветствие +code/bot.py запуск, отправка ошибок в технический чат, сверка статуса бота в группах +code/handlers/ роутеры: help, settings, stats, mentions, voice, events, chat (бот в группах, служебные сообщения) +code/db.py запросы к PostgreSQL +code/schema.sql схема: chats, users, members, chat_stats и member_stats по периодам, bot_status_history +code/nlp.py имена в начальной форме, раскладка, переворот, экранирование +scripts/ перенос данных из SQLite +data/ картинки ивентов и приветствие ``` -Статистика участников хранится в отдельной таблице на каждый чат — так устроены рабочие базы бота. -Счётчики увеличиваются одним запросом, поэтому одновременные сообщения не теряются. Распознавание и синтез -речи (Google Web Speech и gTTS) идут в отдельном потоке, чтобы бот не замирал. +Счётчики за всё время и за текущий месяц растут одним запросом (`INSERT … ON CONFLICT DO UPDATE`), +поэтому одновременные сообщения не теряются. Запросы к базе асинхронные, а распознавание и синтез речи +(Google Web Speech и gTTS) идут в отдельном потоке — бот не замирает. Разметка сообщений — HTML, +пользовательский текст экранируется. ## Разработка @@ -75,12 +100,15 @@ pip install -r requirements-dev.txt ruff check --select E9,F,B code tests && pytest ``` -Что проверяют тесты: -- счётчики статистики; -- упоминания и `/all`; -- обнуление месячной статистики; -- раскладку, переворот и экранирование; -- что обработчики бота загружаются. +Тестам нужен PostgreSQL (`TEST_DATABASE_URL`). Что они проверяют: +- счётчики по периодам; +- упоминания и ограничения больших чатов; +- деление `/all` на сообщения; +- статус бота в группах и историю; +- перенос из SQLite; +- раскладку и экранирование. + +CI прогоняет их на Python 3.10 и 3.12. Docker-образ собирается по тегу `v*` и публикуется в GitHub Packages и `dcr.deev.su`.