KirillandClaude Fable 5.1 4534ab2683 Добавить поддержку Яндекс Маркета (goods-feedback API)
- app/services/ym.py: клиент Partner API — getGoodsFeedbacks с пагинацией и
  фильтром по дате, updateGoodsFeedbackComment (ответ), deleteGoodsFeedbackComment
  (удаление), обработка новых отзывов по аналогии с WB/Ozon
- воркер ym_worker, включается при заданных YM_API_KEY и YM_BUSINESS_ID
- кнопки отправки/удаления ответа, платформа в сообщении и в таблице,
  статистика /stat и /allstat
- переменные YM_API_KEY, YM_BUSINESS_ID, YM_CHECK_INTERVAL, PRODUCTS_YM_SHEET_LINK
- README и .env.example

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 20:13:38 +03:00

Бот для отзывов Ozon, Wildberries и Яндекс Маркета

Telegram-бот, который собирает новые отзывы с Ozon, Wildberries и Яндекс Маркета, публикует их в группу с топиками, анализирует через GPT и помогает на них отвечать: автоматически или по кнопке.

Что умеет

  • Опрос маркетплейсов. Фоновые воркеры по таймеру запрашивают новые отзывы через Ozon Seller API, WB Feedbacks API и Яндекс Маркет Partner API (goods-feedback). Каждый отзыв сохраняется в SQLite, повторно не обрабатывается.
  • Раскладка по топикам. Отзывы с оценкой выше порога (NEGATIVE_RATING, по умолчанию 3) уходят в топик хороших, остальные в топик плохих. Отзывы без текста (только оценка) можно направлять в отдельные топики.
  • Анализ через GPT. Определяет тональность, причину и критичность отзыва по промпту. Критичные отзывы помечаются #требует_обработки.
  • Ответы. Три варианта: автоответ через GPT, автоответ по шаблону для отзывов без текста, либо ручной режим с кнопками «Сгенерировать ответ» / «Написать свой ответ» / «Отправить» / «Удалить ответ».
  • Google Sheets. Каждый отзыв дописывается строкой в таблицу отзывов. Названия и категории товаров подтягиваются из справочников товаров WB, Ozon и Яндекс Маркета.
  • Статистика. Команды /stat (за сегодня) и /allstat (за всё время): количество, доля плохих, средний рейтинг, критичные, тональность.

Настройки (промпты, автоответы, модель, шаблоны) хранятся в базе отдельно для хороших и плохих отзывов и меняются прямо из бота. Они сохраняются между перезапусками и редеплоями, поэтому база должна лежать на постоянном томе.

Как это работает

Ozon API ─┐                          ┌─> Telegram (топики хороших / плохих / без текста)
WB API  ──┼─> воркер ─> SQLite ─> очереди ─┤
YM API  ──┘      │                        └─> Google Sheets (таблица отзывов)
                 └─> GPT: анализ + генерация ответа

Точка входа app/__main__.py поднимает бесконечные задачи: опрос Ozon, опрос WB, опрос Яндекс Маркета (если заданы YM_API_KEY и YM_BUSINESS_ID), отправка сообщений в Telegram, запись в Google Sheets. Затем запускает polling Telegram. Бот реагирует только на сообщения из чата TG_CHAT_ID в разрешённых топиках.

Структура кода:

Путь Назначение
app/config.py Чтение переменных окружения и .env, промпты по умолчанию, шаблоны, настройка ORM
app/handlers/reviews.py Формирование сообщения об отзыве, очереди в Telegram и Sheets
app/handlers/callbacks.py Кнопки: генерация, отправка, удаление ответа, переключатели настроек
app/handlers/commands.py Команды /stat, /allstat, /settings, шаблоны, /max_tokens
app/handlers/prompt.py Просмотр, изменение и сброс промптов
app/services/ozon.py, wb.py, ym.py Клиенты API маркетплейсов и обработка новых отзывов
app/services/gpt.py Запросы к GPT, разбор JSON анализа
app/services/sheets.py Работа с Google Sheets через gspread
app/services/stats.py Подсчёт статистики
app/models/ Модели Review и Settings (Tortoise ORM)

