Commit Graph
172 Commits
Author SHA1 Message Date
Claude 38e80f8fb8 Add BEN2 and BiRefNet-HR as selectable Remove Background models
BEN2 becomes the new default local backend (clean cutouts, strong on
hair/fur edges), with BiRefNet-HR available as a high-res/print
alternate and U2Net kept as the lightweight fallback. Both are
MIT-licensed and download weights from HuggingFace on first use
(cached via the existing hf_cache bind mount), unlike U2Net/SAM which
need an explicit download script.

- config: new BG_REMOVAL_MODEL setting (default "ben2")
- tools.py: remove-background-base64 now tries local backends in
  order (request.model override > BG_REMOVAL_MODEL > ben2/u2net),
  falling back to rembg's birefnet-general session as a last resort
- requirements.gpu.txt / Dockerfile.gpu: add ben2 + transformers deps
  needed for the new backends, with a build-time smoke test for ben2
- frontend: model dropdown in the Remove Background dialog, threaded
  through api.js to the new request field

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ro4PwQKvSc3CH19LSN21Ht
2026-06-18 14:20:24 +00:00
Claude 781b9e7cdc Fix install-local-gpu.sh running its entire setup body twice
Commit 5c85987 appended a second copy of the toolkit-install/DNS-fix/
GPU-verify steps instead of inserting the new prerequisite-checks
section once. Removed the duplicate, keeping the more informative
GPU-check failure message from the second copy.
2026-06-18 13:57:28 +00:00
Claude a4a9dbc33a Auto-download U2Net model on startup; remove dead PyTorch U2Net module
U2Net only ever downloaded lazily on the first Remove Background click,
unlike SAM which retries on every container start. If that one attempt
failed (DNS/firewall) the model was never fetched again, surfacing as
"No background removal method available. Install u2net or rembg."

Mirrors the existing SAM auto-download/AUTO_DOWNLOAD_SAM pattern for
U2Net, and documents manual host-side recovery in the README.

Also deletes backend/app/services/u2net_model.py (hand-written
U2NET/U2NETP PyTorch classes) — unused since tools.py switched to
cv2.dnn.readNetFromONNX for background removal.
2026-06-18 13:10:07 +00:00
Outis 34642161f4 Merge pull request #61 from outis1one/claude/fervent-dirac-ldwaki
install-local-gpu.sh: add prerequisite checks before setup steps
2026-06-15 18:44:30 -04:00
Outis be8ee77a7c Merge pull request #60 from outis1one/claude/compassionate-albattani-s4lqb5
Add AI subject replace: file-picker compositing with LAB color matching
2026-06-15 11:57:41 -04:00
Claude 142df74192 Add AI subject replace: file-picker compositing with LAB color matching
- Backend: POST /api/image/replace-subject
  Uses rembg to extract the subject from a source photo, scales it to fit
  the selection mask bounding box (or canvas centre when no selection is
  active), applies a partial LAB color transfer (blend=0.45) so the
  subject's lighting matches the background, then composites the result.
  Also adds POST /api/image/extract-subject for standalone subject extraction.

- Frontend: "Replace with subject from file" button in the selection panel
  (selection_actions.js) — opens a native file picker so no clipboard API
  or HTTPS is required.  Calls the new endpoint with the current SAM mask.

- Frontend: Image > Replace Subject (AI)... menu entry backed by
  modules/image/replace_subject.js — a full dialog with file picker,
  thumbnail preview, and "match background lighting" toggle.  Works with
  or without a prior Smart Select; if a selection exists it confines the
  subject to that region.

https://claude.ai/code/session_01UtrvbisMp1yGu6PqeLmrFr
2026-06-15 15:04:37 +00:00
Claude 5c85987278 install-local-gpu.sh: add prerequisite checks before setup steps
Checks Docker installed + daemon running, NVIDIA driver (nvidia-smi),
and curl. Prints specific install commands for each missing dependency
and exits early with a clear summary rather than failing partway through.

