File size: 1,708 Bytes
6880a8f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0b99fa7
 
 
6880a8f
 
 
 
 
 
 
 
 
c2ffcb9
 
 
6880a8f
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# Hugging Face Docker Space: KCNA Interactive Learning Lab + AI tutor.
# Runs on the free "CPU basic" tier (2 vCPU, 16 GB RAM). No GPU, no paid inference.
#  - llama-server (llama.cpp) serves an open-weight GGUF model on 127.0.0.1:8081
#  - the Node API (server.mjs) serves the web app and /api/* on port 7860
# The web app and API are pre-built by CI (scripts/build-space.ts); nothing is compiled here.

FROM docker.io/library/node:22-bookworm-slim AS node

# Pinned llama.cpp CPU server image (Ubuntu based)
FROM ghcr.io/ggml-org/llama.cpp:server@sha256:2103d1f4f2e2e223ad80587dcb39fc15a9f912f29ae1fa9fc1193fe8c1aea82f

COPY --from=node /usr/local/bin/node /usr/local/bin/node

# Model is public; it is downloaded at build time so cold starts don't re-download it.
# Override with Space variables MODEL_REPO / MODEL_FILE (passed as build args).
ARG MODEL_REPO=unsloth/Qwen3-4B-Instruct-2507-GGUF
ARG MODEL_FILE=Qwen3-4B-Instruct-2507-Q4_K_M.gguf
ARG MODEL_LABEL="Qwen3-4B-Instruct-2507 (Q4_K_M, llama.cpp CPU)"
RUN mkdir -p /models \
 && curl -fsSL --retry 5 --retry-delay 5 -o /models/model.gguf "https://huggingface.co/${MODEL_REPO}/resolve/main/${MODEL_FILE}" \
 && ls -la /models

WORKDIR /srv
COPY server.mjs start.sh ./
COPY web ./web
RUN chmod 755 /srv/start.sh && chmod -R a+rX /srv /models

# llama.cpp ships its shared libraries next to the binary in /app
ENV LD_LIBRARY_PATH=/app \
    PORT=7860 \
    STATIC_DIR=/srv/web \
    LLAMA_URL=http://127.0.0.1:8081 \
    TUTOR_PROVIDER=llamacpp \
    TUTOR_MODEL="${MODEL_LABEL}" \
    LLAMA_CTX=8192 \
    LLAMA_THREADS=2 \
    ALLOWED_ORIGINS=https://mhhamdan.github.io \
    NODE_ENV=production

USER 1000
EXPOSE 7860
ENTRYPOINT ["/srv/start.sh"]