Telegram-бот для семейного бюджета: как перестать тревожиться и накопить на Ford Focus
Мы тут своей микросемьей ведём микросемейный микробюджет в Google Таблице. Таблица вроде как хорошая, но заполнять её с телефона неудобно: открыть, найти строку, ввести сумму, выбрать категорию. Морока знатная
Навайбкодил связку Telegram-бот+Google Таблица (на самом деле сложнее, но об этом ниже), где просто пишем боту в Telegram, как человеку: «обед 3200, такси 2450». Дальше бот сам разбирает сообщение, ставит категорию и дописывает строки в таблицу.
Ниже описываю как он устроен, на какие грабли можно наступить и как повторить такое у себя.
Все суммы и чеки в этом посте выдуманы, валюта в самой крепкой валюте мира – тенге. Имена и потребность в ведении бюджета настоящие.
Что умеет бот (не техническая часть)
Если коротко: записывает расходы и доходы, понимает даты, шлёт напоминания, строит отчёты и каждый месяц сам заводит новый файл.

Запись обычным текстом. Одно сообщение может содержать несколько трат. Бот отвечает подтверждением и кнопкой «Удалить».

Даты задним числом. «Вчера продукты 15620» или «12.09 такси 2980». Модель получает сегодняшнюю дату и сама считает дату траты. Назад можно до 45 дней.

Фото чека. Присылаю снимок, получаю список позиций с категориями.

Уведомления друг другу. Когда я что-то записываю, собюджетница видит копию, и наоборот. Это же касается удалений.

Удаление ошибок. Собюджетница написала «аптека 38600» вместо 3860. Удалить можно командой «удали последнее» или кнопкой в два нажатия: «Удалить», потом «Да, удалить». Так случайное нажатие ничего не стирает.

Напоминания. Три раза в день: в 10:00, 15:00 и 20:30. Но только тому, кто ничего не записал с прошлого напоминания. Если записал, бот молчит. В тексте спрашивает и про траты, и про поступления денег, поэтому на напоминание можно ответить «зарплата пришла 310000».

Отчёты
Под полем ввода всегда есть кнопка «📊 Отчет». Она открывает меню из пяти отчётов.

Самый любимый отчёт «План и факт». Он выглядит точно как лист «Сводка» в таблице: статья, план, факт, разница, перерасход красным. В демо-месяце мы уложились в план 700 000 ₸, потратив 671 100 ₸, но две статьи вышли за рамки: кафе и рестораны (51 000 при плане 45 000) и транспорт (44 470 при плане 40 000).

Остальные четыре отчёта: расходы по категориям, по дням, доходы и расходы, а также личные расходы и транспорт по людям.


Так выглядит лист «Сводка» в самой таблице.

Как это устроено (задротско-техническая часть)

- Google Apps Script весь бэкенд, один файл.
- Google Таблица хранилище и формулы бюджета. Берём бесплатный шаблон «Месячный бюджет» из галереи Google.
- Claude Haiku 4.5 через API превращает текст или фото чека в JSON: сумма, описание, категория, расход или доход.
- Google Charts внутри Apps Script рисует диаграммы, Google Slides API рисует картинку «План и факт».
- Cloudflare Worker на бесплатном тарифе принимает webhook от Telegram.
Отчёты строит обычный код, на них Claude не тратится вообще. Модель нужна только для разбора сообщений и чеков.
Грабли
1. Telegram не принимает webhook на Apps Script
Сначала бот опрашивал Telegram раз в минуту, и кнопки отвечали с задержкой до минуты. Казалось, что бот завис, приходилось тыкать в кнопки несколько раз. Webhook напрямую не заработал: Apps Script отвечает на POST редиректом 302, а Telegram редиректы не проходит. Решение: поставить посередине Cloudflare Worker. Он сразу отвечает Telegram «ok», а сообщение пересылает в Apps Script в фоне. Секрет webhook проверяется на стороне скрипта, а повторные доставки отсекаются по id обновления.
2. Триггер «раз в минуту» не ровно раз в минуту
Время срабатывания плавает, запуск может пропуститься. Поэтому напоминание не ждёт «ровно 15:00», а имеет окно догонки в 30 минут. Факт отправки запоминается до самой отправки, чтобы при сбое бот не слал одно и то же каждую минуту. Новый файл месяца создаётся «при первом запуске в новом месяце», а не «ровно в полночь».
3. Чьи «Личные расходы»?
В таблице у записи нет автора. По строке «Личные расходы, 6 000» не понять, кто потратил. Можно завести отдельные статьи на каждого, но список раздувается. Добавил скрытый лист «_Лог бота»: кто, когда, сколько, какая строка, какой id сообщения. Отчёт «Тимур и Кристина» считает по логу и честно предупреждает, что учитывает только записи через бота. Тот же лог позволил сделать безопасное удаление: бот стирает только свои записи и не трогает строки, которые уже правили руками. В будущем думаю это исправить как дойдут руки.
4. «Вода 300» оказалась коммуналкой
Модель увидела слово «вода» и выбрала «Коммунальные услуги». Одного списка категорий мало, нужны ещё правила на спорные случаи. В промпт добавили: коммуналка только для счетов и квитанций (свет, газ, вода по счётчику, ОСИ/КСК), а бутылка воды и напитки это «Питание».

