💰

Финансовый ассистент: учёт денег из PDF-выписок в Telegram

собственный продукт: бот и веб-дашборд, выписки четырёх банков, Gemini

Telegram-бот и веб-дашборд для учёта личных финансов: разбирает PDF-выписки ВТБ, Сбербанка, Т-Банка и Озон Банка, принимает траты фразой, отделяет бизнес от личного. Python, aiogram 3, PostgreSQL, Gemini.

В продакшене · собственный продукт
4 банка
ВТБ, Сбербанк, Т-Банк и Озон Банк: банк определяется по самому PDF
~120 тестов
функций pytest: разбор текста, сверка выписок, долги, наличные, выгрузка; база и сеть не нужны
1 фраза
в чат: и трата, и долг, и постоянный платёж записаны и разложены по категориям

Задача

Деньги ходят через несколько банков, карты близких и наличные. Приложение каждого банка показывает только свой кусок. Переводы между своими счетами выглядят как доходы и расходы, а ручной учёт в таблице обычно заканчивается через пару недель. К тому же часть трат относится к работе и собственным проектам, а часть к личной жизни, и в банковском приложении они перемешаны.

Нужна была единая и честная картина денег: сколько пришло, куда ушло, что из этого дело, а что личное. Причём без ручного переноса каждой операции: выписку банка нужно просто бросить в чат, а мелкую трату сказать обычной фразой.

Решение

Финансовый ассистент — собственный Telegram-бот с веб-дашбордом поверх тех же данных. Реализовано в версии 1.14.0:

  • Выписки четырёх банков. PDF ВТБ (кредитная карта, счёт кредитки, дебетовые карты), Сбербанка, Т-Банка и Озон Банка. Банк определяется автоматически, запасной вариант — универсальный разбор CSV и XLSX.
  • Реестр счетов и карт. Номер счёта, договор, последние четыре цифры карт, владелец. Следующая выписка сама попадает на нужный счёт; для кредитки ВТБ видны долг, лимит, ставка и дата платежа.
  • Траты словами. «Вчера кофе 250», «+65000 зарплата нал», «постоянные расходы 2500 подписка». В одном сообщении может быть несколько операций, а одна покупка раскладывается на несколько категорий.
  • Голосовые и фото чека. Речь расшифровывает Gemini; из чека получаются позиции с категориями, которые привязываются к операции по карте.
  • Счёт словами. «По кредитке», «со сбера», «с карты 5515»: запись ложится на нужный счёт, а неоднозначное бот не угадывает и спрашивает.
  • Ночной разбор. Неизвестные продавцы уходят в модель одним запросом, утром категории расставлены, спорное приходит списком кнопок.
  • Вопросы о своих деньгах. «На что больше всего уходит?», «сравни с прошлым месяцем»: ответ собирается по данным бота, а инвестиционных советов бот не даёт.
  • Долги, постоянные платежи и бюджеты. Книга долгов по людям, платежи с днём списания, бюджеты по категориям с предупреждением на 80 % и 100 %.
  • Направления и реинвестиции. Доход, расход и динамика за 12 месяцев по каждому направлению.
  • Дашборд как Telegram Mini App. Вкладки «Бизнес», «Покупки», «Долги», календарь трат, сравнение с прошлым периодом, выгрузка в CSV и XLSX.
  • Доступ для двух человек. Владелец и близкий человек со своими счетами и своей сводкой.

Как это устроено

Определение банка, счёта и карты по PDF

Для каждого банка есть свой парсер (программа, читающая структуру файла), а отдельный модуль по шапке выписки определяет банк, владельца, счёт, карты, период и остаток. Если формат банка неизвестен, включается запасной разбор CSV и XLSX. Парсеры рассчитаны на текущую вёрстку PDF: когда банк её меняет, суммы перестают сходиться с итогами выписки, и парсер приходится поправить. В выписке по дебетовой карте ВТБ нет номера счёта, поэтому карты одного счёта объединяются по одинаковому остатку на дату выписки, а если этого мало, помогает кнопка «Это тот же счёт».

Сверка перекрывающихся выписок без дублей

Банк часто отдаёт выписку с запасом по датам, и один и тот же день попадает в два файла. Бот сравнивает загружаемые операции с уже сохранёнными и повторно их не записывает; расхождения в зоне перекрытия перечисляются в ответе. Повторная загрузка того же файла ничего не меняет.

Переводы между своими счетами не считаются доходом

Перевод с карты на карту выглядит как расход в одном месте и доход в другом. Бот определяет такие переводы по формулировкам банков, по своему имени владельца и по парам «ушло — пришло» на одну сумму, и в доходы и расходы они не попадают. Любой счёт можно исключить из общих итогов одной кнопкой.

Слияние ручной записи с операцией из выписки

Трату, которую вы записали в чат, бот не задваивает с той же операцией, когда придёт выписка. Сумма может слегка отличаться: допуск 2 % или 100 рублей, плюс небольшое окно по дате. Название места из сообщения ищется в описании банка с учётом транслитерации («перекрёсток» и PEREKRESTOK считаются одним местом). Если подходящих операций несколько, бот предлагает выбор кнопками, а слияние можно отменить. Слабое место: две разные траты на одну сумму в один день могут слиться, тогда их разъединяют кнопкой.

Снятие наличных: перевод, а не трата

Раньше сказать боту о снятии было нечем: из выписки он узнавал банкомат, а из сообщения нет, и снятие либо пропадало, либо становилось тратой. Теперь снятие записывается как переезд денег с карты в карман, а траты из того же сообщения остаются отдельными записями. Записанное словами снятие сливается с банкоматной операцией, когда приходит выписка, поэтому карман не считается дважды. Одно и то же снятие за день не записывается повторно; настоящее второе снятие той же суммы записывается по слову «ещё».

