Support remote SAM3 inference through a private Metal worker

This commit is contained in:
Joshua Warren
2026-10-08 11:47:59 -05:00
parent b8df5f472c
commit 0613f925de
10 changed files with 350 additions and 19 deletions
+36 -1
View File
@@ -42,6 +42,39 @@ The result is stored with the mask: the model's 288 × 288 mask logits over the
need the model, so masks survive moving the library to a machine without it, and the web build
renders them. Editing the photo's look later does not recompute a mask (click again to update).
## Remote Metal inference
Native builds with `sam` can keep the editor, RAW files, library, and exports local while
a Mac runs SAM 3. Build both ends from the same revision. On the Mac, install the model
as described below, then run:
```sh
cargo build --release --locked -p lightcraft-segment --bin lightcraft-sam3-worker
target/release/lightcraft-sam3-worker "$HOME/Library/Application Support/LightCraft/models/sam3" 127.0.0.1:8793
```
On the editing computer, start an SSH tunnel in one terminal and LightCraft in another:
```sh
ssh -N -T -o ExitOnForwardFailure=yes -L 127.0.0.1:8793:127.0.0.1:8793 user@your-mac
LIGHTCRAFT_SAM3_REMOTE=127.0.0.1:8793 lightcraft
```
Object clicks, Describe prompts, and detail refinement use the remote worker. Only the
rendered model input (long edge at most 1008 pixels) and prompts cross the tunnel. The
worker caches the current photo; detail crops do not replace that cache. Returned masks
stay in the local library, so later adjustments and exports work without the connection.
The worker requires Metal and accepts one editing connection at a time. It loads weights
on demand and releases them when the client disconnects or remains idle for ten minutes.
Both endpoints require loopback addresses: SSH provides authentication and encryption.
The listener has no independent authentication; do not expose it through a public proxy.
No local weights are required in remote mode. An unavailable worker produces an explicit
error, not a silent CPU fallback. Restore the tunnel and retry. Unset
`LIGHTCRAFT_SAM3_REMOTE` to use the local model again. This offloads segmentation only,
not RAW development, denoising, or upscaling. The model licence below still applies.
## Getting the model
### In the app (recommended)
@@ -148,10 +181,12 @@ Therefore:
| `mask.objectPoint` | `{x, y, exclude?: bool, id?}` | one click on the selected mask's Object selection (≤ 64 clicks) |
| `mask.refineDetail` | `{id?, component?}` | the zoomed-in detail pass → `{started}` |
| `segment.prepare` | `{}` | load the model and analyze the active photo → `{busy}` |
| `segment.model.status` | `{}` | `{available, installed, dir, loaded, busy, analyzing, sizeBytes, license, licenseUrl, mirrors, download}` |
| `segment.model.status` | `{}` | `{available, installed, remote, dir, loaded, busy, analyzing, sizeBytes, license, licenseUrl, mirrors, download}` |
| `segment.model.download` | `{acknowledged: true}` | start the download in the background → `{started}` |
| `segment.model.cancel` | `{}` | stop it (it resumes next time) → `{cancelled}` |
`remote` reports the configured endpoint, not its health. `installed` describes local weights only.
Coordinates are normalized to the uncropped, oriented photo, like every mask shape. `seg` passes
a stored segmentation (as `mask.list` / the develop settings hold it): the mask is made without
the model. Without the model, the AI kinds fail with an error starting "The SAM 3 model is not
+3
View File
@@ -135,6 +135,9 @@
lost everything at quit; a temporary session shows a banner the whole time and never writes to your library.
### Editing
- Optional remote SAM 3: keep the native editor local and run Object, Describe, and detail
inference on a Mac through SSH. Saved masks still render and export offline.
See [remote Metal inference](ai-masks.md#remote-metal-inference).
- AI masks with SAM 3 (Object and Describe in the Masking panel): click an object to select it (⌥-click leaves a
part out), or type what to select ("sky", "the red car", "car, road"); both combine with other masks, have an
Edge setting, and get a sharper zoomed-in pass in the background. The model runs inside LightCraft in pure Rust