Commit Graph
165 Commits
Author SHA1 Message Date
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
Outis 723845ead4 Merge pull request #46 from outis1one/claude/awesome-bohr-mks3co
Claude/awesome bohr mks3co
2026-06-10 17:19:57 -04:00
Claude 78341297a2 Add TIFF (CMYK/Multilayer) and PDF (RGB/CMYK) export formats
- tiff-writer.js: pure-JS multipage TIFF encoder with RGBA and CMYK
  color modes; RGB→CMYK conversion; one IFD per layer for multilayer
- pdf-writer.js: pure-JS PDF-1.4 writer; RGB pages use browser JPEG
  encoding (DCTDecode); CMYK pages embed raw DeviceCMYK pixel data;
  multipage support (one page per visible layer)
- save.js: adds TIFF (CMYK), TIFF (Multilayer), PDF (RGB), PDF (CMYK)
  to the export dialog; CMYK types bypass the separated-layers loop and
  composite with a white background before color conversion
2026-06-10 19:26:14 +00:00
Claude 3746c02d44 Add SAM click-to-select with brush refinement in AI Edit tool
Backend:
- sam_service.py: auto-downloads SAM ViT-B (~375 MB) on first use with
  progress tracking; loads model to CUDA/MPS/CPU; predict_points() takes
  multi-point prompts (include/exclude labels) and returns best mask
- POST /api/segment/point: SAM point-prompt endpoint; returns mask PNG
- GET  /api/segment/install-status: poll download progress
- POST /api/segment/install: explicit trigger (also auto on first click)
- main.py: pre-download SAM on startup alongside NCNN

Frontend (ai_edit.js):
- Click mode (default): click object → SAM generates mask instantly
  Alt+click → subtract (deselect over-selected area)
  Multiple clicks accumulate for multi-object or refinement
- Brush + / Brush − modes: paint to add or erase from SAM mask by hand
- If SAM model is still downloading on first click: inline progress bar,
  user retries the click when done
- Unified action bar: Erase | Replace (inline prompt) | Upscale | Expand | Clear
- All modes share the same mask canvas; SAM and brush are fully composited

https://claude.ai/code/session_01B58MaJCU1R6KwBDJCp8AfN
2026-06-10 18:18:33 +00:00
Claude 1132656370 Replace scattered AI tools with single unified AI Edit tool
Before: 4 separate tools (ai_inpaint, ai_lama_erase, ai_smart_inpaint,
ai_replace_selection) with no clear relationship, buried in toolbar.

After: one "AI Edit" brush tool. Paint mask → floating action bar appears:
  Erase    — LaMa removes masked content, no prompt needed
  Replace  — inline prompt reveals in-place ("make her smile" / "replace
             with a wolf") → calls /api/inpaint/remote
  Upscale  — delegates to existing upscale module
  Expand   — delegates to existing outpaint module
  Clear    — wipe mask and start over

Brush size controlled by tool attributes (5–200px).
Red overlay gives immediate visual feedback while painting.
Floating panel appears as soon as first brush stroke is made.

https://claude.ai/code/session_01B58MaJCU1R6KwBDJCp8AfN
2026-06-10 16:42:10 +00:00
Outis a187b8e0f2 Merge pull request #45 from outis1one/claude/awesome-bohr-mks3co
Skip NCNN install on headless/no-Vulkan machines
2026-06-10 12:05:42 -04:00
Claude 717f482987 Skip NCNN install on headless/no-Vulkan machines
- Add _vulkan_available(): checks /dev/dri/renderD* on Linux, assumes
  true on macOS/Windows; set REALESRGAN_NCNN=force to override
- Add _test_ncnn_binary(): test-runs the binary after install and checks
  stderr for "no vulkan" — marks skipped if Vulkan init fails at runtime
- ensure_ncnn_installed() now returns early with state=skipped when no
  Vulkan detected, avoiding a wasted ~30MB download on CPU-only servers
- Recommend PyTorch CPU when available on headless (AI quality, slow but
  works); Lanczos as final fallback
- Frontend: handle state=skipped immediately (no polling needed), show
  brief informational toast; show "Headless server" note in dialog

https://claude.ai/code/session_01B58MaJCU1R6KwBDJCp8AfN
2026-06-10 00:50:09 +00:00
Outis 3085e5688b Merge pull request #44 from outis1one/claude/awesome-bohr-mks3co
Claude/awesome bohr mks3co
2026-06-09 14:39:48 -04:00