Skip to content

ivanmem/vk-caption-ai

Repository files navigation

VK Caption AI

Настольное приложение на Tauri 2 + Vue 3 + Naive UI, которое решает две смежные задачи поверх локальной vision-модели в LMStudio:

  1. Подпись к фотографиям альбома ВКонтакте — модель смотрит на каждое фото и предлагает текстовое описание, которое затем сохраняется в поле подписи через VK API. Доступны автоматический и ручной режимы.
  2. Локальный «распределитель» фото — модель раскладывает кучу файлов из указанной папки по подкаталогам (например, «Документы», «Скриншоты», «Природа», «_unsorted»), руководствуясь набором правил, который формирует пользователь.

Вся тяжёлая работа (HTTP к LMStudio и VK, чтение/перемещение файлов, декодирование изображений и генерация миниатюр) выполняется на стороне Rust через Tauri-команды, поэтому интерфейс остаётся отзывчивым даже при работе с большими альбомами и папками на сотни файлов.


Содержание


Возможности

  • Работа с локальной vision-моделью через OpenAI-совместимый API LMStudio (адрес и имя модели задаются в настройках).
  • Подписи к фото ВК:
    • выбор альбома и владельца, фильтрация по «без подписи»;
    • автоматический режим — пакетная обработка с прогрессом, текущим фото и кнопкой отката последней правки;
    • ручной режим — пошаговый просмотр с предложением модели, которое можно принять, исправить или пропустить.
  • Локальный распределитель файлов:
    • очередь задач — несколько папок ставятся в ряд и обрабатываются последовательно (следующая idle-задача стартует автоматически);
    • шаблоны настроек — наборы правил/папок/моделей сохраняются под именем и переиспользуются как пресет для новых задач;
    • построение списка целевых папок прямо моделью (по существующей структуре каталога-источника или с нуля по описанию);
    • режим «оставить нераспознанные на месте» либо сложить их в папку _unsorted;
    • индивидуальные переопределения модели и температуры на каждую задачу;
    • превью-миниатюры (генерируются на стороне Rust в JPEG ≈10 КБ, чтобы WebView2 не декодировал тяжёлые HEIC/PNG в основном потоке).
  • Открытие файла по клику и «Показать в проводнике» через tauri-plugin-opener.
  • Тёмная и светлая темы Naive UI, выбор сохраняется между сессиями.

Системные требования

Компонент Минимум
ОС Windows 10/11 (приложение собирается под NSIS-installer; теоретически портируется на Linux/macOS, но не тестировалось)
Node.js 24.14+ (см. engines в package.json)
Rust стабильный канал, 1.77.2+ (требование tauri-plugin-opener)
Tauri CLI ставится через @tauri-apps/cli (зафиксирован в devDependencies)
LMStudio любая текущая версия с включённым OpenAI-совместимым API и загруженной vision-моделью (например, Qwen2-VL, Llava, MiniCPM-V)
Видеокарта желательно дискретная — vision-модель и компоновщик WebView2 делят GPU; на интегрированной графике возможны видимые подтормаживания UI во время массовой классификации

Установка и запуск

git clone https://github.com/<your-fork>/vk-caption-ai.git
cd vk-caption-ai

npm install

npm run tauri:dev

Команда tauri:dev сначала поднимает Vite-сервер на http://localhost:1420, а затем стартует Tauri-окно, которое к нему подключается.


Первичная настройка

  1. Откройте вкладку Настройки в приложении.
  2. Заполните блок VK (нужно только для режима подписей):
    • VK Token — получается на vkhost.github.io (приложение VK Admin или собственное); хранится локально, на серверы не уходит.
    • VK Owner IDid пользователя или сообщества (для группы — со знаком минус, как принято в VK API).
    • VK Album ID — выбирается из выпадающего списка после ввода токена, либо вводится вручную (100 = «Сохранённые», wall = «Со стены» и т.д.).
  3. В блоке LMStudio укажите:
    • Хост LMStudio — обычно http://localhost:1234.
    • Имя модели — точное имя из LMStudio (например, qwen2-vl-7b-instruct).
    • Температуру — творческий разброс при генерации (0 → детерминированно, 1 → сильно «фантазирует»).
  4. Выберите режим обработки: Авто или Ручной.

