# Qwen Console App Консольное приложение на Python с четырьмя функциями: - 📷 **описание изображений** — указываешь путь к файлу, приложение возвращает текстовое описание через vision-модель Qwen - 📊 **генерация графиков** — по текстовому запросу LLM пишет код на matplotlib, приложение выполняет его и сохраняет PNG - 🏛 **архитектурные схемы** — по описанию системы LLM генерирует DOT, Graphviz рендерит это в PNG - ♻️ **воспроизведение с фото** — указываешь путь к фото графика или схемы, приложение распознаёт тип и отрисовывает заново ## Стек - [openai](https://github.com/openai/openai-python) SDK — работа с любым OpenAI-совместимым провайдером (OpenRouter, DashScope, vLLM и др.) - [matplotlib](https://matplotlib.org/) + numpy — рендеринг графиков - [Graphviz](https://graphviz.org/) + [python-graphviz](https://github.com/xflr6/graphviz) — рендеринг архитектурных схем из DOT - [uv](https://docs.astral.sh/uv/) — менеджер пакетов и виртуальных окружений ## Требования - Python **3.11+** - установленный `uv` ([инструкция](https://docs.astral.sh/uv/getting-started/installation/)) - **бинарь Graphviz** в `$PATH` (нужен для команды `arch`): - Linux: `sudo apt install graphviz` - macOS: `brew install graphviz` - Windows: [скачать с graphviz.org](https://graphviz.org/download/) - API-ключ провайдера, поддерживающего мультимодальную модель Qwen ## Установка ```bash git clone cd image_recognition # создаёт .venv и ставит зависимости из pyproject.toml + uv.lock uv sync ``` ## Конфигурация Скопируй шаблон и впиши свои ключи: ```bash 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)**. Текстовая модель упадёт при попытке передать ей картинку. ## Запуск ```bash 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 не коммитить!) ``` ## Работа с зависимостями ```bash 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](https://github.com/google/nsjail) / [firejail](https://firejail.wordpress.com/) - вместо `exec` — разобрать запрос в ограниченный DSL, а уже его превратить в matplotlib-вызовы детерминированным кодом ## Возможные улучшения - история команд (readline / prompt_toolkit) - автодополнение путей к файлам по Tab - флаг `--open` для автоматического открытия PNG после генерации - кэш описаний по хэшу изображения - вывод сгенерированного кода графика в режиме отладки (`--debug`) - тесты для `render_plot` с фиксированными промптами