https://claude.ai/code/session_01WVDg7amsy1TTtxvpku7bcM
2026-06-14 10:06:31 +00:00
Outis ffe56c99e9 Merge pull request #59 from outis1one/claude/fervent-dirac-ldwaki
Claude/fervent dirac ldwaki
2026-06-14 06:03:01 -04:00
Claude ea77d95ab0 Replace start-gpu.sh with install-local-gpu.sh + bring-up-local-gpu.sh
install-local-gpu.sh (run once):
- Installs nvidia-container-toolkit (Ubuntu/Debian/RHEL auto-detected)
- Installs docker-dns-fix.service systemd unit: permanent iptables DNS
  fix that runs after docker.service on every boot, without touching ufw
- Restarts Docker and applies the rule immediately
- Verifies GPU is accessible inside Docker

bring-up-local-gpu.sh (run each time):
- Thin wrapper: docker compose -f docker-compose.gpu.yml up -d --build
- Accepts pass-through args (down, logs -f, --no-build, etc.)
- BUILDID=$(date +%s) ./bring-up-local-gpu.sh for pip cache bust

README Quick Start, Updates, and Troubleshooting updated accordingly.

https://claude.ai/code/session_01WVDg7amsy1TTtxvpku7bcM
2026-06-14 01:04:26 +00:00
Claude 7cfbb6034f Add start-gpu.sh: auto-applies iptables DNS fix before container start
The iptables DOCKER-USER rule is lost on reboot; the script re-applies
it each run, checks for duplicates, and is silently skipped on macOS/WSL.
Default behaviour (no args): docker compose up -d --build.
All docker compose subcommands can be passed as args (logs, down, etc.).
README Quick Start and Updates sections now reference ./start-gpu.sh.

https://claude.ai/code/session_01WVDg7amsy1TTtxvpku7bcM
2026-06-14 00:58:43 +00:00
Claude ce29cc1d30 README: restore iptables as primary DNS fix with isolation clarification
iptables fix is simpler (one command, no 13 GB download) and does not
affect container isolation — adds clarifying note so users understand
it only restores Docker's default outbound DNS behaviour.
Docker helper container kept as fallback option.

https://claude.ai/code/session_01WVDg7amsy1TTtxvpku7bcM
2026-06-14 00:55:09 +00:00
Claude d83f94cc24 README: use Docker helper container for offline model download
Replaces 'pip install huggingface-hub' (breaks on PEP 668 / Debian 12+)
with a docker run --rm python:3.11-slim one-liner that downloads directly
into ./data/hf_cache without touching host Python packages.

https://claude.ai/code/session_01WVDg7amsy1TTtxvpku7bcM
2026-06-14 00:53:54 +00:00
Claude b63a4f9187 README: simplify AI model offline download — remove iptables option
Replace two-option (iptables vs download) with a single clear offline
download path using huggingface-cli into ./data/hf_cache.

https://claude.ai/code/session_01WVDg7amsy1TTtxvpku7bcM
2026-06-14 00:38:45 +00:00
Outis 4cc92c3e40 Merge pull request #58 from outis1one/claude/fervent-dirac-ldwaki
Claude/fervent dirac ldwaki
2026-06-13 20:36:12 -04:00
Claude 11772e620c Fix build cache, DNS/model download, and AI Edit error handling
Build / pip layer fixes:
- Add BUILDID ARG to Dockerfile.gpu; pass from docker-compose.gpu.yml build args
  so pip layers can be force-busted without --no-cache:
    BUILDID=$(date +%s) docker compose -f docker-compose.gpu.yml up --build

Model download (DNS-blocked environments):
- Change HF model cache from named volume to ./data/hf_cache bind mount
  so models can be pre-downloaded on the host (no rebuild needed)
- Remove now-unused hf_model_cache named volume
- README: add iptables fix + huggingface-cli offline download instructions

Error handling improvements:
- ai_edit_region: catch ConnectError/Errno-3 → return 503 with exact fix commands
- _require_remote: give actionable message when local_gpu provider fails to load
- _build_provider: catch AttributeError (torch.xpu from wrong diffusers) not just ImportError
- local_diffusion.py: fix docstring to reflect <0.29.0 pin

https://claude.ai/code/session_01WVDg7amsy1TTtxvpku7bcM
2026-06-14 00:14:34 +00:00
Claude 59b26b6d5e Fix diffusers/torch compat, SAM docs, and SelectionActions UX
- Pin diffusers to >=0.28.0,<0.29.0 to avoid AttributeError on torch.xpu
  (diffusers 0.29+ requires PyTorch 2.4 but base image ships 2.1.2)