Ночной разбор и правила по продавцам

Категория определяется в таком порядке: выученные правила по продавцу, затем ключевые слова (побеждает самое длинное совпадение), затем категория, которую дал банк. Что осталось неизвестным, ночью уходит в модель одним запросом. Понятное раскладывается по категориям и запоминается правилом, а утром приходит список кнопками: сверху непонятное, ниже разобранное для правки.

Одни расчёты для бота и дашборда

Вся аналитика собрана в одном слое (общая для бота и дашборда), поэтому цифры в меню Telegram и на графиках совпадают. Дашборд — веб-страница без сборки на HTML и Chart.js, которая открывается как Telegram Mini App. Вход по подписи Telegram или по личной ссылке из бота: она действует час, после чего браузеру выдаётся cookie на 30 дней.

Резервные копии и мониторинг живости

Ежедневный дамп базы проверяется на целостность и ротируется, а восстановление можно проверить на отдельной базе, не трогая боевую. Каждые 5 минут внешняя проверка смотрит контейнеры, базу, отметку «бот жив» (бот ставит её раз в минуту) и адрес дашборда. При отказе в Telegram приходит сообщение. Ошибка в хендлере не остаётся молчанием: человек видит ответ, а владелец получает сведения о том, что упало и на каком сообщении.

Результат

  • Меню в одном сообщении: месяц одним взглядом (доходы, расходы, итог, сегодня, постоянные платежи до конца месяца, долги).
  • Направления и «кто съедает больше»: направления и личное в одном ряду по убыванию расхода, с долей и сдвигом к прошлому месяцу.
  • Дашборд: расходы по дням, календарь трат, «что изменилось», покупки по позициям чеков, выгрузка операций в CSV и XLSX.
  • Подсказки: рост расходов, превышение бюджетов, устаревшие выписки, скорый платёж по кредитке.
  • Напоминание о платеже по кредитке за 3 дня, недельный дайджест по понедельникам, сверка наличных.
  • Автоматические тесты (около 120 функций pytest) проверяют разбор текста, сверку выписок, долги, определение банка, выгрузку и работу с наличными.

Технологии: что и зачем

  • Python 3.13 и aiogram 3 — Telegram-бот: меню, сообщения, файлы, планировщик напоминаний.
  • FastAPI и uvicorn — API дашборда; сам фронтенд без сборки, на HTML, CSS, JS и Chart.js.
  • PostgreSQL 17 и SQLAlchemy 2.0 (асинхронно) — хранение операций, счетов, правил, долгов и бюджетов.
  • pdfplumber, pandas, openpyxl, chardet — разбор PDF-выписок, запасной CSV и XLSX, выгрузка.
  • Google Gemini — сложный текст, голосовые, фото чеков, ночной разбор и вопросы о деньгах; ключи и списки моделей с очерёдностью заданы в .env.
  • Docker Compose — три контейнера: база, бот и веб-часть; таблицы создаются при старте.

Статус

Собственный продукт, в продакшене. Текущая версия 1.14.0 от 22 сентября 2026 года: снятие и внесение наличных из сообщения. До неё в тот же день вышли раскидка трат по направлениям, вопросы о своих деньгах, календарь трат и учёт счёта словами.

Ограничения: миграций нет, откат версий делается из копии базы; мультивалютности нет; сложный текст и фото чека уходят в Google. Переводы между своим счётом и счётом близкого в режиме «Все» считаются доходом у одного и расходом у другого.

Вопросы по проекту

Как свести выписки нескольких банков в одну картину и не получить дубли?
Пришлите PDF-выписку ВТБ, Сбербанка, Т-Банка или Озон Банка. Бот сам определяет банк, счёт и карту, сверяет перекрывающиеся периоды и не записывает уже загруженные операции повторно, а расхождения в перекрытии перечисляет в ответе. Для остальных банков есть запасной разбор CSV и XLSX.
Как отделить бизнес от личных трат в учёте?
У операций есть направления: работа, собственные проекты, личное. Направление берётся из категории или ставится у операции, а кнопка «Раскидать» ставит его сразу всей группе трат по одному месту, в прошлом и будущем. Во вкладке «Бизнес» видны доход, расход и реинвестиции за 12 месяцев и сводка «кто съедает больше».
Как вести учёт долгов по людям?
Долг записывается фразой: «должен диме 14к», «вернул диме 5к». Для каждого человека ведётся книга движений с остатком, разные падежи имени сводятся к одному человеку. Деньги по долгу из выписки не считаются ни доходом, ни расходом.
Как считать наличные, если банк их не видит?
Снятие и внесение записываются словами: «снял наликом 6500», «внёс 5000 на карту». Это перевод между картой и карманом, а не трата, поэтому в расходы месяца не идёт. После сообщения бот пишет, сколько по его подсчёту осталось в кармане, а по понедельникам просит сверить наличные.
Где хранятся данные и что уходит в Google?
Данные лежат в базе PostgreSQL в Docker на том сервере, где запущен бот. Бот и дашборд открываются только Telegram-ID из списка разрешённых, для остальных бот отказывает, а API дашборда отвечает 401. В Google Gemini уходят фото чека и текст сообщения, когда нужен сложный разбор; без ключей работают только встроенные правила.
Может ли пользоваться второй человек?
Да. Второй человек пишет свои траты, они идут на его счета, и видит свою сводку, операции, счета, выгрузку и общую сводку «на двоих». Разделы владельца (бизнес, долги, бюджеты, категории, дашборд, ночной разбор, админ-команды) ему закрыты.

Нужно похожее?

Расскажите о задаче — покажем, как решали такое, и прикинем объём работ.