# syntax=docker/dockerfile:1 # --------------------------------------------------------------------------- # Dockerfile for a Hugging Face "Docker Space" that serves a GGUF model # (empero-ai/Qwythos-9B-Claude-Mythos-5-1M-GGUF) through llama-cpp-python # with a streaming Gradio chat UI. # # Design goals: # - Small final image -> multi-stage build. All compilers / build tools # (cmake, ninja, gcc) live ONLY in the builder stage. The runtime stage # just installs the pre-built wheel. # - Reliable build -> pin apt/pip behaviour (no interactive prompts, # no cache dirs left behind, explicit CMake flags for llama.cpp so the # build never silently falls back to something incompatible with the # CPU the Space actually runs on). # - CPU-only -> no CUDA/ROCm toolkits anywhere in the image. # --------------------------------------------------------------------------- # =========================== 1. Builder stage =============================== FROM python:3.11-slim AS builder # ca-certificates is needed either way (HTTPS to PyPI / abetlen's wheel # index / the HF Hub later). The heavy compiler toolchain (build-essential, # cmake, ninja, git) is installed ONLY in the fallback branch below, so the # common case pays no apt cost either. RUN apt-get update && apt-get install -y --no-install-recommends \ ca-certificates \ && rm -rf /var/lib/apt/lists/* WORKDIR /build RUN pip install --no-cache-dir --upgrade pip wheel setuptools # --------------------------------------------------------------------------- # Fast path vs. fallback path for llama-cpp-python. # # The project's maintainer publishes prebuilt CPU-only wheels at a custom # index (https://abetlen.github.io/llama-cpp-python/whl/cpu). When one # matches our Python ABI (cp311) / platform (manylinux x86_64), this avoids # a from-source compile that otherwise takes 15-30+ minutes on a free HF # Spaces builder. `--only-binary=:all:` makes pip fail fast instead of # silently falling back to a slow sdist build if no wheel matches, so we # can detect the miss and switch strategies ourselves. # # If no prebuilt wheel is available (e.g. maintainer hasn't published one # for the current llama-cpp-python release / Python version yet), we fall # back to the original from-source build: install compilers, then build # with explicit CMake flags tuned for broad CPU compatibility: # - GGML_NATIVE=OFF : don't auto-detect the *build* machine's CPU flags. # The image is built on different hardware than it # runs on, so "native" builds can crash with # "illegal instruction" on the actual Space runner. # - GGML_AVX2/FMA/F16C: supported by virtually all modern x86_64 cloud # CPUs (including HF's free-tier runners), giving # good performance without AVX-512-only risk. # - CMAKE_BUILD_PARALLEL_LEVEL=nproc: the previous Dockerfile left this # unset, which on some setups serializes the C++ # compile across hundreds of translation units — # a big, avoidable chunk of that 20+ minute build. # - CMAKE_BUILD_TYPE=Release + Ninja: faster/smaller than default Make. RUN set -eux; \ if pip wheel --no-cache-dir --only-binary=:all: --wheel-dir /wheels \ --extra-index-url https://abetlen.github.io/llama-cpp-python/whl/cpu \ "llama-cpp-python"; \ then \ echo "==> Installed prebuilt CPU wheel for llama-cpp-python (fast path)"; \ else \ echo "==> No prebuilt wheel available; building llama-cpp-python from source"; \ apt-get update && apt-get install -y --no-install-recommends \ build-essential cmake ninja-build git \ && rm -rf /var/lib/apt/lists/*; \ export CMAKE_ARGS="-DGGML_NATIVE=OFF -DGGML_AVX2=ON -DGGML_FMA=ON -DGGML_F16C=ON -DCMAKE_BUILD_TYPE=Release -GNinja"; \ export FORCE_CMAKE=1; \ # Cap parallel compile jobs at 4: the free HF Spaces Docker builder # may report more cores than it has RAM to back, and a runaway # `-j$(nproc)` C++ compile is a classic way to get the build OOM-killed. BUILD_CORES="$(nproc)"; \ if [ "$BUILD_CORES" -gt 4 ]; then BUILD_CORES=4; fi; \ export CMAKE_BUILD_PARALLEL_LEVEL="$BUILD_CORES"; \ pip wheel --no-cache-dir --wheel-dir /wheels "llama-cpp-python"; \ fi # ============================ 2. Runtime stage ================================ FROM python:3.11-slim AS runtime LABEL maintainer="hf-space" \ description="Gradio chat UI serving empero-ai/Qwythos-9B-Claude-Mythos-5-1M-GGUF via llama-cpp-python" # Runtime-only system dependencies: # - libgomp1: OpenMP runtime required by llama.cpp's multithreaded kernels. # - ca-certificates: needed for HTTPS downloads from the Hugging Face Hub. # NOTE: no compilers, no cmake, no git here -> keeps the final image lean. RUN apt-get update && apt-get install -y --no-install-recommends \ libgomp1 \ ca-certificates \ && rm -rf /var/lib/apt/lists/* # Run as a non-root user (Hugging Face Spaces requirement/best practice). RUN useradd --create-home --uid 1000 appuser WORKDIR /app # Install the pre-built llama-cpp-python wheel from the builder stage. COPY --from=builder /wheels /wheels COPY requirements.txt . RUN pip install --no-cache-dir --upgrade pip && \ pip install --no-cache-dir /wheels/*.whl && \ pip install --no-cache-dir -r requirements.txt && \ rm -rf /wheels /root/.cache/pip ~/.cache/pip # Application code COPY app.py . # --------------------------------------------------------------------------- # Runtime configuration (all overridable as Space "Variables and secrets" # without touching the Dockerfile). See README.md for the full list. # --------------------------------------------------------------------------- ENV \ # Where to look for the GGUF model on the Hub. GGUF_REPO_ID="empero-ai/Qwythos-9B-Claude-Mythos-5-1M-GGUF" \ # Leave empty to auto-select; set to force an exact filename. GGUF_FILENAME="" \ # Quantization to prefer when auto-selecting (falls back automatically # if this exact quant isn't present in the repo). PREFERRED_QUANT="Q4_K_M" \ # Local, persistent-within-container cache for downloaded model files # and Hub metadata so restarts of a *running* Space don't re-download. MODEL_CACHE_DIR="/data/models" \ HF_HOME="/data/hf_home" \ HF_HUB_ENABLE_HF_TRANSFER="0" \ # Context window (tokens). The model supports up to 1,048,576 via # baked-in YaRN scaling, but free CPU Spaces cannot allocate that much # KV-cache. Default is a safe value for a 16GB-RAM CPU Space; raise it # via the Space's Variables UI if you have more headroom. N_CTX="4096" \ # Free tier has 2 vCPUs; more threads just adds contention. N_THREADS="2" \ N_BATCH="256" \ MAX_NEW_TOKENS="1024" \ TEMPERATURE="0.6" \ TOP_P="0.95" \ TOP_K="20" \ REPEAT_PENALTY="1.05" \ SYSTEM_PROMPT="" \ # Number of retries when downloading the model file from the Hub. DOWNLOAD_MAX_RETRIES="5" \ # Gradio server bind settings (must be 0.0.0.0 + 7860 for HF Spaces). GRADIO_SERVER_NAME="0.0.0.0" \ GRADIO_SERVER_PORT="7860" \ PYTHONUNBUFFERED="1" # Cache/data directories must be writable by the non-root user. RUN mkdir -p /data/models /data/hf_home && \ chown -R appuser:appuser /data /app USER appuser EXPOSE 7860 CMD ["python", "app.py"]