- Pin transformers to <4.40.0 to match
- README: add SAM offline download troubleshooting for DNS-blocked containers
- SelectionActions panel: 'Selection ready' title + subtitle makes clear
  nothing has fired yet; AI actions show inline description (not just tooltip);
  section labels 'AI Actions' / 'Classic Tools'; scale hint updates live;
  Enter key submits AI edit prompt; _actionCard hover border for clickability

https://claude.ai/code/session_01WVDg7amsy1TTtxvpku7bcM
2026-06-13 23:53:21 +00:00
Claude d7683b836a Try Cloudflare DNS first in GPU container; add troubleshooting note
1.1.1.1 uses a different anycast route than 8.8.8.8 so may reach the
container even when Google's servers don't. Falls back to Google if
Cloudflare is also unreachable. If all fail (Errno -3), port 53 UDP is
blocked at the Docker bridge level — comment has the iptables fix.

https://claude.ai/code/session_01WVDg7amsy1TTtxvpku7bcM
2026-06-13 23:35:12 +00:00
Claude 80830beae2 Fix scale-selection 500 error (missing BytesIO import) and compact GPU badge
ai_tools.py: add 'from io import BytesIO' — scale_selection and paste
endpoints used BytesIO directly but it was only imported locally in one
unrelated function, causing NameError on every scale call.

provider-badge.js: redesign badge to fit the narrow (~40px) left toolbar.
Was rendering 'GPU · sdxl_offload · Quadro RTX 3000' inline which wrapped
into multiple lines covering tool icons. Now shows a status dot + short
label (SDXL / OAI / Rep…) with all details moved to the hover tooltip.

https://claude.ai/code/session_01WVDg7amsy1TTtxvpku7bcM
2026-06-13 23:33:07 +00:00
Outis 828a861a17 Merge pull request #57 from outis1one/claude/fervent-dirac-ldwaki
Fix: guard load_plugins() so helper files without a default export do…
2026-06-13 19:21:27 -04:00
Claude 34d9f5aafc Fix: guard load_plugins() so helper files without a default export don't crash tool init
selection_actions.js uses named exports only (no default export).
load_plugins() was calling new classObj.default(ctx) on every file in tools/,
causing TypeError which aborted render_main_tools() -> render_main_gui() ->
leaving menu and toolbar blank. Added null guard and per-file try/catch,
matching the defensive pattern already added to load_modules().

https://claude.ai/code/session_01WVDg7amsy1TTtxvpku7bcM
2026-06-13 23:04:10 +00:00
Outis 9a53ee67e7 Merge pull request #56 from outis1one/claude/fervent-dirac-ldwaki
Claude/fervent dirac ldwaki
2026-06-13 18:53:40 -04:00
Claude 2a0c414a1c Fix: wrap load_modules() in try/catch so a bad module constructor never kills GUI init
Without this, any constructor throw in any module stops load_modules() mid-loop
and render_main_gui() (which builds the menu) never runs — resulting in a blank
page with no menu. The failing module is now logged to the browser console
instead of silently aborting startup.

https://claude.ai/code/session_01WVDg7amsy1TTtxvpku7bcM
2026-06-13 22:43:15 +00:00
OutisandClaude 523aa6971d GPU local inference, print presets, progress bars, selection actions
main.py referenced info.vram_gb but the field is info.vram_total_gb.
This crashed the FastAPI lifespan hook on every startup when
AI_PROVIDER=local_gpu, causing a restart loop.

https://claude.ai/code/session_01WVDg7amsy1TTtxvpku7bcM

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-13 16:12:44 -04:00
Claude 0514f5b67b Fix AttributeError: GpuCapabilities has no attribute 'vram_gb'
main.py referenced info.vram_gb but the field is info.vram_total_gb.
This crashed the FastAPI lifespan hook on every startup when
AI_PROVIDER=local_gpu, causing a restart loop.

https://claude.ai/code/session_01WVDg7amsy1TTtxvpku7bcM
2026-06-13 20:08:55 +00:00
Outis a6542cfc73 Merge pull request #54 from outis1one/claude/fervent-dirac-ldwaki
Rewrite README with accurate current state of the project
2026-06-13 13:43:28 -04:00
Claude 59198a6be2 Rewrite README with accurate current state of the project
Old README described the original React/Fabric.js UI and listed
"No local GPU inference" as a non-goal. Updated to reflect:
- miniPaint-based editor with SAM brush selection
- GPU quick-start (nvidia-container-toolkit prereqs, docker-compose.gpu.yml)
- Cloud API quick-start
- GPU tier auto-selection table (FLUX/SDXL/SD by VRAM)
- Full feature list (selection actions, print tools, progress bars)
- Correct clone URL and update commands
- Troubleshooting section

