# Syntheogenesis HF Space — Docker SDK. # # Bake the Flask app + ESM-2 dependencies into a single image. HF Spaces # routes traffic to whatever port the container listens on (default 7860); # we honor that via the PORT env var. FROM python:3.12-slim # Run as a non-root user — HF Spaces convention. The user has uid 1000 # which matches the Space's writable directories. ARG USER_UID=1000 ARG USER_GID=1000 RUN groupadd --gid $USER_GID app \ && useradd --uid $USER_UID --gid $USER_GID -m -s /bin/bash app # System packages needed by Biopython / Pillow / general compile of any # native Python wheel that doesn't ship binary for Python 3.12 yet. RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential gcc git curl ca-certificates \ && rm -rf /var/lib/apt/lists/* WORKDIR /app # Install Python deps first so Docker can cache the layer when source changes. COPY requirements.txt ./ RUN pip install --no-cache-dir --upgrade pip \ && pip install --no-cache-dir -r requirements.txt # Now copy source + install the package itself. COPY --chown=app:app pyproject.toml ./ COPY --chown=app:app dee ./dee RUN pip install --no-cache-dir -e . # Pre-create writable dirs the app expects under /tmp (HF Spaces gives the # non-root user a writable /tmp but not /app/.dee). ENV HOME=/tmp \ XDG_CACHE_HOME=/tmp/.cache \ HF_HOME=/opt/hf-cache \ HF_HUB_DISABLE_TELEMETRY=1 \ HOST=0.0.0.0 \ PORT=7860 \ PYTHONUNBUFFERED=1 # HF_HOME now points at a BAKED, image-resident dir (not ephemeral /tmp) so the # default model's weights persist across Space restarts instead of re-downloading. RUN mkdir -p /tmp/.cache /tmp/.dee/output /tmp/.dee/state /opt/hf-cache \ && chown -R app:app /tmp/.dee /tmp/.cache /opt/hf-cache USER app # Bake the default ESM-2 (35M) weights into the image so a cold start doesn't pay # the re-download cost. Best-effort: if the prefetch fails at build time, the # build still succeeds and the app simply lazy-loads the model at runtime. RUN python -c "from transformers import AutoTokenizer, AutoModelForMaskedLM; m='facebook/esm2_t12_35M_UR50D'; AutoTokenizer.from_pretrained(m); AutoModelForMaskedLM.from_pretrained(m)" \ || echo 'ESM-2 prefetch skipped — model will lazy-load at runtime' EXPOSE 7860 # Production WSGI server. ONE gthread worker (state lives in-process), threads # for concurrency, generous timeout (the model load happens in a background # thread so requests stay fast). gunicorn's master auto-restarts the worker on a # crash, so an unhandled error no longer downs the whole Space until a reboot. CMD ["gunicorn", "dee.server:build_app()", \ "--workers", "1", "--threads", "8", "--worker-class", "gthread", \ "--bind", "0.0.0.0:7860", "--timeout", "120", "--graceful-timeout", "30", \ "--keep-alive", "5", "--access-logfile", "-", "--error-logfile", "-"]