chess-tutor / Dockerfile
github-actions[bot]
deploy prod from 06dbd16a01ddcfe02b2d936c681e3e4eaa9b141f
8e756fd
Raw
History Blame Contribute Delete
3.17 kB
# syntax=docker/dockerfile:1.4
# Chess Tutor web UI — Vite static build + Python API on port 8765.
#
# Runtime files staged explicitly (not whole docs/ or data/ trees):
# docs/playstyle_catalog*.yaml — coaching copy (3 YAML files only)
# data/models/.../playstyle_teacher.joblib
# data/models/.../opening_climber_stats.joblib
# data/inference/chesscom_lichess_rapid_linear.joblib
# data/web_artifacts/cohort/standard_600/*
# data/lichess-puzzles/... — copied when present locally (optional)
#
# Not included: playstyle_feature_lookup.json, research docs, cohort DB,
# playstyle_elo.joblib. Rust prebuilt is copied when present (amd64 speedup).
#
# Build:
# docker build -t chess-tutor-web .
# Run:
# docker run --rm -p 8765:8765 chess-tutor-web
FROM node:20-bookworm-slim AS frontend
WORKDIR /app/src/chess_tutor/web/frontend
COPY src/chess_tutor/web/frontend/package.json src/chess_tutor/web/frontend/package-lock.json ./
RUN npm ci
COPY src/chess_tutor/web/frontend/ ./
RUN npm run build
FROM python:3.12-slim-bookworm AS runtime
WORKDIR /app
RUN apt-get update \
&& apt-get install -y --no-install-recommends curl \
&& rm -rf /var/lib/apt/lists/*
COPY requirements-web.txt pyproject.toml ./
RUN printf '%s\n' '# Chess Tutor web image' > Initial-plan.md
COPY src ./src
COPY classical-eval-rs/prebuilt/ classical-eval-rs/prebuilt/
COPY docker/entrypoint.sh docker/stage-web-data.sh /tmp/docker/
COPY docs/playstyle_catalog.yaml \
docs/playstyle_catalog_extended_dimensions.yaml \
docs/playstyle_catalog_coaching_dimensions.yaml \
/tmp/stage/catalog/
COPY data/models/cohort/standard_600/playstyle_teacher.joblib \
data/models/cohort/standard_600/opening_climber_stats.joblib \
/tmp/stage/models/
COPY data/inference/chesscom_lichess_rapid_linear.joblib /tmp/stage/inference/
COPY data/web_artifacts/cohort/standard_600/ /tmp/stage/web_artifacts/
# Optional puzzle shard from local checkout (skipped when file is absent)
RUN --mount=type=bind,source=.,target=/ctx,readonly \
mkdir -p /tmp/stage/lichess-puzzles/data \
&& if [ -f /ctx/data/lichess-puzzles/data/train-00000-of-00003.parquet ]; then \
cp /ctx/data/lichess-puzzles/data/train-00000-of-00003.parquet /tmp/stage/lichess-puzzles/data/; \
fi
RUN chmod +x /tmp/docker/stage-web-data.sh /tmp/docker/entrypoint.sh \
&& /tmp/docker/stage-web-data.sh /tmp/stage /app \
&& mv /tmp/docker/entrypoint.sh /entrypoint.sh \
&& rm -rf /tmp/stage /tmp/docker
RUN pip install --no-cache-dir -U pip wheel \
&& pip install --no-cache-dir -r requirements-web.txt \
&& pip install --no-cache-dir -e . --no-deps \
&& pip install --no-cache-dir \
"numpy==2.4.4" \
"scipy>=1.14.1,<1.18" \
"scikit-learn>=1.5.0,<1.9"
COPY --from=frontend /app/src/chess_tutor/web/static ./src/chess_tutor/web/static
ENV HOST=0.0.0.0 \
PORT=8765 \
DOWNLOAD_PUZZLES=0 \
PYTHONUNBUFFERED=1
EXPOSE 8765
HEALTHCHECK --interval=30s --timeout=5s --start-period=120s --retries=3 \
CMD curl -fsS "http://127.0.0.1:8765/api/version" >/dev/null || exit 1
ENTRYPOINT ["/entrypoint.sh"]