AI-бот для автоматических ответов на входящие сообщения (Direct Messages) в Instagram аккаунте Astana Hub.
Бот автоматически отвечает на входящие DM в Instagram, используя контекст аккаунта (биографию и последние посты) и языковую модель Gemini. Бот отвечает только на вопросы, связанные с Astana Hub и технологической экосистемой Казахстана.
Стек:
- Flask — веб-сервер для приёма webhook-запросов от Meta
- Instagram Graph API (v25.0) — получение контекста аккаунта и отправка ответов в DM
- Google Gemini API (
gemini-2.5-flash) — генерация ответов на основе контекста - Railway — хостинг и деплой
Пользователь пишет DM в Instagram
↓
Meta отправляет POST-запрос на webhook (Railway URL)
↓
app.py — Flask получает POST /webhook
↓
Проверка на prompt injection (BLOCKED_PHRASES)
↓
Вызов get_answer(message_text) из rag.py
↓
rag.py — проверяет кэш контекста (TTL: 1 час)
├── Кэш свежий → использует сохранённый контекст
└── Кэш устарел → GET запросы к Instagram Graph API
├── /me?fields=biography,username (биография)
└── /me/media?fields=caption&limit=10 (10 постов)
↓
Формирование промпта: System Prompt + Контекст + Вопрос
↓
Gemini API генерирует ответ
↓
app.py — POST на Graph API /messages → ответ отправляется в DM
hubs_bot/
├── app.py # Основной Flask-сервер, обработка webhook
├── rag.py # Логика RAG: кэш контекста + вызов Gemini
├── update_context.py # Утилита для ручного обновления контекста (не используется в проде)
├── subscribe.py # Одноразовый скрипт подписки на Instagram webhooks
├── requirements.txt # Python-зависимости
├── Procfile # Команда запуска для Railway (gunicorn)
├── .env # Локальные переменные окружения (не коммитить!)
└── .gitignore # Исключения для git
Принимает GET-запросы для верификации webhook от Meta и POST-запросы с входящими сообщениями. Парсит sender_id и текст сообщения, проверяет на prompt injection, вызывает get_answer() и отправляет ответ через Graph API. Игнорирует собственные исходящие сообщения (защита от бесконечного цикла).
Реализует RAG-логику без векторной базы данных. При первом обращении загружает биографию и последние 10 постов аккаунта через Instagram Graph API и сохраняет в памяти (кэш). Кэш живёт 1 час, затем обновляется автоматически. Формирует промпт с системными инструкциями и контекстом, вызывает Gemini.
Python-зависимости: flask, requests, python-dotenv, gunicorn, google-generativeai.
Команда запуска production-сервера: web: gunicorn app:app -b 0.0.0.0:$PORT.
Файл с секретными переменными окружения для локального запуска. Никогда не коммитить в git.
| Переменная | Описание | Где взять |
|---|---|---|
VERIFY_TOKEN |
Произвольная строка для верификации webhook | Придумать самостоятельно/meta сам выдает |
ACCESS_TOKEN |
Instagram Page Access Token | Meta Developer Dashboard → Instagram → Generate Token |
IG_ID |
ID Instagram бизнес-аккаунта | Meta Developer Dashboard или Graph API Explorer: /me?fields=id |
GEMINI_API_KEY |
API ключ Google Gemini | aistudio.google.com → Get API Key |
- Зайди на developers.facebook.com
- Нажми My Apps → Create App
- Выбери тип Business/обычное приложение
- Заполни название и контактный email
- В левом меню нажми Add Product
- Найди Instagram и нажми Set Up
- В разделе Instagram перейди в API Setup with Instagram Login или Basic Display
- В блоке Instagram Business Account добавь свой аккаунт
- Аккаунт должен быть Professional (Business или Creator)
- Перейди в Tools → Graph API Explorer
- Выбери своё приложение и нужную Instagram Page
- Запроси разрешения:
instagram_basic,instagram_manage_messages,pages_manage_metadata - Нажми Generate Access Token и скопируй токен
- Для долгоживущего токена (60 дней): обменяй через
GET /oauth/access_token?grant_type=fb_exchange_token
- В разделе Instagram перейди во вкладку Webhooks
- Нажми Configure
- В поле Callback URL введи:
https://ВАШ_ДОМЕН_RAILWAY/webhook - В поле Verify Token введи значение из переменной
VERIFY_TOKEN - Нажми Verify and Save — сервер должен быть запущен в этот момент!
- После сохранения webhook нажми Add Subscriptions для своего аккаунта
- Поставь галочку на поле messages
- Сохрани
- Перейди в App Roles → Roles
- Нажми Add People → Testers
- Добавь Instagram-аккаунты, которые должны получать ответы от бота в dev режиме
- Приглашённые пользователи должны принять приглашение на developers.facebook.com/apps
- Загрузи код в GitHub репозиторий (убедись что
.envв.gitignore) - Зайди на railway.app → New Project → Deploy from GitHub repo
- Выбери репозиторий
- Открой проект → вкладка Variables
- Добавь все переменные из раздела 4:
VERIFY_TOKENACCESS_TOKENIG_IDGEMINI_API_KEY
- Railway автоматически перезапустит сервис
- Перейди в настройки сервиса → вкладка Networking
- Нажми Generate Domain
- Скопируй выданный домен вида
https://xxx.up.railway.app
- Вернись в Meta Developer Dashboard → Instagram → Webhooks
- Вставь домен в поле Callback URL:
https://xxx.up.railway.app/webhook - Нажми Verify and Save
- 200 DM в сутки — лимит Meta на отправку сообщений через API для большинства типов аккаунтов
- Бот не может написать первым — Instagram API позволяет отвечать только на входящие сообщения от пользователей, которые уже написали боту
- Dev режим — пока приложение не прошло модерацию Meta, бот отвечает только пользователям, добавленным как тестировщики в App Roles
- Кэш сбрасывается при перезапуске — контекст (посты и биография) хранится в памяти процесса. При каждом перезапуске контейнера на Railway кэш очищается и загружается заново при первом запросе (это штатное поведение, задержки нет)
Проблема: Flask читает тело запроса при проверке подписи HMAC, после чего request.json возвращает None, так как поток уже прочитан.
Решение: Проверка подписи закомментирована в коде. Webhook верификации через VERIFY_TOKEN достаточно для базовой безопасности.
# Временно отключили проверку подписи:
# if not verify_signature(request):
# return make_response("Unauthorized", 401)Проблема: Старые модели (gemini-2.0-flash и ниже) могут быть недоступны или иметь исчерпанные квоты. Ошибка ResourceExhausted или 404 ловится в except и бот возвращает шаблонный ответ "Извините...".
Решение: Использовать актуальную модель gemini-2.5-flash. Следить за логами Railway на строку [RAG] Error generating answer:.
Проблема: Если приложение в статусе Development, входящие сообщения от пользователей которые не являются тестировщиками приложения — не триггерят webhook.
Решение: Добавить всех нужных пользователей как тестировщиков в Meta Dashboard → App Roles → Roles → Testers. Для публичного бота — подать приложение на модерацию Meta (перевести в Live режим).
Нужно доделать хранение констекста, можно добавить дополнительные функции. Это тестовый вебхук, MVP.