https://claude.ai/code/session_01WVDg7amsy1TTtxvpku7bcM
2026-06-13 17:15:33 +00:00
Outis 6466142072 Merge pull request #53 from outis1one/claude/fervent-dirac-ldwaki
Claude/fervent dirac ldwaki
2026-06-13 13:11:42 -04:00
Claude 372ab48991 Real per-step progress bars for local GPU inference
Backend:
- local_diffusion.py: add _make_step_cb() that writes step/total_steps/
  progress into _states on every diffusers callback_on_step_end; wired into
  txt2img, inpaint, img2img with TypeError fallback for older diffusers
- ai_tools.py: GET /api/generate/progress SSE endpoint — streams _states
  as JSON array every 200ms so clients get live denoising step counts

Frontend:
- progress_overlay.js: add connectProgressSSE(pipeType, baseUrl) /
  disconnectProgressSSE() — opens EventSource, maps step/total_steps
  to bar percentage (0→85% during denoising, 85→100 for decode/place)
- text_to_image.js: connect SSE before POST, disconnect on done/error
- selection_actions.js: connect SSE for AI edit / asymmetry operations

Result: for local GPU, progress bar shows "Step 12 / 30" with exact fill;
for remote providers and upscale (no step callbacks), shimmer animates.

https://claude.ai/code/session_01WVDg7amsy1TTtxvpku7bcM
2026-06-13 16:48:55 +00:00
Claude ee94282753 Add progress overlay and fix txt2img for local GPU
- New progress_overlay.js: animated fullscreen overlay with shimmer bar,
  fake progress creep, Esc-to-cancel, used by all slow AI operations
- text_to_image.js: allow local_gpu provider (was incorrectly blocked);
  show provider/model/VRAM info in dialog; show estimated generation time;
  use progress overlay during generation
- upscale.js: replace alertify.message with progress overlay (90s estimate
  for AI upscale, 10s for Lanczos)
- frame_fit.js: progress overlay for extend mode (AI outpaint ~45s)
- print_prepare.js: progress overlay for full upscale+frame chain (~2 min)
- selection_actions.js: progress overlay for all AI region edits

https://claude.ai/code/session_01WVDg7amsy1TTtxvpku7bcM
2026-06-13 16:37:04 +00:00
Claude 5940e10542 Add print size presets, 18x24 frame, and Prepare for Print workflow
- Add 18x24" to FRAME_SIZES in backend and frontend (frame_fit.js)
- Add 200 DPI option to frame_fit dialog (adequate for large-format prints)
- Add 18x24 portrait/landscape at 200 and 300 DPI to Canvas Size presets (size.js)
- New /api/print/prepare endpoint: chains AI upscale to target DPI then frame-fit
  in one server-side call (avoids round-tripping a large upscaled image)
- New print_prepare.js module: "Prepare for Print" dialog with per-frame quality
  assessment (current effective DPI, needed upscale factor, AI vs Lanczos note)
- Add "Prepare for Print..." to Image menu above "Fit to Frame..."

https://claude.ai/code/session_01WVDg7amsy1TTtxvpku7bcM
2026-06-13 16:25:56 +00:00
Claude a97834fda3 feat: real-world selection actions — scale %, AI edit, clipboard paste
Backend (3 new endpoints under /api/image/):
- POST /api/image/scale-selection  — scale selected object by any % in-place;
  LaMa/OpenCV fills the exposed gap so the scene looks natural
- POST /api/image/ai-edit-region   — AI redraws the masked region via the
  configured inpaint provider (local_gpu / InvokeAI / ComfyUI / OpenAI)
- POST /api/image/paste-into-selection — scales clipboard image to fit the
  selection bounding box, masks it to the selection shape, composites result

Frontend (selection_actions.js + tool integration):
- New SelectionActions panel: fixed bottom-center HUD that appears
  automatically after every SAM selection (click or paint)
