中文文档见 README_zh.md
LingoPic is a macOS desktop app that localizes the text inside product images for cross-border e-commerce — batch-converting Simplified Chinese to Taiwan Traditional (with localized phrasing) or Chinese to natural English. AI-powered, local-first, and it never touches your originals.
- Batch Conversion — select a folder, convert hundreds of product images in one go. Mirror directory output preserves your original files untouched.
- Multi-Provider AI — pluggable image-edit models (Gemini, GPT Image, Seedream, Qwen) and vision models (Gemini, GPT, Kimi). Bring your own API keys.
- Vision Preflight + Review — vision models pre-scan images for text before editing and review results after, catching missed conversions or artifacts.
- Quality Tiers — "Fast & Cheap" vs "Slow & Accurate" presets that map to different model + prompt combinations. Pick per batch.
- Overlay Compare — side-by-side and overlay comparison modes with keyboard shortcuts (arrow keys, space to flash). Instantly spot what changed.
- Resume / Checkpoint — conversion state is persisted by content hash + parameter key. Interrupted batches pick up where they left off — no double billing.
- Compliance Scanner — detect policy violations (banned terms, contact info, QR codes, platform-specific phrases) with customizable rules.
- Long Image Splitting — auto-split tall images into chunks the model can handle, then merge results back.
- Single-Image Wizard — step-by-step guided conversion for individual images: preflight → edit → review.
- First-Launch Onboarding — 3-step wizard (configure API key → choose models → start converting) for new users. Skips automatically after completion.
- Full-Auto & Semi-Auto Modes — run the entire folder unattended, or preview and approve each image before processing.
Pre-built macOS apps are published on the Releases page (Apple Silicon / arm64). Download the .dmg, drag the app to /Applications, then remove the Gatekeeper quarantine flag (the app is not Apple-notarized):
sudo xattr -rd com.apple.quarantine /Applications/LingoPic.appSee docs/INSTALL.md for details. To build from source instead, follow Quick Start below.
- macOS (the app uses Keychain for API key storage)
- Node.js 22+ (managed via mise or nvm)
- API key for at least one supported provider (see below)
| Type | Provider | Default Model |
|---|---|---|
| Image Edit | Gemini | gemini-2.5-flash-image |
| Image Edit | GPT Image | gpt-image-1 |
| Image Edit | Seedream | seedream-4.0 |
| Image Edit | Qwen | qwen-image-edit-plus |
| Vision | OpenAI GPT (Vision) | gpt-5.5 |
| Vision | Gemini (Vision) | gemini-2.5-flash |
| Vision | Kimi (Vision) | kimi-k2-community |
Vision models handle preflight text detection and post-edit review. Image-edit models perform the actual conversion. Each is independently configurable.
# Clone
git clone https://github.com/jianglin-wu/lingopic.git
cd lingopic
# Install dependencies
npm install
# Start dev mode (Electron + Vite HMR)
npm run dev
# Run tests
npm test # 475 unit tests (vitest)
npm run test:e2e # 34 E2E tests (Playwright)
npm run typecheck # TypeScript check- Open the app, navigate to Settings (sidebar)
- Under Model Config, select a provider tab (e.g., GPT Image)
- Enter your API endpoint, model name, and API key
- Click Test Connection to verify
- Under Active Models, choose your default image-edit and vision models
- Switch back to Import, choose a folder, and start converting
src/
main/ # Electron main process — window, IPC handlers, services, providers
ipc/ # IPC handler per domain (config, batch, conversion, compliance, etc.)
services/ # Pure logic: ConfigService, ConversionService, BatchQueueService, etc.
providers/ # Model adapters (Gemini, GPT Image, Seedream, Qwen, vision providers)
preload/ # contextBridge — exposes whitelisted API to renderer
renderer/ # React 19 SPA
pages/
Import.tsx # Main page: import, batch, compare, retry, split, compliance
Settings.tsx# Settings: providers, proxy, tiers, prompts, compliance rules
import/ # 30+ sub-components for cards, dialogs, panels, overlays
settings/ # 7 settings panel components
shared/ # Types, IPC channels, conversion/batch/tier/prompt contracts
e2e/ # Playwright E2E tests (browser mode + mocked IPC)
docs/ # Install guide and tech design reference
Electron 3-process architecture built with electron-vite:
┌─ Main Process ──────────────────────────────────┐
│ BrowserWindow │ IPC Handlers │ Services │
│ ProviderRegistry (Gemini/GPT/Seedream/Qwen) │
│ BatchQueueService (concurrency + retry) │
│ JobStateService (content-hash checkpointing) │
└──────────────────────────────────────────────────┘
│ invoke/handle │ webContents.send
▼ ▼
┌─ Preload ───────────────────────────────────────┐
│ contextBridge.exposeInMainWorld('api', { ... }) │
└──────────────────────────────────────────────────┘
│
▼
┌─ Renderer (React 19) ───────────────────────────┐
│ Import Page │ Settings Page │
│ window.api.xxx() — typed IPC calls │
└──────────────────────────────────────────────────┘
1. Read source image
2. [Vision Preflight] → detect text, generate conversion table
3. Edit Request → image-edit model with combined prompt
4. Download output (provider-dependent)
5. Normalize → match original format & dimensions
6. [Vision Review] → verify edited image quality
7. Atomic write → tmp → rename to mirror directory
| Command | Description |
|---|---|
npm run dev |
Start Electron + Vite dev server with HMR |
npm run build |
Build all three processes to dist/ |
npm run package |
Build + package as macOS .app |
npm test |
Run 475 vitest unit tests |
npm run test:e2e |
Run 34 Playwright E2E tests (headless) |
npm run test:e2e:ui |
Playwright interactive UI mode |
npm run typecheck |
tsc --noEmit |
| Layer | Technology |
|---|---|
| Framework | Electron 35 |
| Build | electron-vite 3, Vite 6 |
| UI | React 19, TypeScript 5.8 |
| Testing | Vitest (475 tests), Playwright (34 E2E) |
| Packaging | electron-builder |
| API Keys | macOS Keychain (/usr/bin/security) |
- Never overwrite originals — output goes to
<source>_繁体/<run-label>/, atomic write via tmp→rename - Bring your own keys — API keys stay in macOS Keychain, never written to disk in plaintext
- Resumable by default — every job is checkpointed by content hash + parameter key. Interrupted = resumed, not restarted
- Model-agnostic — provider adapters implement a shared interface. Adding a new model is a single adapter file + registry entry
MIT — see LICENSE for full text.
Built for cross-border e-commerce sellers localizing product images for new markets (Taiwan Traditional, English, and more to come). "LingoPic" = lingo (the words) + pic (the picture) — the words in your product pictures, made local.