image_recognition/README.md

8.3 KiB
Raw Blame History

Qwen Telegram Bot

Telegram-бот на Python с четырьмя функциями:

  • 📷 описание изображений — присылаешь фото, бот возвращает текстовое описание через vision-модель Qwen
  • 📊 генерация графиков — по текстовому запросу бот просит LLM написать код на matplotlib, выполняет его и отправляет PNG
  • 🏛 архитектурные схемы — по описанию системы LLM генерирует DOT, Graphviz рендерит это в PNG
  • ♻️ воспроизведение с фото — кидаешь фото графика или архитектурной схемы, бот распознаёт тип, извлекает структуру и отрисовывает заново в своём стиле

Стек

  • python-telegram-bot — асинхронный клиент Telegram Bot API
  • openai SDK — работа с любым OpenAI-совместимым провайдером (OpenRouter, DashScope, vLLM и др.)
  • matplotlib + numpy — рендеринг графиков
  • Graphviz + python-graphviz — рендеринг архитектурных схем из DOT
  • uv — менеджер пакетов и виртуальных окружений

Требования

  • Python 3.11+
  • установленный uv (инструкция)
  • бинарь Graphviz в $PATH (нужен для команды /arch):
  • токен Telegram-бота от @BotFather
  • API-ключ провайдера, поддерживающего мультимодальную модель Qwen

Установка

git clone <https://git.lambda.coredump.ru/BtoB_team/image_recognition.git>
cd image_recognition

# создаёт .venv и ставит зависимости из pyproject.toml + uv.lock
uv sync

Конфигурация

Скопируй шаблон и впиши свои ключи:

cp .env.example .env

⚠️ Для функции описания изображений модель должна быть мультимодальной (VL). Текстовая модель упадёт при попытке передать ей картинку.

Запуск

uv run bot.py

Бот запускается в режиме long-polling и пишет лог в stdout.

Использование

Действие Что делает бот
/start или /help Показать справку
Отправить фото (без подписи-команды) Вернуть описание изображения
/plot <описание> Сгенерировать и прислать matplotlib-график
/arch <описание> Нарисовать архитектурную схему через Graphviz
/repro + фото Распознать график/схему и отрисовать её заново

Примеры запросов к /plot:

/plot sin(x) и cos(x) на отрезке [0, 2π]
/plot затухающая синусоида на [0, 10]
/plot столбчатая диаграмма продаж по месяцам с рандомными значениями
/plot гистограмма нормального распределения, 1000 сэмплов

Примеры запросов к /arch:

/arch React-фронт, FastAPI-бэкенд, Postgres и Redis за nginx
/arch микросервисы: auth, orders, payments. Общаются через RabbitMQ, у каждого своя БД Postgres, Prometheus собирает метрики
/arch телеграм-бот, принимает вебхуки, складывает задачи в очередь Celery с Redis-брокером, воркеры пишут результаты в S3

Как пользоваться /repro

Два варианта:

  1. Прикрепить фото с подписью /repro — бот сразу обработает его.
  2. Ответить /repro на сообщение с фото (reply-to-message).

Бот классифицирует изображение как график (plot) либо архитектурную схему (architecture), извлекает структуру через vision-модель, генерирует для неё matplotlib-код или DOT и отрисовывает заново. Это не попиксельная копия — это реконструкция: бот старается передать тот же тип графика/те же компоненты и связи, но стиль будет его собственный.

Структура проекта

.
├── bot.py            # основной скрипт: конфиг, LLM-клиент, хэндлеры Telegram
├── pyproject.toml    # зависимости и метаданные проекта для uv
├── uv.lock           # фиксация версий (создаётся после uv sync)
├── .env.example      # шаблон переменных окружения
└── .env              # реальные ключи (в git не коммитить!)

Работа с зависимостями

uv add <пакет>         # добавить зависимость
uv remove <пакет>      # убрать зависимость
uv sync                # синхронизировать .venv с lock-файлом
uv run <команда>       # выполнить команду в окружении проекта

⚠️ Безопасность

Код для построения графиков генерируется LLM и исполняется через exec в урезанном неймспейсе (без import, без open, с ограниченным набором builtins). Этого достаточно для локального использования и dev-стенда, но это не песочница.

Архитектурные схемы безопаснее: Graphviz парсит DOT как данные, а не исполняет его как код, поэтому инъекция через промпт там в худшем случае даст кривую или огромную картинку.

Для публичного бота стоит изолировать исполнение /plot, например:

  • отдельный воркер-процесс с resource.setrlimit (CPU, память, время)
  • Docker-контейнер без сети и с read-only FS
  • nsjail / firejail
  • вместо exec — разобрать запрос в ограниченный DSL, а уже его превратить в matplotlib-вызовы детерминированным кодом

Возможные улучшения

  • webhook вместо polling для продакшена
  • очередь задач (arq / Celery) для тяжёлого рендеринга
  • кэш описаний по хэшу изображения
  • вывод сгенерированного кода графика в подписи к картинке (дебаг-режим)
  • rate-limiting на пользователя
  • тесты для render_plot с фиксированными промптами