- Panel actions: Scale by % (default 3%), Make less symmetrical (AI),
  custom AI Edit prompt, Replace with clipboard, Copy/Cut to layer, Erase
- Both smart_select.js and brush_select.js updated to show the panel,
  add updateLayerWithResult(), and hide panel on clearSelection/on_leave
- brush_select: offerFloatSelection() replaced with richer action panel

Real-world workflows now supported in one click after painting over object:
  "Make this 3% bigger" → scale-selection (LaMa fills gap)
  "Make this less symmetrical" → ai-edit-region with asymmetry prompt
  "Replace this with what I copied" → paste-into-selection

https://claude.ai/code/session_01WVDg7amsy1TTtxvpku7bcM
2026-06-13 16:10:32 +00:00
Claude 9b895673eb feat: GPU capability display in UI + GTX 1060 6GB SDXL fix
Model selection:
- Add sdxl_offload tier (eff_vram ≥ 4.0 GB) for GTX 1060 6GB and Quadro
  6GB cards that were falling through to SD 2.1 despite SDXL fitting with
  model_cpu_offload. Cards with 5.3 GB effective VRAM now get SDXL quality.
- Update _tier_label(), _caps(), _build_warnings() for new tier.

Frontend GPU display:
- api.js: add getGpuStatus() fetching /api/gpu/status
- capabilities.js: add getGpuStatus() export with own LRU cache;
  refreshCapabilities() now also resets GPU status cache
- provider-badge.js: when AI_PROVIDER=local_gpu show green badge with
  GPU name, tier, VRAM, CC, feature flags, and capabilities in tooltip.
  Strip "NVIDIA GeForce" prefix so "GTX 1060 6GB" fits in badge.
- ai_provider_settings.js: add local_gpu to all provider dropdowns;
  show GPU info panel (device, VRAM, CC, features, tier, model table per
  operation) in the settings dialog when a GPU is detected.

https://claude.ai/code/session_01WVDg7amsy1TTtxvpku7bcM
2026-06-13 15:58:13 +00:00
Claude fe4d911a00 Dynamic GPU capability detection: probe CC, VRAM, feature flags, pick best model
Replaces fixed tier table with real hardware probing and dynamic model selection.

gpu_detect.py — complete rewrite:
- Reads torch.cuda.get_device_properties + mem_get_info for actual free VRAM
- Detects: fp16 (CC≥6.0), bf16 (CC≥8.0), fp8 (CC≥8.9 Ada/Hopper),
           int8 (CC≥7.0), tensor_cores (CC≥7.0), xformers presence
- Pre-Pascal (CC<6.0): effective_vram halved (fp32 weights are 2× larger)
- Subtracts 400MB driver overhead from free VRAM before model selection
- _select_txt2img / _select_inpaint / _select_img2img / _select_upscale:
    eff≥20GB  → FLUX.1-schnell (no offload)
    eff≥10GB  → FLUX.1-schnell (model_cpu_offload)
    eff≥7.5GB → SDXL
    eff≥5.5GB → SDXL + attention_slicing
    eff≥3.5GB → SD 2.1
    eff≥2.5GB → SD 2.1-base + attention_slicing
    eff≥1.7GB → SD 1.5
    else      → SD 1.5 + sequential_cpu_offload
- ModelSpec carries: model_id, family, memory_opt, native_res, vram_fp16_gb
- Warnings: old CC, pre-Pascal fp32, fp8 upgrade hint, xformers install tip
- Compatibility shim get_model_ids() retained for existing callers
- infer_spec_from_model_id() auto-detects family from HF_MODEL_* overrides

local_diffusion.py — refactored to use ModelSpec:
- Reads spec from GpuCapabilities.recommended[op] instead of tier table
- FLUX.1-schnell: FluxPipeline / FluxImg2ImgPipeline, 4 steps, guidance=0.0
- SD families: family-aware pipeline class selection (sd15/sd2x/sdxl)
- Memory opts applied per ModelSpec.memory_opt field
- xformers attention enabled automatically when xformers detected

gpu_status.py — richer response:
- Exposes all feature flags (fp16/bf16/fp8/int8/tensor_cores/xformers)
- Returns full ModelSpec per operation (model_id, family, memory_opt, native_res)

