Telegram-бот для инкрементального сбора, постоянного хранения и анализа активности на GitHub. Бот собирает историю изменений, сохраняет ее в СУБД SQLite, мгновенно генерирует компактные отчеты (JSON) для передачи в контекстное окно LLM и поддерживает обновление данных в реальном времени через вебхуки GitHub.
Вместо летучего кэширования запросов бот использует постоянные таблицы tracked_repos (отслеживаемые репозитории) и
commits (атомарные записи коммитов с деталями измененных файлов):
- Холодный запуск (Backfill): При первой проверке или принудительном сбросе (
needs_full_resync) бот скачивает полную историю за период глубинойmax_backfill_days(по умолчанию 2 года). - Инкрементальный добор (Delta-sync): Последующие проверки запрашивают у GitHub GraphQL API только изменения с
момента последнего известного коммита (
last_synced_sha/last_synced_at), минимизируя накладные расходы на сетевые запросы и лимиты токенов API.
Если данные по запрашиваемому пользователем профилю (или конкретному репозиторию) обновлялись недавно (в пределах
настроенного fast_path_max_age, например, последние 120 секунд), бот мгновенно извлекает и компилирует отчет прямо из
локальной СУБД SQLite, минуя очередь фоновых задач Arq.
Сразу после отправки отчета бот асинхронно запускает тихую фоновую досинхронизацию (silent_background_sync), чтобы
обновить данные к следующему запросу без отправки дублирующих уведомлений в чат.
Бот может выступать в роли приемника вебхуков GitHub:
- Тонкий вебхук-сервис (aiohttp): Принимает push-события от GitHub, проверяет подпись
X-Hub-Signature-256и мгновенно регистрирует задачу в очереди воркеров, отвечая серверу GitHub менее чем за 50 мс. - Асинхронная обработка коммитов: Воркер Arq разбирает пуш, фильтрует коммиты по отслеживаемому автору, добирает детали измененных файлов через REST API и сохраняет их в базу данных.
- Safety-Net Реконсиляция (Cron-задача): Раз в 6 часов воркер выполняет фоновую сверку метаданных репозиториев,
работающих в режиме вебхуков. Если push-событие было утеряно из-за сетевого сбоя или даунтайма, кросс-проверка
обнаружит расхождение по дате
pushed_atи автоматически дозагрузит пропущенные коммиты.
- Команда
/repos: Показывает список всех отслеживаемых репозиториев пользователя с инлайн-кнопками включения/отключения отслеживания (is_active). Списки клавиатур автоматически разбиваются на страницы ( пагинируются), предотвращая падение по лимитам размера сообщений Telegram. - Интерактивный запуск: При нажатии кнопки «📊 Мой анализ» бот выводит меню выбора репозиториев. Пользователь может точечно проанализировать один конкретный репозиторий или весь профиль целиком («📁 Все репозитории»).
- Язык:
Python 3.11 - Telegram Bot:
python-telegram-bot(v20, асинхронный режим) - Фоновые задачи & Очередь:
arq+Redis - База данных:
SQLite+SQLAlchemy Core+aiosqlite(WAL-режим для конкурентного чтения/записи) - Транспорт GitHub API:
httpx(поддержка HTTP/2, раздельные лимиты REST/GraphQL, pre-flight оценка стоимости запросов) - Вебхук-сервер:
aiohttp
| Команда | Описание |
|---|---|
/start |
Приветственное сообщение, вывод главного Reply-меню. |
/analyze @username |
Запуск анализа (или вывод меню выбора репозиториев) профиля. |
/repos |
Интерактивный список отслеживаемых репозиториев с инлайн-кнопками. |
/status <job_id> |
Проверка статуса выполнения фонового анализа по его идентификатору. |
Скопируйте пример файла конфигурации и заполните переменные:
cp .env.example .envДля запуска бота, воркера Arq и Redis в стандартном режиме (опрос по расписанию):
docker compose up -dДля запуска с поддержкой приема вебхуков GitHub (поднимает дополнительный сервис webhook на порту 8080):
docker compose --profile webhook up -dpip install -r requirements.txt
# 1. Запустить Redis
# 2. Запустить воркер фоновых задач:
arq src.worker.settings.WorkerSettings
# 3. Запустить бота:
python -m src.bot.main
# 4. (Опционально) Запустить вебхук-приемник:
python -m src.webhook.server| Переменная | Обязательна | Описание |
|---|---|---|
GITHUB_TOKEN |
✅ | Основной токен GitHub (с правами public_repo или repo). |
GITHUB_EXTRA_TOKENS |
— | Дополнительные токены через запятую для ротации пула токенов. |
TELEGRAM_BOT_TOKEN |
✅ | Токен бота от @BotFather. |
REDIS_URL |
✅ | URL для подключения к Redis (например, redis://localhost:6379/0). |
DATABASE_URL |
— | Путь к SQLite: sqlite+aiosqlite:///data/app.db?timeout=20.0. |
MAX_WORKERS |
— | Максимальное число параллельных потоков сбора репозиториев (по умолчанию: 10). |
MAX_REQUESTS_PER_USER |
— | Суточный лимит запросов на одного пользователя Telegram (по умолчанию: 10). |
USER_COOLDOWN_MINUTES |
— | Кулдаун между запросами к одному профилю (по умолчанию: 30 мин). |
MAX_BACKFILL_DAYS |
— | Глубина первоначального сбора истории коммитов в днях (по умолчанию: 730). |
FAST_PATH_MAX_AGE |
— | Время жизни кэша отчета в секундах для срабатывания Fast-path (по умолчанию: 120). |
WEBHOOK_ENABLED |
— | Активация приема push-событий вебхуков (true/false). |
WEBHOOK_SECRET |
— | Секретный ключ вебхука для проверки подписи (обязателен, если вебхуки включены). |
WEBHOOK_PUBLIC_URL |
— | Публичный URL для GitHub (например, https://yourdomain.com/webhook/github). |
OWNER_GITHUB_USERNAME |
— | GitHub-логин владельца бота для автоматической регистрации вебхуков CLI-скриптом. |
Для передачи истории изменений в контекстное окно LLM бот преобразует собранные данные в ультракомпактный формат
CompactResult, экономящий до 60% токенов:
{
"user": "torvalds",
"from": "2024-01-01",
"ext": [
".c",
".h"
],
"repos": {
"torvalds/linux": [
{
"d": 74,
"m": "tcp: fix memory leak in error path",
"f": [
[
"net/ipv4/tcp",
0,
12,
3
],
[
"include/net/tcp",
1,
2
]
]
}
]
}
}from— базовая дата отсчета периода.ext— упорядоченный по частоте список уникальных расширений файлов (индекс).d— смещение в днях от базовой даты (from+dдней), исключающее передачу длинных строк дат.m— тема (subject) коммита, усеченная до 72 символов.f— измененные файлы в формате массива:[путь_без_расширения, индекс_расширения_в_ext, добавлено_строк?, удалено_строк?]. Нули в конце опускаются.
src/
├── config.py # Конфигурация pydantic-settings
├── logger.py # Настройки логов через loguru
├── models/
│ └── models.py # Модели Pydantic (AnalysisResult, CompactResult) и сжатие
├── core/
│ ├── sync.py # Инкрементальная синхронизация коммитов с GitHub в БД
│ ├── report.py # Сборка отчетов AnalysisResult из локальной СУБД, Fast-path
│ ├── exceptions.py # Исключения сборщика (CollectorError, RateLimitError)
│ └── validator.py # Валидация юзернеймов GitHub
├── github/
│ ├── client.py # HTTP-клиент (httpx + HTTP/2), единый транспорт
│ ├── auth.py # TokenPool (раздельные бюджеты токенов REST/GraphQL)
│ ├── ratelimit.py # Стратегии RateLimiter (оценка стоимости, задержки)
│ ├── models.py # Модели данных GitHub (Repository, CommitHeader)
│ ├── queries.py # Описание GraphQL-запросов и пакетных алиасов
│ ├── paginator.py # Асинхронная постраничная навигация по курсорам
│ ├── graphql.py # GraphQL-интеграция
│ ├── rest.py # REST-добор файлов коммита
│ ├── filters.py # Логика фильтрации (needs_rest_details)
│ └── service.py # Публичный фасад GitHubService для проекта
├── storage/
│ ├── database.py # API работы со SQLite (aiosqlite + SQLAlchemy)
│ ├── redis.py # Инициализация клиента Redis
│ ├── cache.py # Быстрый кэш Redis (блокировки, суточные лимиты, кулдауны)
│ └── pubsub.py # Реализация очередей Pub/Sub для бота
├── bot/
│ ├── app.py # Фабрика приложения и логика отправки уведомлений
│ ├── main.py # Инициализация бота, регистрация хендлеров
│ ├── keyboards.py # reply-клавиатуры главного меню и утилиты пагинации инлайн-кнопок
│ └── handlers/
│ ├── analyze.py # Логика Fast-path, старт фоновых задач, инлайн-выбор репозиториев
│ ├── menu.py # Обработка текстового Reply-меню бота
│ ├── status.py # Просмотр статуса фоновых задач по их ID
│ └── repos.py # Обработка команды /repos и инлайн-кнопок управления репозиториями
└── worker/
├── tasks.py # Задачи фонового воркера (анализ, вебхуки, реконсиляция)
└── settings.py # Настройки воркера Arq, инициализация БД, cron-расписание