Spaces:
Running
Running
Fix Docker Space deployment: simplify architecture for HF Spaces
Browse files- Dockerfile +19 -20
- Dockerfile.complex +54 -0
- README.md +2 -2
- app.py +25 -121
- supervisord.conf +4 -2
Dockerfile
CHANGED
@@ -1,32 +1,31 @@
|
|
1 |
FROM python:3.12-slim
|
2 |
|
3 |
-
#
|
4 |
-
RUN
|
5 |
-
nginx \
|
6 |
-
supervisor \
|
7 |
-
&& rm -rf /var/lib/apt/lists/*
|
8 |
|
9 |
-
#
|
10 |
-
|
11 |
|
12 |
-
#
|
13 |
-
|
14 |
-
|
15 |
|
16 |
-
#
|
17 |
-
|
18 |
|
19 |
-
# Copy
|
20 |
-
COPY
|
|
|
21 |
|
22 |
-
# Copy
|
23 |
-
COPY
|
24 |
|
25 |
-
# Create
|
26 |
-
RUN mkdir -p
|
|
|
27 |
|
28 |
# Expose port 7860 (the only port HF Spaces allows)
|
29 |
EXPOSE 7860
|
30 |
|
31 |
-
# Start
|
32 |
-
CMD ["
|
|
|
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 |
-
##
|
30 |
|
31 |
-
This Space
|
|
|
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
|
22 |
-
|
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 |
-
#
|
100 |
-
|
101 |
-
|
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
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
</
|
|
|
189 |
|
190 |
|
191 |
def is_preview_running():
|
192 |
"""Check if the preview app is running and accessible."""
|
193 |
-
#
|
194 |
-
|
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 |
-
|
211 |
-
|
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 |
-
#
|
700 |
-
|
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
|