The mkdir -p preflight check only verified that data/models and
data/hf_cache could be created, which succeeds vacuously on a directory
that already exists — exactly the case when Docker created ./data as
root on a prior run. Confirmed in practice: U2Net's download reached the
network fine but failed writing the file with Permission denied. Now
test actual writability and point at the one-time fix (chown ./data back
to the calling user) instead of suggesting sudo re-runs that would leave
the ownership problem in place permanently.
Also handle pip's PEP 668 "externally-managed-environment" error
(Debian/Ubuntu 12+) when installing huggingface_hub, retrying with
--break-system-packages — safe here since --user already keeps the
install out of apt-managed system site-packages.
download_sam_model.py crashed with an uncaught PermissionError when
data/models/ is root-owned (common after a prior Docker run) and a
non-root host user tries to recreate the convenience sam_model.pth
symlink — observed in the wild, and it aborted the whole prefetch run
before U2Net/BEN2/BiRefNet-HR were ever attempted. Worse, the same
unguarded symlink call sat inside the post-download try/except, so a
successful download could get deleted just because the symlink step
failed afterward. Wrapped symlink creation in a shared helper that
warns and continues instead of raising — the real model file already
satisfies entrypoint.sh's checks regardless of the symlink.
prefetch-models.sh now treats SAM, U2Net, and the HuggingFace models as
independent steps (one failing no longer aborts the rest) and prints a
summary of which steps failed, so a single run gives full diagnostic
signal instead of stopping at the first error.
Lets SAM, U2Net, BEN2, and BiRefNet-HR (optionally SDXL via --sdxl) be
downloaded outside Docker into ./data/, which is already bind-mounted
into the GPU container — so a blocked container network no longer blocks
first-run setup. Reuses the existing dual-mode download_sam_model.py and
download_u2net_model.py as-is. For the HuggingFace Hub models, sets
HF_HOME (rather than --cache-dir) so the host-side cache layout matches
the container's default ~/.cache/huggingface resolution exactly, avoiding
a path-nesting mismatch between the two.
Wired into install-local-gpu.sh's completion banner and
bring-up-local-gpu.sh's header, and referenced from the relevant README
troubleshooting sections and the hf_cache bind-mount comment in
docker-compose.gpu.yml.