FROM python:3.11-slim # Switch to root to install ALL system dependencies including Playwright browser libs USER root RUN apt-get update && apt-get install -y \ ffmpeg \ espeak-ng \ portaudio19-dev \ python3-dev \ build-essential \ # ── Playwright / Chromium system dependencies ────────────────────────────── libnss3 \ libnspr4 \ libatk1.0-0 \ libatk-bridge2.0-0 \ libcups2 \ libdrm2 \ libdbus-1-3 \ libxkbcommon0 \ libxcomposite1 \ libxdamage1 \ libxfixes3 \ libxrandr2 \ libgbm1 \ libasound2 \ libpango-1.0-0 \ libcairo2 \ libatspi2.0-0 \ libwayland-client0 \ wget \ ca-certificates \ # ── S4: headless Blender runtime links (no X server needed in --background) ─ curl \ xz-utils \ libgl1 \ libegl1 \ libx11-6 \ libxi6 \ libxxf86vm1 \ libxrender1 \ libgomp1 \ libsm6 \ && rm -rf /var/lib/apt/lists/* # ── S4: Blender 4.5 LTS headless (official Linux x64 tarball, URL verified 2026-07-17). # Geometry processing + GLB export only — no rendering → CPU hardware is sufficient. ARG BLENDER_VERSION=4.5.3 # BLENDER IS OPTIONAL AND MUST NOT BE ABLE TO TAKE THE BACKEND DOWN. # # This step used to be fatal. On 2026-08-08 download.blender.org began answering # HuggingFace's build IPs with 403 — the file is still published (verified 200 # with the same URL and the same curl User-Agent from a normal network), so this # is the CDN refusing the builder, not a bad version pin. The whole Space failed # to build and the API, the assistant and the PC relay all went offline because a # 377 MB download for the 3D geometry pipeline was refused by a third party. # # The core backend does not need Blender; only the model/GLB pipeline does. So # the download is now best-effort with a mirror fallback and a soft exit, and # blender_available() at runtime decides whether that one feature is offered. # An optional dependency of one subsystem should degrade that subsystem, never # the server. RUN mkdir -p /opt/blender && \ ( curl -fsSL --retry 3 --retry-delay 2 \ -A "Mozilla/5.0 (X11; Linux x86_64) omega-build" \ "https://download.blender.org/release/Blender4.5/blender-${BLENDER_VERSION}-linux-x64.tar.xz" \ -o /tmp/blender.tar.xz \ || curl -fsSL --retry 2 --retry-delay 2 \ -A "Mozilla/5.0 (X11; Linux x86_64) omega-build" \ "https://mirrors.ocf.berkeley.edu/blender/release/Blender4.5/blender-${BLENDER_VERSION}-linux-x64.tar.xz" \ -o /tmp/blender.tar.xz \ || echo "BLENDER DOWNLOAD UNAVAILABLE — continuing without it" ) && \ ( test -s /tmp/blender.tar.xz \ && tar -xJf /tmp/blender.tar.xz -C /opt/blender --strip-components=1 \ && rm -f /tmp/blender.tar.xz \ && /opt/blender/blender --version \ || echo "Blender not installed; 3D geometry features will report unavailable" ) && \ true # Set up a new user named "user" with user ID 1000 RUN useradd -m -u 1000 user # Switch to the "user" user USER user ENV HOME=/home/user \ PATH=/home/user/.local/bin:/opt/blender:$PATH \ CLOUD_ENV=true \ PLAYWRIGHT_BROWSERS_PATH=/home/user/.playwright \ BLENDER_PATH=/opt/blender/blender # Set the working directory to the user's home directory WORKDIR $HOME/app # Copy the requirements file and install dependencies COPY --chown=user backend/requirements.txt $HOME/app/backend/requirements.txt RUN awk '!/^#/ && NF' backend/requirements.txt | while read -r req; do \ req=$(echo "$req" | tr -d '\r'); \ echo "=== INSTALLING: $req ==="; \ pip install --no-cache-dir --upgrade "$req" || { echo "FAILED ON: $req"; exit 1; }; \ done # Install Playwright Chromium browser binaries (for social media automation) RUN playwright install chromium # Copy the rest of the backend source code COPY --chown=user backend/ $HOME/app/backend/ # Copy required root modules and config COPY --chown=user modules/ $HOME/app/modules/ COPY --chown=user config.py $HOME/app/config.py # S4: AR scene bus (started by backend.main at boot; /scene/ws proxies into it) COPY --chown=user phone/ $HOME/app/phone/ # Copy the centralized database. # # NOTE: memory.db is not only the credential vault — it also carries `memories`, # `conversations`, `skills`, the knowledge-graph `nodes`/`edges`, `apscheduler_jobs` # and `master_vault_ledger`. Removing it drops real user data, not just keys, and # also breaks this build step. Restored deliberately. # # The credentials inside it are additionally present as HF Space Secrets, and # get_secret() reads the environment first, so the vault is a fallback rather # than the primary source. COPY --chown=user memory.db $HOME/app/memory.db # ── S4: ship the WebAR client — mobile AR loads straight from the Space at /webar/ COPY --chown=user webar/ $HOME/app/webar/ # ── Part 36: ship the signed Guardian APK so the install path actually resolves. # backend/routes/distribution_routes.py serves dist/app-release.apk at /distribution/android, # and the manifest reports its size and SHA-256. Without this COPY the route answers 503 # "apk_not_staged" no matter what is uploaded to the Space repo, because the file would exist # in the repo and not in the image the container actually runs. The advertised download URL # returning 404 was the original defect; this is the line that closes it. COPY --chown=user dist/ $HOME/app/dist/ # ── S4: writable pipeline dirs (container FS is ephemeral; durable copies are pushed # to the private OMEGA models dataset via huggingface_hub at runtime) RUN mkdir -p $HOME/app/storage/models3d $HOME/app/storage/forge_templates $HOME/app/storage/chroma_db # Expose the default port for Hugging Face Spaces EXPOSE 7860 # We use the Self-Healing Supervisor to boot the actual server CMD ["python", "-u", "backend/supervisor.py"] # S4 rebuild marker 2026-07-17 — Blender pipeline + WebAR serving # Part 18 (2026-07-22): repo copy reconciled with the deployed Space copy; this file # is now the single source of truth — deploy_hf_space.py stages it with a content guard.