File size: 4,261 Bytes
da89010 bc610c2 9e27039 da89010 9e27039 da89010 bc610c2 9e27039 da89010 1f1ea05 2f079cf da89010 1f1ea05 2f079cf da89010 bc610c2 da89010 9e27039 da89010 f95c194 9e27039 da89010 9e27039 da89010 fd8d54e da89010 fd8d54e da89010 1f1ea05 | 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 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | # ββ Base image ββββββββββββββββββββββββββββββββββββββββββββββββ
# Alpine (musl libc), not Debian slim (glibc) β the abetlen prebuilt CPU
# wheel for llama-cpp-python is itself linked against musl (confirmed via
# readelf: NEEDED libc.musl-x86_64.so.1), even though its filename is
# tagged with the generic "linux_x86_64" platform tag rather than a
# proper musllinux tag. On a glibc image this crashes at import time with
# "OSError: libc.musl-x86_64.so.1: cannot open shared object file".
# All other compiled deps here (pydantic-core, uvloop, httptools) publish
# real musllinux wheels, so nothing needs to compile from source.
FROM python:3.11-alpine
# ββ Environment βββββββββββββββββββββββββββββββββββββββββββββββ
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PIP_NO_CACHE_DIR=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1
# ββ System dependencies βββββββββββββββββββββββββββββββββββββββ
# Runtime-only β libstdc++/libgomp satisfy the wheel's NEEDED entries
# (ggml-cpu uses OpenMP + C++). No compiler needed since nothing builds
# from source.
RUN apk add --no-cache curl libstdc++ libgomp
# ββ Work directory ββββββββββββββββββββββββββββββββββββββββββββ
WORKDIR /app
# ββ Python dependencies βββββββββββββββββββββββββββββββββββββββ
# Install llama-cpp-python from precompiled CPU wheels (no compile β fast!)
# Pinned version + --only-binary forces pip to fail fast if the abetlen wheel
# index ever stops publishing a matching wheel, instead of silently falling
# back to a from-source cmake build that blows past HF's build timeout.
# Plain llama-cpp-python (no [server] extra) β we load the model directly
# with the Llama class and implement the OpenAI-style routes ourselves,
# rather than running llama_cpp.server's own bundled FastAPI app (which had
# a bug in its generic error-handling path that returned empty 400s on every
# proxied request). Then install our own minimal FastAPI stack.
RUN pip install --upgrade pip && \
pip install \
--only-binary=llama-cpp-python \
"llama-cpp-python==0.3.19" \
--extra-index-url https://abetlen.github.io/llama-cpp-python/whl/cpu && \
pip install \
fastapi \
"uvicorn[standard]" \
huggingface_hub \
pydantic
# ββ Copy app ββββββββββββββββββββββββββββββββββββββββββββββββββ
COPY app.py .
# ββ Port ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
EXPOSE 7860
# ββ Default environment (override via Space Settings) βββββββββ
# SPACE_ROLE: "reasoning" | "uncensored" | "general" (default: general) β
# picks the curated model automatically. Deliberately NOT setting MODEL_ID
# here: a hardcoded ENV MODEL_ID would always exist in os.environ, so
# app.py's `os.environ.get("MODEL_ID", ROLE_TO_MODEL_ID[SPACE_ROLE])`
# fallback could never trigger β every Space would pin to that value
# regardless of SPACE_ROLE. (This bit us once: this line used to read
# `ENV MODEL_ID="qwen"` and silently overrode SPACE_ROLE on every Space.)
# MODEL_ID / MODEL_REPO / MODEL_FILE: optional raw overrides, set only as a
# Space Variable if you want to bypass role-based selection entirely.
# N_CTX: context window tokens (default: 8192)
# N_THREADS: CPU threads (default: 4)
# API_KEY: optional bearer token to protect the API
# CONFIG_URL: optional URL to a JSON config (for multi-Space clusters)
ENV N_CTX="8192" \
N_THREADS="4"
# ββ Launch ββββββββββββββββββββββββββββββββββββββββββββββββββββ
CMD ["python", "app.py"]
|