From 6b1703240f9e5427d0c08588a3e331f234f7cf59 Mon Sep 17 00:00:00 2001 From: anandhu-eng Date: Tue, 15 Sep 2026 17:19:07 +0530 Subject: [PATCH] feat(docker): provision ROUGE scorer deps and corpora in dev image Install the `rouge` extra in both uv sync layers and prefetch the scorer's runtime data, so a pushed image can run `eval_method: "rouge"` with no network - matching how PROVISION_DSR1 / PROVISION_VBENCH already make the DeepSeek-R1 and VBench evaluators self-contained. The extra is declared explicitly rather than inherited from `test`, since ROUGE is a runtime capability of the published image and should not depend on a test-only extra to supply it. Installing the packages is not enough on its own: nltk.sent_tokenize needs the punkt/punkt_tab corpora and evaluate.load("rouge") fetches its metric script from the HF Hub. A new PROVISION_ROUGE=1 block prefetches both and then asserts the corpora resolve, so a silent download failure fails the build instead of the benchmark. Both caches land in their default per-user locations (~/nltk_data, ~/.cache/huggingface). Deliberately not redirected to /opt via NLTK_DATA/HF_HOME: HF_HOME is global at runtime, so repointing it would orphan what the DSR1/VBench stages already cached under the default path. The block sits after VBench and before the LABEL layer, so editing it rebuilds neither the heavy evaluator stages nor anything but image config. Requires the `rouge` extra from #506 - merge that first, or `uv sync --extra rouge` fails here. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/Dockerfile.dev | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/scripts/Dockerfile.dev b/scripts/Dockerfile.dev index f008a4b29..32db12721 100644 --- a/scripts/Dockerfile.dev +++ b/scripts/Dockerfile.dev @@ -7,6 +7,10 @@ # evaluator, PROVISION_DSR1=1). It lives under examples/, not src/, so it is COPYed # in explicitly. To skip it (leaner image, no wan22 accuracy), build with PROVISION_VBENCH=0: # docker build -f scripts/Dockerfile.dev --build-arg PROVISION_VBENCH=0 --build-arg USER_ID=$(id -u) --build-arg GROUP_ID=$(id -g) -t inference-endpoint-dev . +# +# The ROUGE scorer's corpora + metric script are likewise prefetched by default +# (PROVISION_ROUGE=1) so `eval_method: "rouge"` needs no runtime network; build with +# PROVISION_ROUGE=0 to skip. FROM python:3.12.11-slim @@ -52,11 +56,11 @@ ENV PATH="/opt/venv/bin:/home/appuser/.local/bin:$PATH" \ VBENCH_CACHE_DIR=/opt/vbench_cache # Install dependencies first (cached unless pyproject.toml/uv.lock change) -RUN uv sync --frozen --no-install-project --extra dev --extra test +RUN uv sync --frozen --no-install-project --extra dev --extra test --extra rouge # Copy source and install project COPY --chown=${USER_ID}:${GROUP_ID} src/ ./src/ -RUN uv sync --frozen --extra dev --extra test +RUN uv sync --frozen --extra dev --extra test --extra rouge # Provision the isolated DeepSeek-R1 accuracy evaluator. Gated by PROVISION_DSR1 @@ -103,6 +107,28 @@ RUN if [ "${PROVISION_VBENCH}" = "1" ]; then \ echo "PROVISION_VBENCH=${PROVISION_VBENCH}: skipping VBench provisioning" ; \ fi +# ROUGE scorer runtime data. The `rouge` extra above installs nltk/evaluate/rouge_score, +# but neither is self-contained: nltk.sent_tokenize needs the punkt/punkt_tab corpora and +# evaluate.load("rouge") fetches its metric script from the HF Hub. Without this block the +# image needs network at evaluation time for `eval_method: "rouge"` - the same gap +# prefetch_weights.py closes for VBench. +# +# Both land in their default per-user caches (~/nltk_data and ~/.cache/huggingface, i.e. +# appuser's home) and are baked into the image layer. Deliberately NOT redirected to /opt +# via NLTK_DATA/HF_HOME: HF_HOME is a global runtime env var, and pointing it elsewhere +# would orphan whatever the DSR1/VBench stages above already cached under the default path. +# The final python -c asserts the corpora actually resolve, so a silent download failure +# fails the build here rather than at evaluation time. +# PROVISION_ROUGE=0 skips this block (leaner image, no offline rouge accuracy). +ARG PROVISION_ROUGE=1 +RUN if [ "${PROVISION_ROUGE}" = "1" ]; then \ + python -c "import nltk; nltk.download('punkt'); nltk.download('punkt_tab')" && \ + python -c "import evaluate; evaluate.load('rouge'); print('rouge metric cached')" && \ + python -c "import nltk; assert nltk.sent_tokenize('One. Two.') == ['One.', 'Two.']; print('punkt corpora ok')" ; \ + else \ + echo "PROVISION_ROUGE=${PROVISION_ROUGE}: skipping ROUGE corpora/metric prefetch" ; \ + fi + # OCI image metadata so `docker inspect` self-identifies this image (the endpoints benchmark # client, distinct from the lcb-service evaluator image). Declared last so a wording change # only rebuilds this tiny config layer, not the apt/uv/DSR1/VBench stages above.