Skip to content

Commit f6b4dc2

Browse files
authored
Merge pull request #110 from meta-pytorch/mortimer/refactorhfdeploy
cleanup the hf deploy and docker logic
2 parents d8d1f97 + d34e431 commit f6b4dc2

File tree

15 files changed

+272
-272
lines changed

15 files changed

+272
-272
lines changed

scripts/prepare_hf_deployment.sh

Lines changed: 97 additions & 255 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,18 @@
55

66
set -e
77

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+
820
ENV_NAME="$1"
921
BASE_IMAGE_SHA="$2"
1022
STAGING_DIR="hf-staging"
@@ -41,288 +53,118 @@ echo "Copied core files"
4153
cp -r src/envs/$ENV_NAME/* $CURRENT_STAGING_DIR/src/envs/$ENV_NAME/
4254
echo "Copied $ENV_NAME environment files"
4355

44-
# Create environment-specific multi-stage Dockerfile
56+
# Copy and modify the static Dockerfile from the environment
4557
create_environment_dockerfile() {
4658
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"
15288
}
15389

15490
create_environment_dockerfile $ENV_NAME
15591

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
16193
create_readme() {
16294
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"
20096

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
212101

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"
214105

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)
216108

217-
## About
109+
if [ -z "$closing_line" ]; then
110+
echo "Error: Could not find closing --- in front matter"
111+
exit 1
112+
fi
218113

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"
221116

222-
## Web Interface
117+
# Add HF-specific deployment info right after front matter
118+
cat >> $CURRENT_STAGING_DIR/README.md << 'README_EOF'
223119
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
228121
229-
Access the web interface at: \`/web\`
122+
This is a Hugging Face Space deployment of the OpenEnv environment. It includes:
230123
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
232127
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
238129
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
240132
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)
293139
```
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
313140
314-
cat >> $CURRENT_STAGING_DIR/README.md << 'README_EOF'
141+
For full documentation, see the [OpenEnv repository](https://github.com/meta-pytorch/OpenEnv).
315142
316-
## API Documentation
143+
README_EOF
317144

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
319152

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
321162

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"
324166
}
325167

326168
create_readme $ENV_NAME
327-
echo "Created README for HF Space"
169+
echo "Copied and enhanced README for HF Space"
328170
echo "Completed preparation for $ENV_NAME environment"

0 commit comments

Comments
 (0)