File size: 3,575 Bytes
3d2dbcf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
# OpenEnv API container
#
# Two-stage build:
#   1. builder  - compiles the vendored CityFlow Python extension
#   2. runtime  - installs the API dependencies and copies the repo-local data
#
# Runtime env vars:
#   DATA_DIR         generated CityFlow dataset root
#                    default: /app/data/generated
#   SPLITS_DIR       train/val/test split files
#                    default: /app/data/splits
#   CHECKPOINT_PATH  optional DQN checkpoint
#                    default: /app/artifacts/dqn_shared/best_validation.pt
# ---------------------------------------------------------------------------

# ── Stage 1: Build CityFlow ─────────────────────────────────────────────────
FROM python:3.12-slim AS builder

# Build tools needed by CityFlow's CMake build
RUN apt-get update && apt-get install -y --no-install-recommends \
        build-essential \
        cmake \
        libboost-all-dev \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /build

# Copy only the CityFlow source (pybind11 is bundled as an extern submodule)
COPY third_party/CityFlow ./CityFlow

# Build and install cityflow into the builder's site-packages
RUN rm -rf ./CityFlow/build
RUN pip install --no-cache-dir ./CityFlow

# Locate the compiled .so so we can copy it to the runtime stage
RUN python -c "import cityflow, os; print(os.path.dirname(cityflow.__file__))"


# ── Stage 2: Runtime ────────────────────────────────────────────────────────
FROM python:3.12-slim AS runtime

WORKDIR /app

# Copy the compiled cityflow extension from the builder
COPY --from=builder /usr/local/lib/python3.12/site-packages/cityflow* \
                    /usr/local/lib/python3.12/site-packages/

# Install Python dependencies (no build tools needed here)
COPY openenv_app/requirements.txt ./requirements.txt
RUN pip install --no-cache-dir -r requirements.txt

# Copy application source (only what the OpenEnv API needs at runtime)
COPY agents/         ./agents/
COPY district_llm/   ./district_llm/
COPY env/            ./env/
COPY openenv_app/    ./openenv_app/
COPY server/__init__.py           ./server/__init__.py
COPY server/path_validators.py    ./server/path_validators.py
COPY server/policy_runner.py      ./server/policy_runner.py
COPY server/roadnet_matcher.py    ./server/roadnet_matcher.py
COPY training/       ./training/
COPY data/splits/    ./data/splits/
COPY data/generated/city_0002/ ./data/generated/city_0002/
COPY artifacts/dqn_shared/best_validation.pt ./artifacts/dqn_shared/best_validation.pt
COPY artifacts/district_llm_adapter_v3/main_run/adapter/ ./artifacts/district_llm_adapter_v3/main_run/adapter/

# Keep runtime paths present, but expect the actual generated dataset to be
# mounted or synced separately instead of baked into the image.
RUN mkdir -p /app/data/generated /app/data/splits

# Default paths (overridable at runtime via env vars).
# DATA_DIR must point at a mounted/generated dataset root that contains city_*/
# directories and scenario files; only data/splits is bundled here.
ENV DATA_DIR=/app/data/generated
ENV SPLITS_DIR=/app/data/splits
ENV CHECKPOINT_PATH=/app/artifacts/dqn_shared/best_validation.pt
ENV DISTRICT_LLM_ADAPTER_PATH=/app/artifacts/district_llm_adapter_v3/main_run/adapter

# OpenEnv and HF Spaces commonly use port 7860.
EXPOSE 7860

CMD ["sh", "-c", "uvicorn openenv_app.app:app --host 0.0.0.0 --port ${PORT:-7860}"]