Все настройки сохраняются через tauri-plugin-store (на диск в JSON) и доступны при следующем запуске.


Режим «Подписи к фото ВК»

Открывается из вкладки Главная.

  • Кнопка «Запустить» загружает фотографии указанного альбома, у которых ещё нет подписи, и обрабатывает их по очереди:
    • в авторежиме — без вмешательства пользователя; кнопка «Отменить» возвращает последнюю сохранённую подпись;
    • в ручном режиме — открывается модальное окно ManualReviewModal, где можно принять, отредактировать или пропустить предложение модели.
  • Сводная статистика «Всего / Обработано / Пропущено / Ошибки» обновляется по ходу работы, ниже виден прогресс-бар и текущее фото.
  • Список всех фото рендерится через n-virtual-list — окно остаётся отзывчивым даже на альбомах в тысячи снимков.

Режим «Распределение»

Открывается из вкладки Распределение. Левая колонка — форма задачи, правая колонка — очередь.

Шаблоны настроек

Полный набор полей формы (папка-источник, папка-назначение, правила, список целевых папок, оверрайды модели и температуры, поведение для пропущенных файлов) можно сохранить как шаблон под произвольным именем:

  • «Создать» — добавляет новый шаблон с дефолтными значениями.
  • «Создать как копию» — клонирует текущий активный шаблон под другим именем (удобно для разводки «Фото / Документы / Скриншоты»).
  • «Удалить шаблон» — убирает пресет; задачи в очереди, созданные по этому шаблону, остаются нетронутыми (config задачи — это её собственный снимок настроек, ссылка на шаблон хранится только как метка).

Активный шаблон используется как пресет для следующей создаваемой задачи. Если форма привязана к уже существующей задаче, выбор шаблона его не меняет.

Очередь задач

  • При нажатии «Запустить» на пустой очереди создаётся новая задача из текущей формы и стартует немедленно.
  • Если очередь не пуста, можно «Добавить в очередь» — задача встанет в ряд со статусом idle и стартует автоматически, как только освободится обработчик.
  • Состояния задачи: idleprocessingdone / cancelled / error.
  • Активная задача показывает «текущий файл», прогресс и сводную статистику (moved / skipped / failed). По завершении автоматически активируется следующая idle-задача.
  • Кнопка «Остановить» прерывает текущую задачу через AbortController: Rust-команды organizer_classify_image и organizer_move_file поддерживают отмену, текущий файл откатывается в pending, задача переходит в cancelled, очередь продолжает работать со следующей.
  • Удаление задачи из очереди — крестиком; активную processing-задачу предварительно нужно остановить.

Целевые папки и правила классификации

  • Список целевых папок заполняется тегами через Enter, при необходимости можно сгенерировать его моделью:
    • «Сгенерировать из существующих» — модель смотрит на содержимое каталога-источника (имена подпапок и нескольких файлов в каждой) и предлагает рабочий список;
    • «Сгенерировать с нуля» — модель опирается только на правила пользователя.
  • Свободные правила — текстовое поле, куда пишутся подсказки моделью на естественном языке: «Скриншоты UI и кода → «Скриншоты»; селфи и портреты → «Люди»; всё, что не подходит, отметь как SKIP» и т.п.
  • Поведение для нераспознанных файлов:
    • либо переместить в папку с настраиваемым именем (по умолчанию _unsorted);
    • либо оставить на месте.
  • Оверрайды модели и температуры на конкретную задачу — пусто = брать значения из общих настроек.

Миниатюры и список файлов

  • Список файлов виртуализирован (n-virtual-list) и при необходимости отключается полностью (если очередь огромная — UI становится легче).
  • Миниатюры генерируются Rust-командой organizer_get_thumbnail: декодирование, ресайз и перекодирование в JPEG ≈10 КБ выполняются вне главного потока; в WebView2 уезжает уже готовый data:-URL. Параллелизм ограничен (MAX_CONCURRENT = 2 в useThumbnail), кеш общий на всё приложение.
  • Превью можно отключить чекбоксом «Показывать миниатюры», если интегрированная графика не справляется одновременно с vision-моделью и предпросмотром.

