# ═══════════════════════════════════════════════════════════════════════════════ # 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 " \ 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"]