8.7 KiB
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):- Linux:
sudo apt install graphviz - macOS:
brew install graphviz - Windows: скачать с graphviz.org
- Linux:
- 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с фиксированными промптами