|
5 | 5 |
|
6 | 6 | set -e |
7 | 7 |
|
| 8 | +# Cross-platform sed in-place editing |
| 9 | +# BSD sed (macOS) requires -i '', GNU sed (Linux) requires -i |
| 10 | +sed_inplace() { |
| 11 | + if sed --version >/dev/null 2>&1; then |
| 12 | + # GNU sed |
| 13 | + sed -i "$@" |
| 14 | + else |
| 15 | + # BSD sed |
| 16 | + sed -i '' "$@" |
| 17 | + fi |
| 18 | +} |
| 19 | + |
8 | 20 | ENV_NAME="$1" |
9 | 21 | BASE_IMAGE_SHA="$2" |
10 | 22 | STAGING_DIR="hf-staging" |
@@ -41,288 +53,118 @@ echo "Copied core files" |
41 | 53 | cp -r src/envs/$ENV_NAME/* $CURRENT_STAGING_DIR/src/envs/$ENV_NAME/ |
42 | 54 | echo "Copied $ENV_NAME environment files" |
43 | 55 |
|
44 | | -# Create environment-specific multi-stage Dockerfile |
| 56 | +# Copy and modify the static Dockerfile from the environment |
45 | 57 | create_environment_dockerfile() { |
46 | 58 | local env_name=$1 |
47 | | - |
48 | | - # Create base Dockerfile |
49 | | - cat > $CURRENT_STAGING_DIR/Dockerfile << DOCKERFILE_EOF |
50 | | -# Copyright (c) Meta Platforms, Inc. and affiliates. |
51 | | -# All rights reserved. |
52 | | -# |
53 | | -# This source code is licensed under the BSD-style license found in the |
54 | | -# LICENSE file in the root directory of this source tree. |
55 | | -
|
56 | | -# Use the specified openenv-base image |
57 | | -FROM $BASE_IMAGE_REF |
58 | | -DOCKERFILE_EOF |
59 | | - |
60 | | - # Add environment-specific dependencies |
61 | | - case $env_name in |
62 | | - "echo_env") |
63 | | - # Echo environment needs no additional dependencies |
64 | | - ;; |
65 | | - "coding_env") |
66 | | - cat >> $CURRENT_STAGING_DIR/Dockerfile << 'DOCKERFILE_EOF' |
67 | | -# Install smolagents for code execution |
68 | | -RUN pip install --no-cache-dir smolagents |
69 | | -DOCKERFILE_EOF |
70 | | - ;; |
71 | | - "chat_env") |
72 | | - cat >> $CURRENT_STAGING_DIR/Dockerfile << 'DOCKERFILE_EOF' |
73 | | -# Install additional dependencies for ChatEnvironment |
74 | | -RUN pip install --no-cache-dir torch transformers |
75 | | -
|
76 | | -# Set up cache directory for Hugging Face models |
77 | | -RUN mkdir -p /.cache && chmod 777 /.cache |
78 | | -ENV HF_HOME=/.cache |
79 | | -ENV TRANSFORMERS_CACHE=/.cache |
80 | | -
|
81 | | -# Pre-download the GPT-2 model to avoid permission issues during runtime |
82 | | -RUN python -c "from transformers import GPT2Tokenizer; GPT2Tokenizer.from_pretrained('gpt2')" |
83 | | -DOCKERFILE_EOF |
84 | | - ;; |
85 | | - "atari_env") |
86 | | - cat >> $CURRENT_STAGING_DIR/Dockerfile << 'DOCKERFILE_EOF' |
87 | | -# Install ALE-specific dependencies |
88 | | -RUN pip install --no-cache-dir \ |
89 | | - gymnasium>=0.29.0 \ |
90 | | - ale-py>=0.8.0 \ |
91 | | - numpy>=1.24.0 |
92 | | -DOCKERFILE_EOF |
93 | | - ;; |
94 | | - "openspiel_env") |
95 | | - # OpenSpiel requires special C++ build process - replace entire Dockerfile |
96 | | - cat > $CURRENT_STAGING_DIR/Dockerfile << DOCKERFILE_EOF |
97 | | -# OpenSpiel environment using pre-built OpenSpiel base image |
98 | | -ARG OPENSPIEL_BASE_IMAGE=ghcr.io/meta-pytorch/openenv-openspiel-base:sha-e622c7e |
99 | | -FROM \${OPENSPIEL_BASE_IMAGE} |
100 | | -
|
101 | | -# Copy OpenEnv core (base image already set WORKDIR=/app) |
102 | | -WORKDIR /app |
103 | | -COPY src/core/ /app/src/core/ |
104 | | -
|
105 | | -# Copy OpenSpiel environment |
106 | | -COPY src/envs/openspiel_env/ /app/src/envs/openspiel_env/ |
107 | | -
|
108 | | -# Copy README for web interface documentation |
109 | | -COPY src/envs/openspiel_env/README.md /app/README.md |
110 | | -
|
111 | | -# Extend Python path for OpenEnv (base image set PYTHONPATH=/app/src) |
112 | | -# We prepend OpenSpiel paths |
113 | | -ENV PYTHONPATH=/repo:/repo/build/python:/app/src |
114 | | -
|
115 | | -# OpenSpiel-specific environment variables (can be overridden at runtime) |
116 | | -ENV OPENSPIEL_GAME=catch |
117 | | -ENV OPENSPIEL_AGENT_PLAYER=0 |
118 | | -ENV OPENSPIEL_OPPONENT_POLICY=random |
119 | | -
|
120 | | -# Health check (curl is provided by openenv-base) |
121 | | -HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ |
122 | | - CMD curl -f http://localhost:8000/health || exit 1 |
123 | | -
|
124 | | -# Note: EXPOSE 8000 already set by openenv-base |
125 | | -
|
126 | | -# Run the FastAPI server (uvicorn installed by openenv-base) |
127 | | -CMD ["uvicorn", "envs.openspiel_env.server.app:app", "--host", "0.0.0.0", "--port", "8000"] |
128 | | -DOCKERFILE_EOF |
129 | | - echo "Created special OpenSpiel Dockerfile with C++ build process" |
130 | | - echo "OpenSpiel builds can take 10-15 minutes due to C++ compilation" |
131 | | - return # Skip the common parts since OpenSpiel has its own complete Dockerfile |
132 | | - ;; |
133 | | - esac |
134 | | - |
135 | | - # Add common parts |
136 | | - cat >> $CURRENT_STAGING_DIR/Dockerfile << 'DOCKERFILE_EOF' |
137 | | -
|
138 | | -# Copy only what's needed for this environment |
139 | | -COPY src/core/ /app/src/core/ |
140 | | -COPY src/envs/ENV_NAME_PLACEHOLDER/ /app/src/envs/ENV_NAME_PLACEHOLDER/ |
141 | | -
|
142 | | -# Health check |
143 | | -HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ |
144 | | - CMD curl -f http://localhost:8000/health || exit 1 |
145 | | -
|
146 | | -# Run the FastAPI server |
147 | | -CMD ["uvicorn", "envs.ENV_NAME_PLACEHOLDER.server.app:app", "--host", "0.0.0.0", "--port", "8000"] |
148 | | -DOCKERFILE_EOF |
149 | | - |
150 | | - # Replace placeholder with actual environment name |
151 | | - sed -i "s/ENV_NAME_PLACEHOLDER/$env_name/g" $CURRENT_STAGING_DIR/Dockerfile |
| 59 | + local dockerfile_path="src/envs/$env_name/server/Dockerfile" |
| 60 | + local prepare_script="src/envs/$env_name/server/prepare_hf.sh" |
| 61 | + |
| 62 | + if [ ! -f "$dockerfile_path" ]; then |
| 63 | + echo "Error: Dockerfile not found at $dockerfile_path" |
| 64 | + exit 1 |
| 65 | + fi |
| 66 | + |
| 67 | + # Copy the static Dockerfile |
| 68 | + cp "$dockerfile_path" "$CURRENT_STAGING_DIR/Dockerfile" |
| 69 | + echo "Copied static Dockerfile from $dockerfile_path" |
| 70 | + |
| 71 | + # Check if environment has custom HF preparation script |
| 72 | + if [ -f "$prepare_script" ]; then |
| 73 | + echo "Found custom HF preparation script, executing..." |
| 74 | + chmod +x "$prepare_script" |
| 75 | + "$prepare_script" "$CURRENT_STAGING_DIR/Dockerfile" "$BASE_IMAGE_REF" |
| 76 | + else |
| 77 | + # Standard Dockerfile modification: replace ARG BASE_IMAGE with FROM |
| 78 | + sed_inplace "s|ARG BASE_IMAGE=.*||g" "$CURRENT_STAGING_DIR/Dockerfile" |
| 79 | + sed_inplace "s|FROM \${BASE_IMAGE}|FROM $BASE_IMAGE_REF|g" "$CURRENT_STAGING_DIR/Dockerfile" |
| 80 | + echo "Modified Dockerfile with base image: $BASE_IMAGE_REF" |
| 81 | + fi |
| 82 | + |
| 83 | + # Add web interface support before the final CMD |
| 84 | + # Use awk for cross-platform compatibility |
| 85 | + awk '/^CMD \[/{print "ENV ENABLE_WEB_INTERFACE=true\n"; print; next} 1' "$CURRENT_STAGING_DIR/Dockerfile" > "$CURRENT_STAGING_DIR/Dockerfile.tmp" |
| 86 | + mv "$CURRENT_STAGING_DIR/Dockerfile.tmp" "$CURRENT_STAGING_DIR/Dockerfile" |
| 87 | + echo "Enabled web interface" |
152 | 88 | } |
153 | 89 |
|
154 | 90 | create_environment_dockerfile $ENV_NAME |
155 | 91 |
|
156 | | -# Add web interface support |
157 | | -echo "ENV ENABLE_WEB_INTERFACE=true" >> $CURRENT_STAGING_DIR/Dockerfile |
158 | | -echo "Added web interface support" |
159 | | - |
160 | | -# Create environment-specific README |
| 92 | +# Copy and prepend HF-specific intro to README |
161 | 93 | create_readme() { |
162 | 94 | local env_name=$1 |
163 | | - |
164 | | - # Capitalize first letter of environment name |
165 | | - env_title=$(echo "$env_name" | awk '{print toupper(substr($0,1,1)) substr($0,2)}') |
166 | | - |
167 | | - # Set environment-specific colors and emoji |
168 | | - case $env_name in |
169 | | - "atari_env") |
170 | | - EMOJI="🕹️" |
171 | | - COLOR_FROM="#FF6200" |
172 | | - COLOR_TO="#D4151B" |
173 | | - ;; |
174 | | - "coding_env") |
175 | | - EMOJI="💻" |
176 | | - COLOR_FROM="#007ACC" |
177 | | - COLOR_TO="#1E1E1E" |
178 | | - ;; |
179 | | - "openspiel_env") |
180 | | - EMOJI="🎮" |
181 | | - COLOR_FROM="#9146FF" |
182 | | - COLOR_TO="#00FFA3" |
183 | | - ;; |
184 | | - "echo_env") |
185 | | - EMOJI="🔊" |
186 | | - COLOR_FROM="#00C9FF" |
187 | | - COLOR_TO="#1B2845" |
188 | | - ;; |
189 | | - "chat_env") |
190 | | - EMOJI="💬" |
191 | | - COLOR_FROM="#0084FF" |
192 | | - COLOR_TO="#25D366" |
193 | | - ;; |
194 | | - *) |
195 | | - EMOJI="🐳" |
196 | | - COLOR_FROM="blue" |
197 | | - COLOR_TO="green" |
198 | | - ;; |
199 | | - esac |
| 95 | + local readme_source="src/envs/$env_name/README.md" |
200 | 96 |
|
201 | | - cat > $CURRENT_STAGING_DIR/README.md << README_EOF |
202 | | ---- |
203 | | -title: ${env_title} Environment Server |
204 | | -emoji: ${EMOJI} |
205 | | -colorFrom: ${COLOR_FROM} |
206 | | -colorTo: ${COLOR_TO} |
207 | | -sdk: docker |
208 | | -pinned: false |
209 | | -app_port: 8000 |
210 | | -base_path: /web |
211 | | ---- |
| 97 | + if [ ! -f "$readme_source" ]; then |
| 98 | + echo "Error: README not found at $readme_source" |
| 99 | + exit 1 |
| 100 | + fi |
212 | 101 |
|
213 | | -# ${env_title} Environment Server |
| 102 | + # Check if README already has HF front matter |
| 103 | + if head -n 1 "$readme_source" | grep -q "^---$"; then |
| 104 | + echo "README has HF front matter, inserting HF deployment section after it" |
214 | 105 |
|
215 | | -FastAPI server for ${env_name} environment powered by Meta's OpenEnv. |
| 106 | + # Find the line number of the closing --- (second occurrence) |
| 107 | + local closing_line=$(grep -n "^---$" "$readme_source" | sed -n '2p' | cut -d: -f1) |
216 | 108 |
|
217 | | -## About |
| 109 | + if [ -z "$closing_line" ]; then |
| 110 | + echo "Error: Could not find closing --- in front matter" |
| 111 | + exit 1 |
| 112 | + fi |
218 | 113 |
|
219 | | -This Space provides a containerized environment for ${env_name} interactions. |
220 | | -Built with FastAPI and OpenEnv framework. |
| 114 | + # Split the README: front matter + rest |
| 115 | + head -n "$closing_line" "$readme_source" > "$CURRENT_STAGING_DIR/README.md" |
221 | 116 |
|
222 | | -## Web Interface |
| 117 | + # Add HF-specific deployment info right after front matter |
| 118 | + cat >> $CURRENT_STAGING_DIR/README.md << 'README_EOF' |
223 | 119 |
|
224 | | -This deployment includes an interactive web interface for exploring the environment: |
225 | | -- **HumanAgent Interface**: Interact with the environment using a web form |
226 | | -- **State Observer**: Real-time view of environment state and action history |
227 | | -- **Live Updates**: WebSocket-based real-time updates |
| 120 | +## 🚀 Hugging Face Space Deployment |
228 | 121 |
|
229 | | -Access the web interface at: \`/web\` |
| 122 | +This is a Hugging Face Space deployment of the OpenEnv environment. It includes: |
230 | 123 |
|
231 | | -README_EOF |
| 124 | +- **Web Interface** at `/web` - Interactive UI for exploring the environment |
| 125 | +- **API Documentation** at `/docs` - Full OpenAPI/Swagger interface |
| 126 | +- **Health Check** at `/health` - Container health monitoring |
232 | 127 |
|
233 | | - # Add environment-specific information |
234 | | - case $env_name in |
235 | | - "echo_env") |
236 | | - cat >> $CURRENT_STAGING_DIR/README.md << 'README_EOF' |
237 | | -## Echo Environment |
| 128 | +### Connecting from Code |
238 | 129 |
|
239 | | -Simple test environment that echoes back messages. Perfect for testing the OpenEnv APIs. |
| 130 | +```python |
| 131 | +from envs.ENV_NAME_PLACEHOLDER import ENV_CLASS_PLACEHOLDER |
240 | 132 |
|
241 | | -### Usage |
242 | | -Send a POST request to `/step` with: |
243 | | -```json |
244 | | -{ |
245 | | - "message": "Hello World" |
246 | | -} |
247 | | -``` |
248 | | -README_EOF |
249 | | - ;; |
250 | | - "coding_env") |
251 | | - cat >> $CURRENT_STAGING_DIR/README.md << 'README_EOF' |
252 | | -## Coding Environment |
253 | | -
|
254 | | -Executes Python code in a sandboxed environment with safety checks. |
255 | | -
|
256 | | -### Usage |
257 | | -Send a POST request to `/step` with: |
258 | | -```json |
259 | | -{ |
260 | | - "code": "print('Hello World')" |
261 | | -} |
262 | | -``` |
263 | | -README_EOF |
264 | | - ;; |
265 | | - "chat_env") |
266 | | - cat >> $CURRENT_STAGING_DIR/README.md << 'README_EOF' |
267 | | -## Chat Environment |
268 | | -
|
269 | | -Provides a chat-based interface for LLMs with tokenization support. |
270 | | -
|
271 | | -### Usage |
272 | | -Send a POST request to `/step` with tokenized input: |
273 | | -```json |
274 | | -{ |
275 | | - "tokens": [1, 2, 3, 4, 5] |
276 | | -} |
277 | | -``` |
278 | | -README_EOF |
279 | | - ;; |
280 | | - "atari_env") |
281 | | - cat >> $CURRENT_STAGING_DIR/README.md << 'README_EOF' |
282 | | -## Atari Environment |
283 | | -
|
284 | | -Provides Atari 2600 games via the Arcade Learning Environment (ALE). |
285 | | -
|
286 | | -### Usage |
287 | | -Send a POST request to `/step` with: |
288 | | -```json |
289 | | -{ |
290 | | - "action_id": 0, |
291 | | - "game_name": "pong" |
292 | | -} |
| 133 | +# Connect to this HF Space |
| 134 | +env = ENV_CLASS_PLACEHOLDER(base_url="https://huggingface.co/spaces/openenv/ENV_NAME_PLACEHOLDER") |
| 135 | +
|
| 136 | +# Use the environment |
| 137 | +result = env.reset() |
| 138 | +result = env.step(action) |
293 | 139 | ``` |
294 | | -README_EOF |
295 | | - ;; |
296 | | - "openspiel_env") |
297 | | - cat >> $CURRENT_STAGING_DIR/README.md << 'README_EOF' |
298 | | -## OpenSpiel Environment |
299 | | -
|
300 | | -Provides access to OpenSpiel games for multi-agent reinforcement learning. |
301 | | -
|
302 | | -### Usage |
303 | | -Send a POST request to `/step` with: |
304 | | -```json |
305 | | -{ |
306 | | - "action": { |
307 | | - "action_id": 1 |
308 | | - } |
309 | | -} |
310 | | -README_EOF |
311 | | - ;; |
312 | | - esac |
313 | 140 |
|
314 | | - cat >> $CURRENT_STAGING_DIR/README.md << 'README_EOF' |
| 141 | +For full documentation, see the [OpenEnv repository](https://github.com/meta-pytorch/OpenEnv). |
315 | 142 |
|
316 | | -## API Documentation |
| 143 | +README_EOF |
317 | 144 |
|
318 | | -Visit `/docs` for interactive API documentation. |
| 145 | + # Append the rest of the original README (skip front matter) |
| 146 | + tail -n "+$((closing_line + 1))" "$readme_source" >> "$CURRENT_STAGING_DIR/README.md" |
| 147 | + else |
| 148 | + echo "Error: README missing HF front matter at $readme_source" |
| 149 | + echo "Please add YAML front matter to the environment README" |
| 150 | + exit 1 |
| 151 | + fi |
319 | 152 |
|
320 | | -## Health Check |
| 153 | + # Set environment-specific class name |
| 154 | + case $env_name in |
| 155 | + "echo_env") ENV_CLASS="EchoEnv" ;; |
| 156 | + "coding_env") ENV_CLASS="CodingEnv" ;; |
| 157 | + "chat_env") ENV_CLASS="ChatEnv" ;; |
| 158 | + "atari_env") ENV_CLASS="AtariEnv" ;; |
| 159 | + "openspiel_env") ENV_CLASS="OpenSpielEnv" ;; |
| 160 | + *) ENV_CLASS="Env" ;; |
| 161 | + esac |
321 | 162 |
|
322 | | -The environment provides a health check endpoint at `/health`. |
323 | | -README_EOF |
| 163 | + # Replace placeholders (cross-platform) |
| 164 | + sed_inplace "s/ENV_NAME_PLACEHOLDER/$env_name/g" "$CURRENT_STAGING_DIR/README.md" |
| 165 | + sed_inplace "s/ENV_CLASS_PLACEHOLDER/$ENV_CLASS/g" "$CURRENT_STAGING_DIR/README.md" |
324 | 166 | } |
325 | 167 |
|
326 | 168 | create_readme $ENV_NAME |
327 | | -echo "Created README for HF Space" |
| 169 | +echo "Copied and enhanced README for HF Space" |
328 | 170 | echo "Completed preparation for $ENV_NAME environment" |
0 commit comments