img2threejs / Dockerfile
Mike0021's picture
Deploy verified img2threejs Docker Space
39ff632 verified
Raw
History Blame Contribute Delete
3.66 kB
# syntax=docker/dockerfile:1
# img2threejs β€” production Dockerfile for a Hugging Face Docker Space.
#
# Build stages:
# 1. fixture β€” regenerate the test fixture factory through the real
# vendored pipeline (strict gate -> explicit unreviewed
# hosted-preview manifest -> generation). A broken forge
# copy fails here.
# 2. nodesmoke β€” npm ci (three + esbuild), bundle the fixture exactly as
# the runtime does, and execute it headlessly in node
# (scene-graph smoke: Group, meshes, finite bbox,
# sculptRuntime). A non-executing factory fails the build.
# 3. runtime β€” python:3.12-slim, non-root UID 1000, tini init,
# uvicorn on 0.0.0.0:7860, /health HEALTHCHECK.
# (esbuild is a statically-linked native binary, so the
# runtime needs no node; node exists only in stage 2.)
# ---------------------------------------------------------------------------
FROM python:3.12-slim-bookworm AS fixture
WORKDIR /build
COPY forge/ forge/
COPY app/__init__.py app/__init__.py
COPY app/forge_bridge.py app/forge_bridge.py
COPY scripts/build_fixture_factory.py scripts/build_fixture_factory.py
COPY tests/fixtures/canned_spec.json tests/fixtures/canned_spec.json
RUN python3 scripts/build_fixture_factory.py /build/factory_fixture.ts
# ---------------------------------------------------------------------------
FROM node:22-bookworm-slim AS nodesmoke
WORKDIR /build
COPY package.json package-lock.json ./
RUN npm ci --omit=dev --no-audit --no-fund && npm cache clean --force
COPY --from=fixture /build/factory_fixture.ts /build/factory.ts
COPY app/static/viewer-core.js app/static/viewer-core.js
COPY scripts/node_smoke.mjs scripts/node_smoke.mjs
RUN set -e; \
factory_export=$(grep -oE 'export function create[A-Za-z0-9]+Model' factory.ts | head -1 | awk '{print $3}'); \
pascal=$(echo "$factory_export" | sed -E 's/^create//; s/Model$//'); \
printf 'export { %s as makeModel, create%sLookDevLights as makeLights } from "./factory.ts";\nexport { mountViewer } from "%s";\n' \
"$factory_export" "$pascal" "/build/app/static/viewer-core.js" > entry.js; \
node_modules/.bin/esbuild entry.js \
--bundle --format=esm --target=es2022 --minify --outfile=model.bundle.js; \
node scripts/node_smoke.mjs /build/model.bundle.js
# ---------------------------------------------------------------------------
FROM python:3.12-slim-bookworm AS runtime
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PIP_NO_CACHE_DIR=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1 \
HOME=/home/user
RUN apt-get update \
&& apt-get install -y --no-install-recommends tini curl ca-certificates \
&& rm -rf /var/lib/apt/lists/* \
&& useradd -m -u 1000 user
USER user
WORKDIR /home/user/app
COPY --chown=user requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY --chown=user package.json package-lock.json ./
COPY --from=nodesmoke --chown=user /build/node_modules ./node_modules
# Runtime source allowlist. Build/test/deploy helpers, fixtures, local
# verification evidence and workspace state never enter the final image.
COPY --chown=user:user app/ ./app/
COPY --chown=user:user forge/ ./forge/
COPY --chown=user:user LICENSE ./LICENSE
EXPOSE 7860
# Local-docker convenience only; the HF runner probes app_port over HTTP.
HEALTHCHECK --interval=30s --timeout=5s --start-period=60s --retries=3 \
CMD curl -fsS http://localhost:7860/health || exit 1
ENTRYPOINT ["/usr/bin/tini", "--"]
CMD ["python", "-m", "app.main"]