Spaces:
Paused
Paused
| # Fossil Agent β ONE Space, GPU. Everything in-process: SAM3, the agent, Chainlit. | |
| # | |
| # ============================================================================ | |
| # WHY THE BUILD USED TO TIME OUT | |
| # ============================================================================ | |
| # | |
| # The old Dockerfile started from python:3.11-slim and ran `pip install torch`: | |
| # | |
| # * pip's resolver could not settle this dependency graph. MEASURED, on the exact | |
| # requirements below: pip did not finish in 280s (I killed it); uv did it in | |
| # under 1s. chainlit + google-adk + litellm + transformers have >1,600 published | |
| # versions between them and pip backtracks through them. THIS was the timeout β | |
| # the resolver, before a single byte of torch was downloaded. | |
| # | |
| # * ...and then it downloaded 3.1 GB anyway: torch (527 MB) plus the four separate | |
| # nvidia-* wheels it declares (2,589 MB). | |
| # | |
| # Fixed by: a base image that already HAS torch+CUDA (a cached layer pull, not a pip | |
| # download), uv instead of pip, and no `accelerate` β it hard-requires torch and was | |
| # dragging all 3.1 GB back in through the side door. Plain `transformers` does NOT | |
| # require torch; every torch entry in its metadata is an `extra`. | |
| # | |
| # ============================================================================ | |
| # THE ROOT/USER SPLIT β the thing that just bit us | |
| # ============================================================================ | |
| # | |
| # pytorch/pytorch keeps its Python in a ROOT-OWNED conda env at /opt/conda. HF Spaces | |
| # want the app to RUN as uid 1000. Those are two different phases, and collapsing them | |
| # is what produced: | |
| # | |
| # USER user | |
| # RUN uv pip install --system ... | |
| # -> error: failed to remove .../jinja2-3.1.4.dist-info/INSTALLER: Permission denied | |
| # | |
| # uv has to overwrite packages conda already put there (jinja2, filelock, sympy...), | |
| # and a non-root user cannot. So: install as root, then drop to `user` for runtime | |
| # only. The container still runs unprivileged, which is the part that matters. | |
| # ============================================================================ | |
| # Different CUDA? Pick another tag: https://hub.docker.com/r/pytorch/pytorch/tags | |
| FROM pytorch/pytorch:2.5.1-cuda12.1-cudnn9-runtime | |
| # --------------------------------------------------------------------------- | |
| # BUILD PHASE β as root. | |
| # --------------------------------------------------------------------------- | |
| # opencv-python-headless dlopens these at import even though it draws nothing. | |
| RUN apt-get update && apt-get install -y --no-install-recommends \ | |
| libgl1 libglib2.0-0 && \ | |
| rm -rf /var/lib/apt/lists/* | |
| WORKDIR /app | |
| # Dependencies before source, so this layer caches across code-only pushes. | |
| COPY requirements.txt . | |
| # uv, not pip. See above: this is the fix, not an optimisation. | |
| # --system installs into the image's conda Python β which is where torch already is. | |
| RUN pip install --no-cache-dir uv && \ | |
| uv pip install --system --no-cache -r requirements.txt | |
| COPY . . | |
| # --------------------------------------------------------------------------- | |
| # RUNTIME PHASE β unprivileged. | |
| # --------------------------------------------------------------------------- | |
| # HF Spaces run the container as uid 1000. Everything the app writes at runtime β | |
| # artefacts, uploads, the HF weight cache β must be writable by that user. | |
| RUN useradd -m -u 1000 user && \ | |
| mkdir -p /app/output /home/user/work /home/user/.cache/huggingface && \ | |
| chown -R user:user /app /home/user | |
| USER user | |
| ENV HOME=/home/user \ | |
| PYTHONUNBUFFERED=1 \ | |
| FOSSIL_WORK_DIR=/home/user/work \ | |
| HF_HOME=/home/user/.cache/huggingface \ | |
| FOSSIL_BG_BACKEND=hf \ | |
| FOSSIL_BG_STRICT=1 | |
| # SAM3's weights (~3 GB) are fetched on FIRST REQUEST, not at build time β so a cold | |
| # Space's first segmentation takes minutes and every one after takes seconds. Don't | |
| # mistake a cold start for a hang. With persistent storage attached, set HF_HOME=/data | |
| # so they survive a restart instead of re-downloading on every cold boot. | |
| # | |
| # FOSSIL_BG_STRICT=1: RMBG-2.0 only. Without it, a bad HF_TOKEN silently falls back to | |
| # GrabCut β a worse but *plausible* matte, so the run still looks fine and the masks | |
| # are merely a bit off. Nobody notices until a mesh has been built on top of them. | |
| EXPOSE 7860 | |
| CMD | |