Compare commits

..

No commits in common. "3064f62192ce7ebdb80daad081c5309ed23fccc0" and "27846f661ec717ec24c469bc97b5157b4daac29c" have entirely different histories.

5 changed files with 40 additions and 47 deletions

View File

@ -1,11 +1,10 @@
# BiRefNet background removal service — CUDA 12.6 inference image. # BiRefNet background removal service — CUDA 12.6 runtime image.
# torch's +cu126 wheels bundle their own CUDA/cuDNN, so no nvidia/cuda base is FROM nvidia/cuda:12.6.1-cudnn-runtime-ubuntu22.04
# needed; the GPU driver is injected by the nvidia container runtime at run time.
FROM python:3.12-slim
ENV PYTHONUNBUFFERED=1 \ ENV DEBIAN_FRONTEND=noninteractive \
PYTHONUNBUFFERED=1 \
UV_PYTHON_INSTALL_DIR=/opt/python \
UV_PROJECT_ENVIRONMENT=/app/.venv \ UV_PROJECT_ENVIRONMENT=/app/.venv \
UV_PYTHON_PREFERENCE=only-system \
UV_COMPILE_BYTECODE=1 \ UV_COMPILE_BYTECODE=1 \
UV_LINK_MODE=copy \ UV_LINK_MODE=copy \
HF_HOME=/app/hf_cache \ HF_HOME=/app/hf_cache \
@ -14,13 +13,18 @@ ENV PYTHONUNBUFFERED=1 \
# uv: fast, reproducible Python + dependency management. # uv: fast, reproducible Python + dependency management.
COPY --from=ghcr.io/astral-sh/uv:0.9 /uv /uvx /bin/ COPY --from=ghcr.io/astral-sh/uv:0.9 /uv /uvx /bin/
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app WORKDIR /app
# Install dependencies first so this layer is cached across code changes. # Install Python + dependencies first so this layer is cached across code changes.
# The BuildKit cache mount keeps the uv download cache warm across rebuilds. # The BuildKit cache mount keeps the uv download cache warm across rebuilds.
COPY pyproject.toml uv.lock ./ COPY pyproject.toml uv.lock ./
RUN --mount=type=cache,target=/root/.cache/uv \ RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --no-install-project --no-dev --frozen uv python install 3.12 \
&& uv sync --no-install-project --no-dev --frozen
# Application code. # Application code.
COPY src ./src COPY src ./src

View File