ai_tools.py — /api/config exposes:
- gpu_vram_total, gpu_vram_free, gpu_cc, gpu_fp16, gpu_bf16, gpu_fp8,
  gpu_tensor_cores, gpu_eff_vram, local_gpu_warnings

requirements.gpu.txt:
- diffusers bumped to >=0.29.0 (FLUX pipeline added in 0.29)
- transformers bumped to >=4.40.0
- sentencepiece added (FLUX T5 tokenizer)

scripts/gpu_setup.py:
- Prints full model table at startup (op → model_id, family, memory_opt, res)
- Shows all feature flags in one line

https://claude.ai/code/session_01WVDg7amsy1TTtxvpku7bcM
2026-06-13 15:35:37 +00:00
Claude 46b9066bba Handle old/low-VRAM GPUs and document nvidia-container-toolkit requirement
GPU tier table extended:
  ultra   ≥16 GB → SDXL (unchanged)
  high    8-16 GB → SDXL (unchanged)
  medium  4-8 GB → SD 2.x (unchanged)
  legacy  2-4 GB → SD 1.5 (~1.7 GB fp16)  ← new: GTX 970/1060/RX 580 etc.
  minimal <2 GB  → SD 1.5 + sequential CPU offload  ← new: very old/integrated GPUs

gpu_detect.py:
- Detects CUDA compute capability (CC); fp16 disabled for CC < 6.0 (pre-Pascal)
- GpuInfo gains compute_capability and warnings fields
- _make_warnings() emits human-readable warnings for low VRAM and old CC
- model tier fallback updated from 'low' to 'legacy'

local_diffusion.py:
- minimal/legacy tiers use enable_sequential_cpu_offload() + enable_attention_slicing(1)
- target resolution per tier: ultra/high=1024, medium=768, legacy/minimal=512
- .to(device) skipped when sequential CPU offload is active

gpu_status.py:
- Response now includes compute_capability and warnings

docker-compose.gpu.yml:
- Full nvidia-container-toolkit install instructions in header comment
- nvidia-docker2 (legacy) fallback documented as comment block inline
- AMD ROCm swap-in instructions added
- GPU tier table documented in header

scripts/gpu_setup.py:
- Prints compute capability, fp16 status, tier, and model selection at startup
- Prints per-tier warnings (old CC, low VRAM)

https://claude.ai/code/session_01WVDg7amsy1TTtxvpku7bcM
2026-06-13 15:19:01 +00:00
Claude 8fe8498df2 Add local GPU inference: auto-detect GPU, auto-download best diffusion models
Adds AI_PROVIDER=local_gpu — a fully self-contained GPU inference engine
using HuggingFace Diffusers that requires zero InvokeAI/ComfyUI setup.
All existing providers (InvokeAI, ComfyUI, OpenAI, Replicate) remain intact
and can be mixed with local GPU via per-operation overrides.

New features:
- GPU auto-detection (CUDA/NVIDIA, MPS/Apple Silicon, CPU fallback)
- VRAM-tiered model selection:
    ultra ≥16 GB → SDXL inpaint + SDXL base
    high  8-16 GB → SDXL inpaint + SDXL base
    medium 4-8 GB → SD 2.x inpaint + SD 2.1
    low  <4 GB   → SD 2.x (small)
- Auto-download model weights to HuggingFace disk cache at startup
  (background task; first request loads from local disk, not internet)
- LRU pipeline cache evicts oldest GPU pipeline when VRAM limit reached
- Per-operation model overrides via HF_MODEL_INPAINT / HF_MODEL_TXT2IMG etc.
- Optional HF_TOKEN for gated/private HuggingFace models

New files:
- backend/app/services/gpu_detect.py   — GPU detection + tier/model mapping
- backend/app/services/local_diffusion.py — Diffusers provider + LRU cache
- backend/app/routers/gpu_status.py    — GET /api/gpu/status, POST /api/gpu/prefetch
- backend/requirements.gpu.txt         — Diffusers ecosystem deps (GPU only)
- docker-compose.gpu.yml               — NVIDIA GPU compose (one-command startup)
- Dockerfile.gpu                       — pytorch/pytorch:2.1.0-cuda12.1 base image
- scripts/gpu_setup.py                 — Startup GPU info logger