Требования

  • Python 3.12+
  • uv (рекомендуется) или pip
  • Telegram-бот, добавленный в супергруппу с включёнными топиками
  • Сервисный аккаунт Google с доступом к Google Sheets API
  • Ключи API Ozon Seller, Wildberries (категория «Отзывы и вопросы»), Яндекс Маркета (Api-Key с доступом «Общение с покупателями», необязательно) и gptunnel.ru

Установка и запуск

  1. Клонируйте репозиторий и установите зависимости:

    uv sync
    

    Без uv: python -m venv .venv, активировать окружение, затем pip install -e .

  2. Создайте .env из шаблона и заполните значения:

    cp .env.example .env
    

    Описание всех переменных есть внутри .env.example. Минимум для запуска: BOT_TOKEN, TG_CHAT_ID, GOOD_REVIEWS_THREAD_ID, BAD_REVIEWS_THREAD_ID.

  3. Подключите ключ сервисного аккаунта Google одним из способов:

    • положите файл в google-auth/key.json (путь можно поменять через GOOGLE_SERVICE_ACCOUNT_FILE);
    • или вставьте содержимое JSON-ключа в переменную GOOGLE_SERVICE_ACCOUNT_JSON. Переменная имеет приоритет над файлом.

    Без ключа бот запустится, но не сможет ни читать справочники товаров, ни писать отзывы в таблицу, поэтому обработка отзывов работать не будет.

    Как получить ключ: в Google Cloud Console создайте проект, включите Google Sheets API, создайте сервисный аккаунт и скачайте JSON-ключ. Затем откройте доступ на редактирование ко всем нужным таблицам для email из поля client_email этого ключа.

  4. Запустите бота:

    uv run python -m app
    

    Запускать нужно из корня проекта, потому что пути к .env и google-auth/key.json относительные.

Деплой в Coolify