Сохранение состояния

Состояние распределения (шаблоны, очередь задач, выбор активной задачи, переключатели UI) хранится в localStorage под ключом vk-caption-ai-organizer. Запись организована вручную, без pinia-plugin-persistedstate, и оптимизирована под сценарий «горячая обработка сотен файлов»:

  • запись делается по дебаунсу в 600 мс — пачка реактивных мутаций сериализуется один раз;
  • watcher слушает не сами задачи, а проекцию-геттер, в которую массив images намеренно не входит. Поэтому смена статуса очередного файла в горячем цикле не дёргает сейв вообще — мутации видит только Vue, до JSON.stringify они не доходят;
  • при записи images у каждой задачи сбрасывается в пустой массив: список файлов всё равно перестраивается Rust'ом при следующем запуске задачи (organizer_list_images), а сводная статистика и currentIndex переживают перезагрузку и видны в очереди;
  • хвост сохраняется на beforeunload, чтобы последняя правка формы не пропала при закрытии окна;
  • при восстановлении задача со статусом processing приводится к cancelled (с пометкой «Обработка прервана перезапуском приложения»), «зависшие» файлы со статусом processing возвращаются в pending.

Дополнительно, во время активной обработки, на корневом контейнере страницы поднимается класс organizer-view--running, который через :deep(*) обнуляет CSS-transition и animation Naive UI, а тяжёлые секции (форма, правая колонка, виртуальный список, текущее фото) изолированы через contain: layout paint style. Это снижает нагрузку на компоновщик WebView2 в условиях, когда GPU занят инференсом vision-модели.


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

src/
  main.ts                 — точка входа Vue + Pinia + Naive UI
  router/index.ts         — три маршрута: /, /organizer, /settings
  views/
    HomeView.vue          — режим подписей к фото ВК
    OrganizerView.vue     — распределение: форма, очередь, список файлов
    OrganizerImageItem.vue — элемент виртуального списка с превью и статусом
    SettingsView.vue      — общие настройки: VK + LMStudio
  stores/
    app.ts                — режим подписей (фото, прогресс, отмена)
    organizer.ts          — распределение: шаблоны, очередь, ручная персистентность
    theme.ts              — выбор темы Naive UI
  composables/
    useThumbnail.ts       — ленивый загрузчик миниатюр через Rust-команду
  components/
    ManualReviewModal.vue — модалка ручного режима (по одному фото)

src-tauri/
  src/
    main.rs               — bootstrap Tauri, регистрация плагинов и команд
    commands.rs           — команды режима подписей (VK API, LMStudio, store)
    organizer.rs          — команды распределения: list / classify / move /
                            generate folders / thumbnail
  capabilities/default.json — разрешения плагинов (opener, store, dialog)
  tauri.conf.json         — конфигурация окна и сборки

Скрипты

Команда Что делает
npm run dev запускает только Vite-сервер (без Tauri-окна) — удобно для отладки UI в браузере
npm run build проверяет типы (vue-tsc --noEmit) и собирает фронт через Vite
npm run typecheck только проверка типов, без сборки
npm run tauri:dev боевой dev-режим: Vite + Tauri-окно с DevTools
npm run tauri:build продакшен-сборка → NSIS-installer в src-tauri/target/release/bundle/nsis/

Сборка релиза

npm run tauri:build

На выходе получается NSIS-инсталлятор VK Caption AI_<version>_x64-setup.exe в каталоге src-tauri/target/release/bundle/nsis/. Конфигурация бандла, иконки и идентификатор приложения задаются в src-tauri/tauri.conf.json и src-tauri/Cargo.toml.

About

Десктопное приложение для автоматической генерации описаний к фотографиям (стикерам) в альбомах VK с использованием современных Vision-моделей через LM Studio. Дополнительно: Позволяет с помощью промпта отсортировать фото по локальным папкам.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors