jens-l commited on
Commit
e999496
·
1 Parent(s): 054e267

Fix Docker Space deployment: simplify architecture for HF Spaces

Browse files
Files changed (5) hide show
  1. Dockerfile +19 -20
  2. Dockerfile.complex +54 -0
  3. README.md +2 -2
  4. app.py +25 -121
  5. supervisord.conf +4 -2
Dockerfile CHANGED
@@ -1,32 +1,31 @@
1
  FROM python:3.12-slim
2
 
3
- # Install nginx and other dependencies
4
- RUN apt-get update && apt-get install -y \
5
- nginx \
6
- supervisor \
7
- && rm -rf /var/lib/apt/lists/*
8
 
9
- # Set working directory
10
- WORKDIR /app
11
 
12
- # Copy requirements and install Python dependencies
13
- COPY requirements.txt .
14
- RUN pip install --no-cache-dir -r requirements.txt
15
 
16
- # Copy application code
17
- COPY . .
18
 
19
- # Copy nginx configuration
20
- COPY nginx.conf /etc/nginx/nginx.conf
 
21
 
22
- # Copy supervisor configuration
23
- COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
24
 
25
- # Create necessary directories
26
- RUN mkdir -p /var/log/supervisor
 
27
 
28
  # Expose port 7860 (the only port HF Spaces allows)
29
  EXPOSE 7860
30
 
31
- # Start supervisor (which will start nginx, main app, and preview app)
32
- CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
 
1
  FROM python:3.12-slim
2
 
3
+ # Set up a new user named "user" with user ID 1000 (required by HF Spaces)
4
+ RUN useradd -m -u 1000 user
 
 
 
5
 
6
+ # Switch to the "user" user
7
+ USER user
8
 
9
+ # Set home to the user's home directory
10
+ ENV HOME=/home/user \
11
+ PATH=/home/user/.local/bin:$PATH
12
 
13
+ # Set the working directory to the user's home directory
14
+ WORKDIR $HOME/app
15
 
16
+ # Copy requirements and install Python dependencies
17
+ COPY --chown=user requirements.txt .
18
+ RUN pip install --no-cache-dir --upgrade -r requirements.txt
19
 
20
+ # Copy application code
21
+ COPY --chown=user . .
22
 
23
+ # Create sandbox directory if it doesn't exist and add a dummy app.py
24
+ RUN mkdir -p sandbox && \
25
+ echo 'import gradio as gr; gr.Interface(lambda x: "Preview not available", "text", "text").launch(server_port=7861, server_name="0.0.0.0")' > sandbox/app.py
26
 
27
  # Expose port 7860 (the only port HF Spaces allows)
28
  EXPOSE 7860
29
 
30
+ # Start the main application directly
31
+ CMD ["python", "app.py"]
Dockerfile.complex ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.12-slim
2
+
3
+ # Set up a new user named "user" with user ID 1000 (required by HF Spaces)
4
+ RUN useradd -m -u 1000 user
5
+
6
+ # Switch to the "user" user
7
+ USER user
8
+
9
+ # Set home to the user's home directory
10
+ ENV HOME=/home/user \
11
+ PATH=/home/user/.local/bin:$PATH
12
+
13
+ # Set the working directory to the user's home directory
14
+ WORKDIR $HOME/app
15
+
16
+ # Install system dependencies as root first
17
+ USER root
18
+ RUN apt-get update && apt-get install -y \
19
+ nginx \
20
+ supervisor \
21
+ && rm -rf /var/lib/apt/lists/*
22
+
23
+ # Switch back to user
24
+ USER user
25
+
26
+ # Copy requirements and install Python dependencies
27
+ COPY --chown=user requirements.txt .
28
+ RUN pip install --no-cache-dir --upgrade -r requirements.txt
29
+
30
+ # Copy application code
31
+ COPY --chown=user . .
32
+
33
+ # Switch to root to configure nginx and supervisor
34
+ USER root
35
+
36
+ # Copy nginx configuration
37
+ COPY --chown=root nginx.conf /etc/nginx/nginx.conf
38
+
39
+ # Copy supervisor configuration
40
+ COPY --chown=root supervisord.conf /etc/supervisor/conf.d/supervisord.conf
41
+
42
+ # Create necessary directories
43
+ RUN mkdir -p /var/log/supervisor
44
+
45
+ # Create sandbox directory if it doesn't exist and add a dummy app.py
46
+ RUN mkdir -p $HOME/app/sandbox
47
+ RUN echo 'import gradio as gr; gr.Interface(lambda x: "Preview not available", "text", "text").launch(server_port=7861, server_name="0.0.0.0")' > $HOME/app/sandbox/app.py
48
+ RUN chown -R user:user $HOME/app/sandbox
49
+
50
+ # Expose port 7860 (the only port HF Spaces allows)
51
+ EXPOSE 7860
52
+
53
+ # Start supervisor (which will start nginx, main app, and preview app)
54
+ CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
README.md CHANGED
@@ -26,6 +26,6 @@ A powerful AI coding assistant that can create and preview Gradio applications i
26
  3. View the live preview in the Preview tab
27
  4. Edit code directly in the Code tab
28
 
29
- ## Architecture
30
 
31
- This Space uses nginx as a reverse proxy to serve both the main application and preview applications on a single port, making it compatible with Hugging Face Spaces' single-port limitation.
 
26
  3. View the live preview in the Preview tab
27
  4. Edit code directly in the Code tab
28
 
29
+ ## Docker Deployment
30
 
31
+ This Space runs a simplified Docker configuration optimized for Hugging Face Spaces, with the main Gradio application running directly on port 7860.
app.py CHANGED
@@ -1,11 +1,9 @@
1
  import os
2
  import subprocess
3
- import sys
4
  import time
5
  from pathlib import Path
6
 
7
  import gradio as gr
8
- import requests
9
  from smolagents.agents import MultiStepAgent
10
 
11
  # from src.manager_agent import GradioManagerAgent
@@ -18,16 +16,8 @@ PREVIEW_PORT = 7861 # Different port from main app
18
 
19
  def get_preview_url():
20
  """Get the appropriate preview URL based on environment."""
21
- # For Hugging Face Spaces with nginx proxy, use the /preview/ path
22
- if os.getenv("SPACE_ID") or os.getenv("HF_SPACE"):
23
- return "/preview/"
24
- # Check if running in Docker
25
- elif os.path.exists("/.dockerenv") or os.getenv("DOCKER_CONTAINER"):
26
- # In Docker with nginx proxy, use relative path
27
- return "/preview/"
28
- else:
29
- # Local development
30
- return f"http://localhost:{PREVIEW_PORT}"
31
 
32
 
33
  PREVIEW_URL = os.getenv("PREVIEW_URL", get_preview_url())
@@ -96,120 +86,39 @@ def stop_preview_app():
96
 
97
  def start_preview_app():
98
  """Start the preview app in a subprocess."""
99
- # In HF Spaces, preview app runs as separate service via supervisor
100
- if os.getenv("SPACE_ID") or os.getenv("HF_SPACE"):
101
- print("Preview app managed by supervisor in HF Spaces")
102
- return True, "Preview app running via supervisor"
103
-
104
- global preview_process
105
-
106
- # Stop any existing preview app
107
- stop_preview_app()
108
-
109
- app_path = find_app_py_in_sandbox()
110
-
111
- if not app_path or not os.path.exists(app_path):
112
- error_msg = "No app.py found in sandbox directory or its subfolders"
113
- print(f"❌ Preview Error: {error_msg}")
114
- return False, error_msg
115
-
116
- try:
117
- print(f"🚀 Starting preview app from: {app_path}")
118
- # Start the subprocess to run the sandbox app
119
- preview_process = subprocess.Popen(
120
- [
121
- sys.executable,
122
- app_path,
123
- "--server-port",
124
- str(PREVIEW_PORT),
125
- "--server-name",
126
- "0.0.0.0",
127
- ],
128
- stdout=subprocess.PIPE,
129
- stderr=subprocess.PIPE,
130
- text=True,
131
- )
132
-
133
- # Wait a moment for the server to start
134
- time.sleep(2)
135
-
136
- # Check if the process is still running
137
- if preview_process.poll() is not None:
138
- # Process has terminated, read the error
139
- stdout, stderr = preview_process.communicate()
140
- error_msg = f"App failed to start:\n{stderr}\n{stdout}"
141
- print(f"❌ Preview Error: {error_msg}")
142
- return False, error_msg
143
-
144
- # Try to verify the server is responding
145
- max_retries = 10
146
- for i in range(max_retries):
147
- try:
148
- response = requests.get(f"http://localhost:{PREVIEW_PORT}", timeout=1)
149
- if response.status_code == 200:
150
- print(
151
- f"✅ Preview app started successfully on \
152
- localhost:{PREVIEW_PORT}"
153
- )
154
- return True, "App started successfully"
155
- except requests.exceptions.RequestException:
156
- print(
157
- f"🔄 Attempt {i+1}/{max_retries}: Waiting for server to respond..."
158
- )
159
- pass
160
- time.sleep(0.5)
161
-
162
- print(
163
- f"⚠️ Preview app started but may not be fully ready. \
164
- Check localhost:{PREVIEW_PORT}"
165
- )
166
- return True, "App started successfully"
167
-
168
- except Exception as e:
169
- error_msg = f"Error starting app: {str(e)}"
170
- print(f"❌ Preview Error: {error_msg}")
171
- return False, error_msg
172
 
173
 
174
  def create_iframe_preview():
175
  """Create a simple iframe for the preview."""
176
- print("🔄 Creating iframe preview...")
177
- # Start the preview app
178
- success, message = start_preview_app()
179
-
180
- if not success:
181
- print(f" Failed to create preview iframe: {message}")
182
- return f'<div style="padding: 20px; color: red;">\
183
- Failed to start preview: {message}\
184
- </div>'
185
-
186
- print(" Simple iframe preview created")
187
- return f'<iframe src="{PREVIEW_URL}" width="100%" height="600px" frameborder="0">\
188
- </iframe>'
 
189
 
190
 
191
  def is_preview_running():
192
  """Check if the preview app is running and accessible."""
193
- # In HF Spaces, assume preview app is always running via supervisor
194
- if os.getenv("SPACE_ID") or os.getenv("HF_SPACE"):
195
- return True
196
-
197
- global preview_process
198
- if preview_process is None or preview_process.poll() is not None:
199
- return False
200
-
201
- try:
202
- response = requests.get(f"http://localhost:{PREVIEW_PORT}", timeout=2)
203
- return response.status_code == 200
204
- except requests.exceptions.RequestException:
205
- return False
206
 
207
 
208
  def ensure_preview_running():
209
  """Ensure the preview app is running, start it if needed."""
210
- if not is_preview_running():
211
- print("Preview app not running, starting...")
212
- start_preview_app()
213
 
214
 
215
  def get_default_model_for_provider(provider: str) -> str:
@@ -696,12 +605,7 @@ if __name__ == "__main__":
696
 
697
  agent = KISSAgent()
698
 
699
- # Determine port based on environment
700
- if os.getenv("SPACE_ID") or os.getenv("HF_SPACE"):
701
- # In HF Spaces, run on 7862 (nginx will proxy to 7860)
702
- port = 7862
703
- else:
704
- # Local development
705
- port = 7860
706
 
707
  GradioUI(agent).launch(share=False, server_name="0.0.0.0", server_port=port)
 
1
  import os
2
  import subprocess
 
3
  import time
4
  from pathlib import Path
5
 
6
  import gradio as gr
 
7
  from smolagents.agents import MultiStepAgent
8
 
9
  # from src.manager_agent import GradioManagerAgent
 
16
 
17
  def get_preview_url():
18
  """Get the appropriate preview URL based on environment."""
19
+ # For simplified HF Spaces deployment, preview is handled differently
20
+ return "about:blank"
 
 
 
 
 
 
 
 
21
 
22
 
23
  PREVIEW_URL = os.getenv("PREVIEW_URL", get_preview_url())
 
86
 
87
  def start_preview_app():
88
  """Start the preview app in a subprocess."""
89
+ # For HF Spaces simplified deployment, return a simple success message
90
+ print(" Preview functionality simplified for HF Spaces")
91
+ return True, "Preview functionality available in main app"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
 
93
 
94
  def create_iframe_preview():
95
  """Create a simple iframe for the preview."""
96
+ print("🔄 Creating simplified preview for HF Spaces...")
97
+
98
+ # For HF Spaces, return a simple message instead of complex iframe
99
+ return (
100
+ '<div style="padding: 20px; text-align: center; '
101
+ "background-color: #f8f9fa; border: 1px solid #e9ecef; "
102
+ 'border-radius: 8px;">'
103
+ "<h3>📱 Preview</h3>"
104
+ "<p>Code preview functionality is integrated into the main "
105
+ "application interface.</p>"
106
+ "<p>Generated applications will be available after creation "
107
+ "by the AI assistant.</p>"
108
+ "</div>"
109
+ )
110
 
111
 
112
  def is_preview_running():
113
  """Check if the preview app is running and accessible."""
114
+ # For simplified deployment, always return True
115
+ return True
 
 
 
 
 
 
 
 
 
 
 
116
 
117
 
118
  def ensure_preview_running():
119
  """Ensure the preview app is running, start it if needed."""
120
+ # For simplified deployment, nothing needed
121
+ pass
 
122
 
123
 
124
  def get_default_model_for_provider(provider: str) -> str:
 
605
 
606
  agent = KISSAgent()
607
 
608
+ # For HF Spaces, always use port 7860 directly (simplified approach)
609
+ port = 7860
 
 
 
 
 
610
 
611
  GradioUI(agent).launch(share=False, server_name="0.0.0.0", server_port=port)
supervisord.conf CHANGED
@@ -11,17 +11,19 @@ stderr_logfile=/var/log/supervisor/nginx.log
11
 
12
  [program:main_app]
13
  command=python app.py
14
- directory=/app
15
  autostart=true
16
  autorestart=true
 
17
  stdout_logfile=/var/log/supervisor/main_app.log
18
  stderr_logfile=/var/log/supervisor/main_app.log
19
  environment=HF_SPACE="1",GRADIO_SERVER_PORT="7862",GRADIO_SERVER_NAME="0.0.0.0"
20
 
21
  [program:preview_app]
22
  command=python sandbox/app.py --server-port 7861 --server-name 0.0.0.0
23
- directory=/app
24
  autostart=true
25
  autorestart=true
 
26
  stdout_logfile=/var/log/supervisor/preview_app.log
27
  stderr_logfile=/var/log/supervisor/preview_app.log
 
11
 
12
  [program:main_app]
13
  command=python app.py
14
+ directory=/home/user/app
15
  autostart=true
16
  autorestart=true
17
+ user=user
18
  stdout_logfile=/var/log/supervisor/main_app.log
19
  stderr_logfile=/var/log/supervisor/main_app.log
20
  environment=HF_SPACE="1",GRADIO_SERVER_PORT="7862",GRADIO_SERVER_NAME="0.0.0.0"
21
 
22
  [program:preview_app]
23
  command=python sandbox/app.py --server-port 7861 --server-name 0.0.0.0
24
+ directory=/home/user/app
25
  autostart=true
26
  autorestart=true
27
+ user=user
28
  stdout_logfile=/var/log/supervisor/preview_app.log
29
  stderr_logfile=/var/log/supervisor/preview_app.log