unknown1321's picture
Clean deploy to HF Space
e9ce6e9
Raw
History Blame Contribute Delete
7.42 kB
# ═══════════════════════════════════════════════════════════════════════════════
# Autonomous Enterprise Payment Orchestrator (AEPO)
# Hugging Face Spaces β€” Production Container
# ═══════════════════════════════════════════════════════════════════════════════
#
# Architecture:
# Stage 1 (frontend-build) β€” Node.js 20 builds the Next.js dashboard to a
# static export (out/) that requires no Node runtime.
# Stage 2 (runtime) β€” Python 3.10-slim runs the FastAPI server which
# serves BOTH the OpenEnv API (POST /reset, /step,
# GET /state) AND the static dashboard at /.
#
# Port mapping:
# 7860 β€” the ONLY port exposed; Hugging Face Spaces routes external traffic here.
#
# OpenEnv compliance:
# POST /reset β†’ initialise episode
# POST /step β†’ advance one step
# GET /state β†’ inspect current observation
# GET / β†’ dashboard UI (static HTML/JS served by FastAPI)
#
# Usage:
# docker build -t aepo .
# docker run -p 7860:7860 aepo
#
# Space (browser): https://huggingface.co/spaces/unknown1321/autonomous-enterprise-payment-orchestrator
# API (OpenEnv): https://unknown1321-autonomous-enterprise-payment-orchestrator.hf.space
# ═══════════════════════════════════════════════════════════════════════════════
# ─────────────────────────────────────────────────────────────────────────────
# Stage 1 β€” Build the Next.js dashboard as a fully-static export
# ─────────────────────────────────────────────────────────────────────────────
FROM node:20-alpine AS frontend-build
# Prevent Node.js from running out of memory during the Next.js build
ENV NODE_OPTIONS="--max_old_space_size=4096"
WORKDIR /build
# Install deps in a separate layer so Docker cache is reused when only source
# files change (not package.json).
COPY frontend/package.json frontend/package-lock.json ./
RUN npm ci --prefer-offline
# Copy the rest of the frontend source and build.
# next.config.mjs must set output: 'export' β†’ generates out/
COPY frontend/ ./
RUN npm run build
# ─────────────────────────────────────────────────────────────────────────────
# Stage 2 β€” Python runtime: FastAPI + static dashboard files
# ─────────────────────────────────────────────────────────────────────────────
FROM python:3.10-slim AS runtime
# ── Labels ───────────────────────────────────────────────────────────────────
LABEL maintainer="Umesh Maurya <unknown1321>" \
description="AEPO β€” Autonomous Enterprise Payment Orchestrator (OpenEnv + HF Spaces)" \
version="0.2.0"
# ── Python environment hardening ─────────────────────────────────────────────
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1 \
OMP_NUM_THREADS=1 \
MKL_NUM_THREADS=1 \
OPENBLAS_NUM_THREADS=1 \
MALLOC_ARENA_MAX=2
# ── HF Spaces mandatory: non-root user UID=1000 ──────────────────────────────
# Hugging Face Spaces executes containers with UID 1000. Creating a matching
# user prevents permission errors on /home/user writes (logs, caches, etc.).
RUN useradd -m -u 1000 -s /bin/bash user
ENV HOME=/home/user
WORKDIR /app
# ── Python dependencies ───────────────────────────────────────────────────────
# Install all non-torch deps first (fast), then fetch the CPU-only torch wheel
# directly by URL to avoid the SHA mismatch that the simple-index advertises.
COPY requirements.txt .
RUN sed -e '/^--extra-index-url/d' -e '/^torch==/d' requirements.txt \
> /tmp/req_base.txt \
&& pip install --no-cache-dir -r /tmp/req_base.txt \
&& pip install --no-cache-dir \
"https://download.pytorch.org/whl/cpu/torch-2.2.0%2Bcpu-cp310-cp310-linux_x86_64.whl" \
&& rm -f /tmp/req_base.txt
# ── Application source ────────────────────────────────────────────────────────
# Copy only the files needed at runtime β€” .venv, java-mirror, node_modules,
# tests, and docs are excluded via .dockerignore.
COPY aepo_types.py unified_gateway.py dynamics_model.py graders.py inference.py openenv.yaml ./
COPY server/ ./server/
# Pre-trained artefacts β€” needed by inference.py (Q-table, MLP weights).
# These are generated by train.py and committed / built before the Docker push.
COPY results/ ./results/
# ── Static frontend (built in Stage 1) ───────────────────────────────────────
# FastAPI mounts this directory at "/" so the dashboard is served at the Space
# root while OpenEnv API routes (/reset, /step, /state) retain priority because
# FastAPI resolves explicit routes before mounted sub-apps.
COPY --from=frontend-build /build/out ./frontend/out
# Transfer ownership to the non-root user so all files are readable/writable.
RUN chown -R user:user /app
# ── Switch to non-root user (HF Spaces requirement) ──────────────────────────
USER user
# ── Expose the single public port ────────────────────────────────────────────
EXPOSE 7860
# ── Healthcheck β€” HF Spaces and openenv validate both probe GET / ─────────────
HEALTHCHECK --interval=30s --timeout=10s --start-period=15s --retries=3 \
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:7860/')" \
|| exit 1
# ── Default command ───────────────────────────────────────────────────────────
CMD ["uvicorn", "server.app:app", "--host", "0.0.0.0", "--port", "7860", \
"--workers", "2", "--log-level", "info"]