@ -1,32 +1,32 @@
# rmbg-as-a-service — slim CUDA inference image. # BiRefNet background removal service — installs the published package on the CUDA 12.6 runtime.
# torch's +cu126 wheels bundle their own CUDA/cuDNN, so no nvidia/cuda base is needed; # Same CUDA base family as the main ../Dockerfile, but installs rmbg-as-a-service from TestPyPI
# the GPU driver is injected by the nvidia container runtime at run time. # with a plain pip rather than building from the local source tree.
FROM nvidia/cuda:12.6.1-cudnn-runtime-ubuntu24.04
# ---- builder: install everything into an isolated venv ---- ENV DEBIAN_FRONTEND=noninteractive \
FROM python:3.12-slim AS builder PYTHONUNBUFFERED=1 \
PIP_BREAK_SYSTEM_PACKAGES=1 \
ENV PIP_DISABLE_PIP_VERSION_CHECK=1
RUN python -m venv /opt/venv
ENV PATH="/opt/venv/bin:${PATH}"
# rmbg-as-a-service from PyPI; CUDA torch from the PyTorch index (its +cu126 build
# outranks the plain wheel by local-version ordering).
RUN --mount=type=cache,target=/root/.cache/pip \
pip install \
--extra-index-url https://download.pytorch.org/whl/cu126 \
rmbg-as-a-service==0.0.3 hf-transfer
# ---- runtime: just Python + the prepared venv ----
FROM python:3.12-slim
ENV PYTHONUNBUFFERED=1 \
HF_HOME=/app/hf_cache \ HF_HOME=/app/hf_cache \
HF_HUB_ENABLE_HF_TRANSFER=1 \ HF_HUB_ENABLE_HF_TRANSFER=1 \
PORT=8000 \ PORT=8000
PATH="/opt/venv/bin:${PATH}"
COPY --from=builder /opt/venv /opt/venv # Ubuntu 24.04 ships Python 3.12 (the project requires >=3.12).
RUN apt-get update \
&& apt-get install -y --no-install-recommends python3 python3-pip ca-certificates \
&& rm -rf /var/lib/apt/lists/*
# Fetch only the rmbg-as-a-service wheel from TestPyPI (--no-deps), so TestPyPI never takes
# part in dependency resolution -- otherwise junk squatted packages there (e.g. "FASTAPI")
# outrank the real ones. Then install it with real PyPI as the index, CUDA torch from the
# PyTorch index (its +cu126 build outranks the plain wheel by local-version ordering).
RUN --mount=type=cache,target=/root/.cache/pip \
pip download --no-deps --dest /tmp/pkg \
--index-url https://test.pypi.org/simple/ \
"rmbg-as-a-service==0.0.3" \
&& pip install \
--extra-index-url https://download.pytorch.org/whl/cu126 \
/tmp/pkg/*.whl hf-transfer \
&& rm -rf /tmp/pkg
EXPOSE 8000 EXPOSE 8000
CMD ["rmbg-as-a-service"] CMD ["rmbg-as-a-service"]

View File

@ -43,7 +43,7 @@ test: ## Send INPUT to the running service, save OUTPUT
$(PYTHON) ../scripts/client.py --url http://localhost:$(PORT) \ $(PYTHON) ../scripts/client.py --url http://localhost:$(PORT) \
--input $(INPUT) --output $(OUTPUT) --background $(BG) --input $(INPUT) --output $(OUTPUT) --background $(BG)
push: build ## Push mindthemath/rmbg:$(TAG) to Docker Hub (needs docker login) push: ## Push mindthemath/rmbg:$(TAG) to Docker Hub (needs docker login)
docker push $(IMAGE):$(TAG) docker push $(IMAGE):$(TAG)
release: build push ## Build then push mindthemath/rmbg:$(TAG) release: build push ## Build then push mindthemath/rmbg:$(TAG)

View File

@ -25,7 +25,6 @@
<input id="file" type="file" accept="image/*" /> <input id="file" type="file" accept="image/*" />
<div class="upload-text">&#9650; DROP IMAGE</div> <div class="upload-text">&#9650; DROP IMAGE</div>
<div class="upload-hint" id="fname">NO FILE SELECTED</div> <div class="upload-hint" id="fname">NO FILE SELECTED</div>
<div class="upload-stats" id="fstats"></div>
<img class="preview-thumb" id="thumb" alt="" hidden /> <img class="preview-thumb" id="thumb" alt="" hidden />
</div> </div>
</section> </section>
@ -176,7 +175,6 @@ const sidebarToggle = $('sidebarToggle');
const drop = $('drop'); const drop = $('drop');
const fileInput = $('file'); const fileInput = $('file');
const fname = $('fname'); const fname = $('fname');
const fstats = $('fstats');
const thumb = $('thumb'); const thumb = $('thumb');
const go = $('go'); const go = $('go');
const dl = $('dl'); const dl = $('dl');
@ -283,13 +281,12 @@ function pickFile(file) {
selectedFile = file; selectedFile = file;
const url = URL.createObjectURL(file); const url = URL.createObjectURL(file);
const kb = Math.round(file.size / 1024); const kb = Math.round(file.size / 1024);
fname.textContent = file.name; fname.textContent = file.name + ' · ' + kb + ' KB';
fstats.textContent = kb + ' KB';
thumb.src = url; thumb.src = url;
thumb.hidden = false; thumb.hidden = false;
drop.classList.add('has-file'); drop.classList.add('has-file');
srcImg.onload = () => { srcImg.onload = () => {
fstats.textContent = fname.textContent = file.name + ' · ' +
srcImg.naturalWidth + '×' + srcImg.naturalHeight + ' PX · ' + kb + ' KB'; srcImg.naturalWidth + '×' + srcImg.naturalHeight + ' PX · ' + kb + ' KB';
}; };
srcImg.src = url; srcImg.src = url;
@ -312,7 +309,6 @@ reset.addEventListener('click', () => {
selectedFile = null; selectedFile = null;
fileInput.value = ''; fileInput.value = '';
fname.textContent = 'NO FILE SELECTED'; fname.textContent = 'NO FILE SELECTED';
fstats.textContent = '';
thumb.removeAttribute('src'); thumb.removeAttribute('src');
thumb.hidden = true; thumb.hidden = true;
drop.classList.remove('has-file'); drop.classList.remove('has-file');

View File

@ -928,13 +928,6 @@ select option {
background-color: #000000; background-color: #000000;
} }
/* px / KB stats, on their own line below the filename */
.upload-stats {
color: #5a7a5a;
font-size: 11px;
margin-top: 4px;
}
/* upload box thumbnail state */ /* upload box thumbnail state */
.upload-box.has-file { .upload-box.has-file {
border-color: #7aa87a; border-color: #7aa87a;