# ─── Stage 1: Build llama-server from source ───────────────────────────────── FROM python:3.11-slim AS llama-builder RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ cmake \ git \ pkg-config \ libopenblas-dev \ && rm -rf /var/lib/apt/lists/* WORKDIR /llama-build RUN git clone --depth 1 https://github.com/ggerganov/llama.cpp . RUN cmake -B build \ -DGGML_BLAS=ON \ -DGGML_BLAS_VENDOR=OpenBLAS \ -DCMAKE_BUILD_TYPE=Release \ -DLLAMA_BUILD_TESTS=OFF \ && cmake --build build --target llama-server -j$(nproc) # ─── Stage 2: Runtime image ─────────────────────────────────────────────────── FROM python:3.11-slim LABEL org.opencontainers.image.title="Surya OCR 2" LABEL org.opencontainers.image.description="CPU-powered document OCR using Surya OCR 2" RUN apt-get update && apt-get install -y --no-install-recommends \ libopenblas0 \ libgomp1 \ curl \ && rm -rf /var/lib/apt/lists/* # Copy llama-server binary from builder COPY --from=llama-builder /llama-build/build/bin/llama-server /usr/local/bin/llama-server RUN chmod +x /usr/local/bin/llama-server # Create non-root user (required for HF Spaces) RUN useradd -m -u 1000 appuser WORKDIR /app # Install Python deps as root first (faster layer caching) COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # Copy app files COPY app.py . # HF Spaces runs as uid 1000 RUN chown -R appuser:appuser /app USER appuser # Writable cache dirs for HF model downloads & llama.cpp ENV HF_HOME=/tmp/hf_cache ENV SURYA_INFERENCE_BACKEND=llamacpp # Use all available threads for llama.cpp ENV OMP_NUM_THREADS=4 ENV GRADIO_SERVER_PORT=7860 ENV GRADIO_SERVER_NAME=0.0.0.0 EXPOSE 7860 CMD ["python", "app.py"]