Бот рассчитан на запуск из Coolify без каких-либо файлов на сервере: все настройки передаются через переменные окружения.

  1. Создайте ресурс. В проекте Coolify нажмите «New Resource», выберите репозиторий (публичный по ссылке или через GitHub App), ветку и build pack Dockerfile. Порт и домен оставьте пустыми: бот не поднимает HTTP-сервер. Если Coolify предлагает health check, отключите его.

  2. Заполните переменные окружения. На вкладке «Environment Variables» добавьте переменные из .env.example. Минимальный набор для рабочего инстанса:

    Переменная Значение
    BOT_TOKEN Токен бота от @BotFather
    TG_CHAT_ID, GOOD_REVIEWS_THREAD_ID, BAD_REVIEWS_THREAD_ID Группа и топики
    GOOGLE_SERVICE_ACCOUNT_JSON Содержимое key.json одной строкой или в base64
    REVIEWS_SHEET_LINK, PRODUCTS_WB_SHEET_LINK, PRODUCTS_OZON_SHEET_LINK, PRODUCTS_YM_SHEET_LINK Ссылки на таблицы
    OZON_API_KEY, OZON_CLIENT_ID, WB_API_KEY, YM_API_KEY, YM_BUSINESS_ID, GPTUNNEL_API_KEY Ключи API
    BRAND_NAME Название бренда для промптов

    Ключ Google удобнее передавать в base64, тогда в значении нет кавычек и переносов строк:

    base64 -w0 key.json
    

    Бот сам определит формат: если значение начинается с {, оно читается как JSON, иначе декодируется из base64.

  3. Подключите постоянное хранилище. На вкладке «Storages» добавьте volume с точкой монтирования /data. Там лежит db.sqlite3 с историей отзывов и настройками. Без тома база будет теряться при каждом редеплое, и бот заново отправит в Telegram последние отзывы с маркетплейсов.

  4. Нажмите Deploy. Образ соберётся по Dockerfile с зависимостями из uv.lock. В логах контейнера должны появиться строки Start polling и Checking for new ... reviews.

Несколько инстансов. Для каждого бренда или магазина создайте отдельный ресурс из того же репозитория со своим набором переменных и своим volume. Инстансы не зависят друг от друга. Можно указать одну и ту же ветку, тогда все они обновятся при пуше, если включён автодеплой.

Запуск в Docker вручную

docker compose up -d --build

Compose читает .env из корня, если файл есть, и хранит базу в томе bot-data. Ключ Google передаётся через GOOGLE_SERVICE_ACCOUNT_JSON либо монтированием google-auth/ (закомментировано в docker-compose.yml). Логи: docker compose logs -f bot. Остановка: docker compose down (с флагом -v удалится и база).

Настройка Telegram

  • Узнать ID чата: добавьте в группу бота @userinfobot или посмотрите в ссылке на сообщение.
  • ID топика: число в конце ссылки на топик https://t.me/c/<chat>/<topic>.
  • Все команды бота работают только внутри разрешённых топиков. Настройки применяются к тому типу отзывов, в чьём топике вызвана команда (хорошие или плохие).

Google-таблицы

Таблица отзывов (REVIEWS_SHEET_LINK). Первая строка должна содержать 12 заголовков в таком порядке:

Дата | Площадка | Название товара | Категория | Подкатегория | ID товара | Оценка | Текст отзыва | Тональность | Причина | Критичность | Тэги

Справочник товаров WB (PRODUCTS_WB_SHEET_LINK). Ключевой столбец SKU или Артикул WB. Используются столбцы Название/Наименование и Категория/Категория продавца.

Справочник товаров Ozon (PRODUCTS_OZON_SHEET_LINK). Ключевой столбец Ozon ID или ozon id акутальный. Используются Товары, Тип товара, Категория 2-го уровня.

Справочник товаров Яндекс Маркета (PRODUCTS_YM_SHEET_LINK, необязательно). Ключевой столбец SKU, Ваш SKU, offerId или Артикул — это SKU продавца (offerId в API). Используются столбцы Название/Наименование/Название товара и Категория/Категория продавца. Если таблица не задана или товар не найден, название и категория записываются как «неизвестно».

Яндекс Маркет

Используются методы Partner API getGoodsFeedbacks (список отзывов, с пагинацией и фильтром по дате), updateGoodsFeedbackComment (создание комментария к отзыву) и deleteGoodsFeedbackComment (удаление ответа по кнопке). Текст отзыва собирается из комментария, достоинств и недостатков. Фото из отзыва отправляются в Telegram вместе с сообщением. API отдаёт отзывы не старше 6 месяцев, поэтому при первом запуске бот заберёт отзывы за этот период.

Если в ссылке на таблицу есть gid=, берётся этот лист, иначе первый. Справочники кэшируются на 5 минут.

Команды бота

Команда Действие
/settings Панель настроек с переключателями: автоответ с текстом, автоответ без текста, анализ, модель GPT
/stat, /allstat Статистика за сегодня / за всё время
/show_prompt Показать текущие промпты анализа и ответа
/change_prompt, /reset_prompt Изменить / сбросить промпт анализа
/change_answer_prompt, /reset_answer_prompt Изменить / сбросить промпт ответа
/template_low текст, /template_high текст Шаблоны ответа на отзывы без текста (1–3 и 4–5 звёзд)
/show_templates Показать текущие шаблоны
/max_tokens N Лимит токенов для ответа GPT
/cancel Отменить ввод промпта или ответа

Промпты по умолчанию заданы в app/config.py, название бренда в них подставляется из BRAND_NAME. Промпт копируется в базу при первом запуске, поэтому смена BRAND_NAME на уже работающем инстансе не изменит сохранённый промпт: сбросьте его командами /reset_prompt и /reset_answer_prompt.

Данные

База SQLite (db.sqlite3) создаётся автоматически при первом запуске. Таблицы review и settings создаются через generate_schemas, недостающие колонки добавляются простой миграцией при старте.

Что не должно попадать в git

Файлы .env, google-auth/key.json и *.sqlite3 уже исключены через .gitignore. Если ключ когда-либо был закоммичен, его нужно отозвать и выпустить заново, удаления из истории недостаточно.

S
Description
No description provided
Readme
148 KiB
Languages
Python 99.3%
Dockerfile 0.7%