image_recognition/README.md
2026-05-26 23:43:07 +03:00

8.7 KiB
Raw Blame History

Qwen Console App

Консольное приложение на Python с четырьмя функциями:

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

Стек

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

Требования

  • Python 3.11+
  • установленный uv (инструкция)
  • бинарь Graphviz в $PATH (нужен для команды arch):
  • 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

Переменные окружения:

Переменная Обязательна По умолчанию Описание
LLM_API_KEY API-ключ провайдера
LLM_BASE_URL https://llm.lambda.coredump.ru/v1 Base URL OpenAI-совместимого API
LLM_MODEL qwen3.5-122b Имя модели
LLM_DISABLE_THINKING false Отключить reasoning (для Qwen3/DeepSeek-R1)

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

Запуск

uv run src/app.py

Приложение запускается в интерактивном режиме и ждёт команд.

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

>>> <команда> <аргумент>
Команда Что делает
describe <путь> Описать изображение
plot <описание> Сгенерировать matplotlib-график → сохраняется в plot.png
arch <описание> Нарисовать архитектурную схему → сохраняется в arch.png
repro <путь> Воспроизвести график/схему с картинки → сохраняется в repro.png
help Показать справку
exit / quit / Ctrl+C Выйти из приложения

Примеры для 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:

>>> repro chart.png
>>> repro /home/user/screenshots/arch_diagram.jpg

Результат repro — это не попиксельная копия, а реконструкция: приложение старается передать тот же тип графика / те же компоненты и связи, но стиль будет его собственный.

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

.
├── app.py            # основной скрипт: конфиг, LLM-клиент, консольный цикл
├── 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-вызовы детерминированным кодом

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

  • история команд (readline / prompt_toolkit)
  • автодополнение путей к файлам по Tab
  • флаг --open для автоматического открытия PNG после генерации
  • кэш описаний по хэшу изображения
  • вывод сгенерированного кода графика в режиме отладки (--debug)
  • тесты для render_plot с фиксированными промптами