# Production image: builds the React frontend, then serves it and the API # from one uvicorn process. Also what the Hugging Face Space builds (see # deploy/push_space.py). # # Everything the app downloads is baked in at build time: the model files, # card stats, and prices. The model is pinned to one Hub commit # (MODEL_REVISION below), and the running container never changes it # (MTG_MODEL_UPDATE=0), so a deploy is reproducible. To ship a new model # release, bump MODEL_REVISION in a commit (see README, "Updating the # model"); rolling back is reverting that commit. Prices still refresh in # the background once they're a day old. # # docker build -t mtg-deck-completion-web . # docker run -p 8000:8000 mtg-deck-completion-web FROM node:22-slim AS web WORKDIR /web COPY web/package.json web/package-lock.json ./ RUN npm ci COPY web/ ./ RUN npm run build FROM python:3.14-slim ENV PIP_NO_CACHE_DIR=1 PYTHONUNBUFFERED=1 # CPU-only torch wheel: the default one bundles CUDA and is several GB larger. RUN pip install torch==2.14.0 --index-url https://download.pytorch.org/whl/cpu COPY requirements-server.txt ./ RUN pip install -r requirements-server.txt # Spaces runs the container as uid 1000, and the app writes to data/ (price # refreshes), so the app directory belongs to that user. RUN useradd -m -u 1000 user && mkdir /app && chown user:user /app USER user ENV HOME=/home/user WORKDIR /app COPY --chown=user scryfall_bulk.py ./ COPY --chown=user tokenizer/ tokenizer/ COPY --chown=user training/ training/ COPY --chown=user server/ server/ # The model release this image serves: a commit sha (or tag) of the Hub repo # nsaroiu/mtg-deck-completion. The selfcheck loads it and builds a deck, so # a release this code can't load fails the build, not the running app. The # download's staging copy (data/.model-snapshot) is only needed for later # updates, which this image never does, so it's dropped in the same layer. ARG MODEL_REVISION=52756aa56863c6ce5a9a40325041034667bce2c4 RUN MTG_MODEL_REVISION=$MODEL_REVISION python -m server.model_files \ && rm -rf data/.model-snapshot \ && python -m server.selfcheck RUN python -m server.card_stats && python -m server.card_prices COPY --chown=user --from=web /web/dist web/dist # Torch sizes its thread pool from the host's cores, not the container's # share; match the vCPUs actually available (2 on a free Space). ENV MTG_MODEL_UPDATE=0 MTG_API_DOCS=0 OMP_NUM_THREADS=2 EXPOSE 8000 CMD ["uvicorn", "server.app:app", "--host", "0.0.0.0", "--port", "8000"]