5. «Вчера» первого числа
Запись «вчера такси», сделанная 1 октября, должна попасть в сентябрьский файл. Поэтому каждая запись маршрутизируется в файл по дате самой траты, а не по сегодняшней. Файл нового месяца бот создаёт сам: копирует прошлый (план по статьям переезжает), чистит транзакции и сообщает об этом в чат.

6. Google Slides игнорирует размер страницы
Картинку «План и факт» я хотел в портретной ориентации. Но Slides.Presentations.create размер страницы молча игнорирует, слайд всегда 16:9, и таблица обрезается. Выход: заранее сделанный пустой шаблон нужного размера. Бот копирует его, рисует таблицу, экспортирует слайд в PNG и удаляет копию. Рядом ещё мелочи: у objectId минимальная длина 5 символов, сервис Slides API нужно подключить в редакторе вручную (иначе 403), а у ячеек есть внутренние отступы, из-за которых таблица «чуть-чуть подрезана снизу». Размер шрифта пришлось подбирать под число строк.
7. Мелочи редактора Apps Script
- Кнопка «Выполнить» после перезагрузки иногда запускает первую функцию в списке, а не выбранную. Так одна тестовая функция случайно создала два лишних файла. Проверяйте, что выбрано.
- Изменения не сохранены, пока сверху не написано «Сохранено на Диске».
- После правки кода webhook работает на старой версии, пока не обновить развёртывание (Развернуть, Управление развёртываниями, новая версия, URL остаётся тем же).
Как повторить у себя (если очень хочется)
- Создайте бота у @BotFather и получите токен.
- Сделайте таблицу из шаблона «Месячный бюджет» (Google Таблицы, галерея шаблонов, «Личное») и положите в отдельную папку.
- Создайте проект Apps Script, вставьте код. Токен бота и ключ Anthropic храните только в Script Properties.
- Подключите сервис Google Slides API и сделайте презентацию-шаблон нужного размера.
- Поставьте триггер по времени раз в минуту (напоминания и новый месяц).
- Разверните скрипт как веб-приложение, создайте Cloudflare Worker и один раз запустите настройку webhook.
Для тех, кто дочитал до конца — промпт для Claude, который сделает все за вас
Ниже один промпт, в который уже зашиты все грабли из этого поста. Вставьте его целиком и поправьте то, что в квадратных скобках.
Промпт: собрать такого бота с нуля одним сообщением
Сделай Telegram-бота для семейного бюджета на Google Apps Script. Код одним файлом .gs, комментарии на русском. Пользуются двое: [Имя 1] и [Имя 2], валюта [тенге], часовой пояс [Asia/Almaty]. **Хранилище.** Google Таблица из стандартного шаблона «Месячный бюджет» (листы «Транзакции» и «Сводка»). На «Транзакциях» два блока с заголовками «Дата, Сумма, Описание, Категория»: слева расходы, справа доходы. Строку заголовков ищи по двум ячейкам «Дата», не по номерам колонок. Все названия листов и заголовков вынеси в константы в начале файла. Каждый месяц отдельный файл «Месячный бюджет. <Месяц> <Год>» в папке [ID папки]. **Разбор сообщений.** Текст и фото чека отправляй в Claude API (модель claude-haiku-4-5), получай JSON-массив записей: дата, сумма, описание, категория, тип (расход или доход). В одном сообщении может быть несколько трат. Передавай модели сегодняшнюю дату, день недели и имя автора, чтобы она понимала «вчера», «в пятницу», «12.09» (не дальше 45 дней назад). Категории расходов: [список]. Категории доходов: [список]. Добавь правило: «Коммунальные услуги» только для счетов и квитанций (свет, газ, вода по счётчику, мусор, ОСИ/КСК); покупка питьевой воды и напитков это «Питание». **Запись.** Каждую запись клади в файл месяца по дате траты, а не по сегодняшней дате. Параллельно веди скрытый лист «_Лог бота»: когда внесено, кто, тип, дата, сумма, описание, категория, номер строки в «Транзакциях», id сообщения, статус. Используй LockService, чтобы две записи не легли в одну строку. **Ответы.** Подтверждение «Записал: обед, 3200 тенге, Кафе» с inline-кнопкой «❌ Удалить». Копия каждой записи и удаления уходит второму человеку («[Имя 1] записал(а): …»). Постоянная клавиатура с одной кнопкой «📊 Отчет». Команды /start (краткая справка) и /report. Сообщение из незнакомого чата: ответить его chat id, больше ничего не делать. **Удаление.** «❌ Удалить» → «Да, удалить / Отмена» → строки этой записи очищаются, в сообщение дописывается «❌ Удалено из таблицы». Команда «удали последнее» удаляет последнюю запись автора без подтверждения. Удалять можно только свои записи. Если строку в таблице уже меняли руками, не трогай её, а напиши, что проверить. **Новый месяц.** При первом запуске в новом месяце скопируй файл прошлого месяца (план по статьям сохраняется), очисти транзакции и лог, напиши [Имя 1] в Telegram, что файл создан. **Напоминания** в 10:00, 15:00 и 20:30 только тем, кто ничего не записал с прошлого напоминания. В тексте упомяни и траты, и доходы. Триггер Apps Script неточный: окно догонки 30 минут, факт отправки запоминай до отправки. **Отчёты** за текущий месяц по кнопке, меню из пяти inline-кнопок: 1. По категориям (столбчатая диаграмма Charts + итог текстом). 2. По дням (сумма, среднее в день, самый затратный день). 3. [Имя 1] и [Имя 2]: кто сколько потратил на статьи [Личные расходы, Транспорт], автор берётся из лога, stacked-диаграмма. 4. Доходы и расходы, остаток. 5. План и факт: картинка, которая выглядит как таблица «Расходы» на листе «Сводка» (статья, предполагаемые, фактические, разница, перерасход красным), без длинного текста. Рисуй через Google Slides API: копируй заранее созданную портретную презентацию-шаблон [ID] (Slides.Presentations.create размер страницы игнорирует), objectId делай длиной от 5 символов, размер шрифта подбирай под число строк с учётом отступов ячеек, экспортируй слайд в PNG, временную копию удаляй. **Скорость.** Telegram webhook, но не напрямую на Apps Script (он отвечает 302, Telegram не принимает): дай код Cloudflare Worker, который сразу отвечает «ok», а тело пересылает в веб-приложение через ctx.waitUntil с redirect: 'follow', передавая секрет webhook как ?tg=. В Apps Script проверяй секрет и отбрасывай повторные update_id через CacheService. Функции setupWebhook и disableWebhook (откат на опрос раз в минуту). **Секреты** (токен бота, ключ Anthropic, секрет webhook) только в Script Properties. В конце дай пошаговую инструкцию по настройке: BotFather, таблица, Script Properties, сервис Slides, триггер раз в минуту, развёртывание веб-приложения, Worker, setupWebhook, setBotCommands.
Шаблон «Месячный бюджет» доступен в галерее шаблонов Google Таблиц или скопировать себе тут.
Если будете повторять и что-то пойдёт не так, пишите своему Claude или в комментариях, попробую ответить. Всем богатства.