Modified:
- backend/app/config.py                — local_gpu settings added
- backend/app/services/remote_provider.py — local_gpu registered as provider
- backend/app/routers/ai_tools.py      — /api/config exposes GPU tier + caps
- backend/app/main.py                  — GPU router + background prefetch task
- backend/entrypoint.sh                — runs gpu_setup.py at container start
- .env.example                         — local_gpu documented as first option

Quick start with GPU:
  docker compose -f docker-compose.gpu.yml up --build

https://claude.ai/code/session_01WVDg7amsy1TTtxvpku7bcM
2026-06-13 15:08:41 +00:00
Outis 81d866efb8 Merge pull request #52 from outis1one/claude/peaceful-gauss-9tfiw0
Claude/peaceful gauss 9tfiw0
2026-06-11 22:59:50 -04:00
Claude 4ba295db37 Fix Fit to Frame: resize canvas to match output dimensions
The fitted image was processed and inserted correctly but the canvas
(config.WIDTH/HEIGHT) was never updated, so the result was clipped to
the original canvas size. Now wraps both new-layer and replace-layer
paths in Prepare_canvas_action + Update_config_action so the canvas
expands (or shrinks) to the target frame size automatically.

https://claude.ai/code/session_017wupXfpjuoSdAqVyak4fJf
2026-06-12 02:20:07 +00:00
Claude 0cf10398bc Fix: also save default_units_short when units toggled in dialogs
Keeps the info-bar unit symbol (px, ", cm, mm) in sync when the user
switches units via the in-dialog toggle rather than Tools > Settings.

https://claude.ai/code/session_017wupXfpjuoSdAqVyak4fJf
2026-06-12 02:13:34 +00:00
Claude f28d8e44b6 Add inches, crop-to-fill, and persistent units to Resize dialog
Resize dialog:
- Units selector (pixels / inches) at the top; switching updates the
  Width/Height placeholders and clears any partially entered values
- New "Crop to fill" checkbox: when both Width and Height are given,
  scales the image with cover-fit (fills target without letterboxing)
  then center-crops — subject looks the same at 5x7, 8x10, 11x14
- resize_layer/resize_gui now honour params.units instead of only
  reading the global default_units setting

Global units persistence:
- Switching units in either Resize or Canvas Size saves the choice to
  default_units so both dialogs open with the same unit next time

https://claude.ai/code/session_017wupXfpjuoSdAqVyak4fJf
2026-06-12 01:50:19 +00:00
Outis 6bd4bd40b9 Merge pull request #51 from outis1one/claude/peaceful-gauss-9tfiw0
Claude/peaceful gauss 9tfiw0
2026-06-11 21:37:39 -04:00
Claude 0bf7697916 Update package-lock.json after npm install
https://claude.ai/code/session_017wupXfpjuoSdAqVyak4fJf
2026-06-12 01:13:46 +00:00
Claude 35932743fc Add inches unit, print size presets, and resize-crop to Canvas Size dialog
- Units selector (pixels/inches) directly in the dialog; switching live-converts
  the width/height fields so you can type e.g. 5 / 7 without mental math
- Six print-size presets at 300 DPI added to the Resolution dropdown:
  5x7, 8x10, and 11x14 in both Portrait and Landscape orientations
- New "Resize & crop image" checkbox: when enabled, image layers are scaled
  with cover-fit (fills the target canvas, no letterboxing) and center-cropped
  so the subject stays proportionally the same across all three print sizes

https://claude.ai/code/session_017wupXfpjuoSdAqVyak4fJf
2026-06-12 01:13:13 +00:00
Outis 045bd0806f Merge pull request #50 from outis1one/claude/awesome-bohr-mks3co
Fix AI Edit tool events, add icon, move color swatch to toolbar bottom
2026-06-11 20:53:20 -04:00
Claude aebd24624a Fix AI Edit tool events, add icon, move color swatch to toolbar bottom
ai_edit.js:
- Extend Base_tools_class and add load() + default_events() so mouse
  events actually wire up (was the root cause of tool not working)
- Use get_mouse_info() for coordinate mapping instead of manual
  clientX/Y math — consistent with all other miniPaint tools
- Fix _mouseToImage() to use mouse.x/y (already in image coords)
  and correct display-scale for overlay brush rendering
- mousedown/mousemove/mouseup now guard on config.TOOL.name

ai_edit.svg: new icon (brush + sparkle star) for the left toolbar

layout.css: add .ai_edit:after CSS rule for the icon

main.js:
- Collapse right-panel Colors section by default (respects saved cookie
  so user preference persists)
- Mount compact foreground/background color swatches at the bottom of
  the left toolbar; click either square to toggle the full color picker
  open/closed; syncs live with config.COLOR every 250ms

https://claude.ai/code/session_01B58MaJCU1R6KwBDJCp8AfN
2026-06-12 00:42:53 +00:00
Outis 335b90e7aa Merge pull request #49 from outis1one/claude/awesome-bohr-mks3co
Fix startup crash: replace sklearn k-means with pure numpy implementa…
2026-06-11 20:15:18 -04:00
Claude 065495e665 Fix startup crash: replace sklearn k-means with pure numpy implementation
sklearn was not installed in the container, causing ModuleNotFoundError on
import of ai_tools.py and preventing the server from starting.

Replaced with a self-contained numpy k-means++ implementation:
- k-means++ seeding for better initial centers
- 20-iteration Lloyd's algorithm
- Same output: hex colors sorted by cluster frequency

No new dependencies required.

https://claude.ai/code/session_01B58MaJCU1R6KwBDJCp8AfN
2026-06-11 23:24:00 +00:00
Outis c07689fcd0 Merge pull request #48 from outis1one/claude/awesome-bohr-mks3co
Claude/awesome bohr mks3co
2026-06-11 18:49:19 -04:00
Claude 54be280b5b Enhance eyedropper with live Pantone matching tooltip
pick_color.js: on hover shows a floating tooltip with:
  - 40px color swatch of the sampled pixel
  - Hex (#RRGGBB), RGB, and HSL values
  - Nearest Pantone name and swatch from the database
  - ΔE value (CIE76 color distance in LAB space)
  - Quality badge: Excellent (<2) / Good (2-5) / Fair (5-10) / Poor (>10)
  - Warning note when ΔE > 10 (color cannot be faithfully printed as Pantone)
  Click copies hex to clipboard and sets as active color (existing behavior).

color_utils.js: hexToRgb, rgbToHsl, sRGB→XYZ→CIE LAB conversion (D65),
  CIE76 deltaE, nearestPantone() (scans all ~350 entries, returns best match).
  Pantone database is pre-converted to LAB at module load for fast scanning.

pantone_colors.js: ~350 representative PMS colors across reds, oranges,
  yellows, greens, teals, blues, purples, magentas, browns, grays, black/white.
  Hex approximations from open-source Pantone datasets (not official Pantone data).

https://claude.ai/code/session_01B58MaJCU1R6KwBDJCp8AfN
2026-06-11 01:52:23 +00:00
Claude d2273017fd Add Auto-Enhance, Color Palette, History Panel, Align, Text Presets
Auto-Enhance (Image menu):
  POST /api/enhance — gray-world white balance, CLAHE contrast on L channel,
  saturation boost ×1.15 in HSV, unsharp mask; all blended by strength slider
  Frontend: strength selector (25/50/75/100%), keep-original option

Extract Color Palette (Image menu):
  POST /api/extract-colors — k-means on 150×150 thumbnail, returns N dominant
  colors sorted by cluster size. Frontend: floating swatch panel, click=copy
  hex, shift+click=set as active color, toggle on/off.

History Panel (Edit menu, Ctrl+H):
  Pure frontend — reads app.State.action_history and action_history_index,
  renders clickable list of past actions (newest first), click any step to
  undo/redo to that point. Auto-refreshes every 800ms while open.

Align to Canvas (Layer menu):
  Floating toolbar with 7 alignment buttons: center H, center V, center both,
  align left/right/top/bottom edges. Uses Update_layer_action for undo support.

Add Text (Generate menu):
  6 styled presets (Heading, Subheading, Body, Caption, Quote, Bold Label)
  shown as live-rendered previews in the dialog. Click a preset to insert a
  text layer with the correct font/size/weight/color pre-applied.

https://claude.ai/code/session_01B58MaJCU1R6KwBDJCp8AfN
2026-06-11 01:41:20 +00:00
Outis 0844333238 Merge pull request #47 from outis1one/claude/great-brahmagupta-00oydt
Add TIFF (CMYK/Multilayer) and PDF (RGB/CMYK) export formats
2026-06-10 17:20:29 -04:00