File size: 5,997 Bytes
b73c012
5d8d23e
c13c2a7
5d8d23e
 
45fe8f0
 
 
6a3762e
5d8d23e
 
45fe8f0
 
 
 
5d8d23e
 
45fe8f0
 
5d8d23e
 
 
 
45fe8f0
 
 
 
 
 
 
 
5d8d23e
 
 
 
 
 
45fe8f0
5d8d23e
 
 
 
 
 
 
 
 
45fe8f0
5d8d23e
b6e5beb
6cd3e11
 
45fe8f0
6cd3e11
5d8d23e
 
 
 
 
 
 
 
45fe8f0
6cd3e11
 
 
 
 
 
5d8d23e
 
 
45fe8f0
5d8d23e
 
 
 
 
 
 
 
 
 
 
 
 
45fe8f0
 
 
 
 
 
 
 
5d8d23e
 
c13c2a7
45fe8f0
 
 
 
 
 
6a3762e
 
 
 
 
 
 
5d8d23e
 
 
 
 
 
b6e5beb
 
5d8d23e
 
 
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# syntax=docker/dockerfile:1
# ════════════════════════════════════════════════════════════════
# HuggingFlow β€” DeerFlow Research Agent for Hugging Face Spaces
# ════════════════════════════════════════════════════════════════
#
# Uses official pre-built DeerFlow images from GHCR β€” no compile step.
# Build time: ~5 min (was 30+ min building from source).
#
# Public port 7860 β†’ health-server.js β†’ nginx:7861 β†’ backend:8001 / frontend:3000
#
# Build args:
#   DEERFLOW_BACKEND  β€” backend image (default: ghcr.io/bytedance/deer-flow-backend:latest)
#   DEERFLOW_FRONTEND β€” frontend image (default: ghcr.io/bytedance/deer-flow-frontend:latest)
#   UV_IMAGE          β€” uv tool image  (default: ghcr.io/astral-sh/uv:0.7.20)
#   NODE_MAJOR        β€” Node.js major version (default: 22)

ARG UV_IMAGE=ghcr.io/astral-sh/uv:0.7.20
ARG DEERFLOW_BACKEND=ghcr.io/bytedance/deer-flow-backend:latest
ARG DEERFLOW_FRONTEND=ghcr.io/bytedance/deer-flow-frontend:latest

# ── uv source ────────────────────────────────────────────────────
FROM ${UV_IMAGE} AS uv-source

# ── Pre-built DeerFlow images (no source compilation needed) ──────
# Backend image layout:  /app/backend/ (Python source + .venv)
# Frontend image layout: /app/frontend/ (built .next + node_modules)
FROM ${DEERFLOW_BACKEND} AS backend-src
FROM ${DEERFLOW_FRONTEND} AS frontend-src

# ── Minimal source clone (skills + config only) ───────────────────
# skills/ and config.example.yaml are not bundled in the official images
FROM alpine/git:latest AS source
RUN git clone --depth=1 \
    https://github.com/bytedance/deer-flow.git /src && \
    cd /src && \
    git log --oneline -1

# ── Runtime ───────────────────────────────────────────────────────
FROM python:3.12-slim-bookworm

ENV LANG=C.UTF-8 \
    LC_ALL=C.UTF-8 \
    PYTHONIOENCODING=utf-8 \
    PYTHONUNBUFFERED=1

ARG NODE_MAJOR=22

# Layer 1: nginx + base tools (rarely changes β€” stays cached)
RUN apt-get update && apt-get install -y --no-install-recommends \
    curl ca-certificates gnupg nginx openssl \
    && rm -rf /var/lib/apt/lists/*

# Layer 2: Node.js (separate layer β€” apt network stall doesn't force pip re-run)
RUN mkdir -p /etc/apt/keyrings \
    && curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key \
       | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \
    && echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] \
       https://deb.nodesource.com/node_${NODE_MAJOR}.x nodistro main" \
       > /etc/apt/sources.list.d/nodesource.list \
    && apt-get update && apt-get install -y --no-install-recommends nodejs \
    && rm -rf /var/lib/apt/lists/*

# Layer 3: Python helpers with retries (flaky HF Spaces network)
RUN pip3 install --no-cache-dir --break-system-packages --timeout 120 --retries 5 \
        huggingface_hub pyyaml \
    || (echo "pip retry 2" && pip3 install --no-cache-dir --break-system-packages --timeout 120 --retries 5 huggingface_hub pyyaml) \
    || (echo "pip retry 3" && pip3 install --no-cache-dir --break-system-packages --timeout 120 --retries 5 huggingface_hub pyyaml) \
    || (echo "ERROR: pip install failed after 3 attempts" && exit 1)

# pnpm for `pnpm start` in Next.js runtime
RUN corepack enable && corepack install -g pnpm@10.26.2

# uv for backend startup (`uv run --no-sync uvicorn ...`)
COPY --from=uv-source /uv /uvx /usr/local/bin/

# ── Create non-root user UID=1000 (required by HF Spaces) ────────
RUN useradd -m -u 1000 -s /bin/bash user && \
    mkdir -p \
        /app/backend \
        /app/frontend \
        /app/skills \
        /app/data \
        /tmp/nginx-tmp && \
    chown -R 1000:1000 /app /tmp/nginx-tmp && \
    chown -R 1000:1000 /var/log/nginx /var/lib/nginx 2>/dev/null || true

# ── Copy pre-built DeerFlow artifacts ────────────────────────────
# Backend: Python source + pre-built .venv (no uv sync / grpcio compile)
COPY --from=backend-src  --chown=1000:1000 /app/backend  /app/backend
# Frontend: built .next + node_modules (no pnpm install / Next.js build)
COPY --from=frontend-src --chown=1000:1000 /app/frontend /app/frontend
# Skills (not bundled in official images)
COPY --from=source --chown=1000:1000 /src/skills           /app/skills
# Config template
COPY --from=source --chown=1000:1000 /src/config.example.yaml /app/config.example.yaml

# ── Copy HuggingFlow runtime scripts ─────────────────────────────
COPY --chown=1000:1000 nginx.conf                    /etc/nginx/nginx.conf
COPY --chown=1000:1000 start.sh                      /app/start.sh
COPY --chown=1000:1000 deerflow-sync.py              /app/deerflow-sync.py
COPY --chown=1000:1000 health-server.js              /app/health-server.js
COPY --chown=1000:1000 cloudflare-proxy.js           /app/cloudflare-proxy.js
COPY --chown=1000:1000 cloudflare-proxy-setup.py     /app/cloudflare-proxy-setup.py
COPY --chown=1000:1000 cloudflare-keepalive-setup.py /app/cloudflare-keepalive-setup.py

RUN chmod +x \
    /app/start.sh \
    /app/deerflow-sync.py \
    /app/cloudflare-proxy-setup.py \
    /app/cloudflare-keepalive-setup.py

USER user
WORKDIR /app

EXPOSE 7860

# 120s start period β€” restore + backend + frontend startup can take up to 2 min
HEALTHCHECK --interval=30s --timeout=10s --start-period=120s \
    CMD curl -fsS http://localhost:7860/health || exit 1

CMD ["/app/start.sh"]