Electron + React desktop app for preparing image datasets: crop workspace with batch export, plus local AI captioning (Ideogram 4 structured captions and plain text) powered by llama.cpp running Uncensored Qwen3-VL.
Crop tab — thumbnail grid, crop workspace with aspect locks, batch GO bar:
Caption tab — queue sidebar, image with bbox overlay, structured Ideogram 4 editor:
- Left grid: load a folder of images (jpg/jpeg/png/tif/tiff/webp/bmp/avif) into a thumbnail grid. Click to focus, hover
×to move to Recycle Bin. - Workspace: large view with zoom slider and draggable/resizable crop box (8 handles) with aspect locks (
free, 1:1, 4:5, 5:4, 4:3, 3:4, 16:9, 9:16, 3:2, 2:3). - Rotate: per-image 90° steps (⟲ ⟳ + reset). Rotation applies first at export, so crop and aspect work in rotated space; preview and thumbnail badges reflect it.
- Settings memory: each image keeps
{crop, aspect, upscaleEnabled, rotation}until GO. - Upscale: global
2×toggle (all) + per-image2×toggle (sharp lanczos3, local). - Forced format: global
jpg/png/tif/webpapplied on export. - GO: batches
rotate → crop → upscale → convertvia sharp into<source>/CaptionManager_output_<ISOtimestamp>/, with progress bar + open-output button. Finished outputs are handed to the Caption tab automatically.
- Queue sidebar: cropped outputs appear here after every GO, with status dots (done / failed / new). Load Folder fills the queue directly from any folder with cropped images — no trip through the Crop tab needed.
- Ideogram 4 editor (3 columns: queue | image + bbox overlay | text editor):
- Bbox canvas overlay — click to select, drag to move, corner-drag to resize, Ctrl+click to cycle stacked boxes, draw-new-box modes for objects and text. Clicking a box scrolls its element card into view.
- Structured editor — Overview, Style (aesthetics, lighting, medium, photo/art toggle, palettes), Composition, Elements (desc, exact text, bbox inputs, per-element palettes). All text fields auto-grow to fit their content.
- Palettes are sampled from real pixels per bbox region after every generation (plus manual 🎨 re-sample buttons), so skin tones and clothing colors are truthful. Each caption shows a
🎨 n/m sampledtag proving which boxes got measured colors.
- Plain-text mode: single-paragraph captions with a simple text editor.
- Steering modal (🎛): instructions appended to the system prompt for every caption (e.g. prefix
high_level_description); prefix requests are also enforced deterministically. - Autosave: captions save on generate, on edit (debounced), and when switching images (
.json/.txtsidecars next to the image). - Batch: Caption all / Save all across the queue.
- Model:
Huihui-Qwen3-VL-8B-Instruct-abliterated-Q4_K_M.gguf+mmproj-F16.gguf(spawnedllama-server, persistent daemon, GPU layers on). - GGUFs are NOT bundled with the portable exe — download at first launch.
- Settings modal (⚙): point to a folder containing the models, or download them in-app with progress (~6 GB). Resolution order: chosen folder → bundled
models/(dev) → app-data folder. Starting a caption with missing models opens Settings automatically.
- At startup the app compares its version against
package.jsonon GitHubmainand shows an Update available dialog with a direct link to the releases page when newer. Silent when up to date or offline. - Settings modal has a Check for updates at startup toggle (on by default) plus a Check now button.
npm install # deps + native rebuild + llama bin + VLM models (postinstall)
npm run electron:dev # vite + electron (recommended dev)
npm run electron # electron with built dist (needs npm run build first)
npm run build # vite build → dist/
npm run dist # build + electron-builder → portable exe (win x64, models excluded)
npm run setup-caption # (re)download llama-server bin + VLM models
npm run download-vlm # VLM models only (progress bar, skip-if-complete)
npm run download-llama # llama.cpp binaries only
npm test # vitest unit suite (no Electron needed)Ships as a Pinokio 8 app (pinokio.js, install.js, start.js, update.js, reset.js, icon.png): install from https://github.com/Arnold2006/CaptionManager.git, Install (npm + models + build), Start launches the Electron window.
electron/ # main (window lifecycle) + preload + splash
config.js # all tunable constants (ports, temps, timeouts, sizes)
log.js # debug log + crash/close diagnostics
images.js # listing, thumbs, oriented previews, palette sampling
batch.js # rotate → crop → lanczos-2× → convert pipeline
captions.js # caption IPC (vision-model orchestration in captionServer.js)
models.js # settings + first-launch model download IPC
updates.js # GitHub version check (pure, unit-tested)
palette.js # dominant-color quantization (pure, unit-tested)
src/App.jsx # tab shell + crop state + batch GO + settings host
src/components/ # CropTab, ThumbnailGrid, Workspace, CropBox,
# CaptionTab + ElementCard + PaletteField + BboxCanvas,
# SettingsModal, AutoTextarea, ErrorBoundary, dialog
src/lib/ # mapLimit (promise pool), caption (data helpers)
test/ # vitest suite — `npm test`
scripts/ # llama-server + VLM model download helpers
models/ # local VLM models (gitignored: *.gguf)
bin/ # llama-server binaries (gitignored, bundled in portable)

