akhaliq HF Staff commited on
Commit
cb0c0c1
Β·
1 Parent(s): 84be902

update streamlit issue

Browse files
Files changed (2) hide show
  1. anycoder_app/prompts.py +82 -31
  2. anycoder_app/ui.py +97 -72
anycoder_app/prompts.py CHANGED
@@ -98,15 +98,16 @@ STREAMLIT_SYSTEM_PROMPT = """You are an expert Streamlit developer. Create a com
98
 
99
  ## Multi-File Application Structure
100
 
101
- When creating complex Streamlit applications, organize your code into multiple files for better maintainability:
102
-
103
- **File Organization:**
104
- - `app.py` or `streamlit_app.py` - Main application entry point
105
- - `utils.py` - Utility functions and helpers
106
- - `models.py` - Model loading and inference functions
107
- - `config.py` - Configuration and constants
108
- - `requirements.txt` - Python dependencies
109
- - `pages/` - Additional pages for multi-page apps
 
110
  - Additional modules as needed (e.g., `data_processing.py`, `components.py`)
111
 
112
  **🚨 CRITICAL: DO NOT Generate README.md Files**
@@ -115,18 +116,70 @@ When creating complex Streamlit applications, organize your code into multiple f
115
  - Generating a README.md will break the deployment process
116
  - Only generate the code files listed above
117
 
118
- **Output Format for Multi-File Apps:**
119
- When generating multi-file applications, use this exact format:
120
 
121
  ```
 
 
 
122
  === streamlit_app.py ===
123
  [main application code]
124
 
125
- === utils.py ===
126
- [utility functions]
127
-
128
  === requirements.txt ===
129
  [dependencies]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  ```
131
 
132
  **🚨 CRITICAL: requirements.txt Formatting Rules**
@@ -146,21 +199,18 @@ When generating multi-file applications, use this exact format:
146
  - pandas
147
  ```
148
 
149
- **Single vs Multi-File Decision:**
150
- - Use single file for simple applications (< 100 lines) - but still generate requirements.txt if dependencies exist
151
- - Use multi-file structure for complex applications with:
152
- - Multiple pages or sections
153
- - Extensive data processing
154
- - Complex UI components
155
- - Multiple models or APIs
156
- - When user specifically requests modular structure
157
-
158
  **Multi-Page Apps:**
159
  For multi-page Streamlit apps, use the pages/ directory structure:
160
  ```
 
 
 
161
  === streamlit_app.py ===
162
  [main page]
163
 
 
 
 
164
  === pages/1_πŸ“Š_Analytics.py ===
165
  [analytics page]
166
 
@@ -169,14 +219,15 @@ For multi-page Streamlit apps, use the pages/ directory structure:
169
  ```
170
 
171
  Requirements:
172
- 1. Create a modern, responsive Streamlit application
173
- 2. Use appropriate Streamlit components and layouts
174
- 3. Include proper error handling and loading states
175
- 4. Follow Streamlit best practices for performance
176
- 5. Use caching (@st.cache_data, @st.cache_resource) appropriately
177
- 6. Include proper session state management when needed
178
- 7. Make the UI intuitive and user-friendly
179
- 8. Add helpful tooltips and documentation
 
180
 
181
  IMPORTANT: Always include "Built with anycoder" as clickable text in the header/top section of your application that links to https://huggingface.co/spaces/akhaliq/anycoder
182
  """
 
98
 
99
  ## Multi-File Application Structure
100
 
101
+ When creating Streamlit applications, you MUST organize your code into multiple files for proper deployment:
102
+
103
+ **File Organization (CRITICAL - Always Include These):**
104
+ - `Dockerfile` - Docker configuration for deployment (REQUIRED)
105
+ - `streamlit_app.py` - Main application entry point (REQUIRED)
106
+ - `requirements.txt` - Python dependencies (REQUIRED)
107
+ - `utils.py` - Utility functions and helpers (optional)
108
+ - `models.py` - Model loading and inference functions (optional)
109
+ - `config.py` - Configuration and constants (optional)
110
+ - `pages/` - Additional pages for multi-page apps (optional)
111
  - Additional modules as needed (e.g., `data_processing.py`, `components.py`)
112
 
113
  **🚨 CRITICAL: DO NOT Generate README.md Files**
 
116
  - Generating a README.md will break the deployment process
117
  - Only generate the code files listed above
118
 
119
+ **Output Format for Streamlit Apps:**
120
+ You MUST use this exact format and ALWAYS include Dockerfile, streamlit_app.py, and requirements.txt:
121
 
122
  ```
123
+ === Dockerfile ===
124
+ [Dockerfile content]
125
+
126
  === streamlit_app.py ===
127
  [main application code]
128
 
 
 
 
129
  === requirements.txt ===
130
  [dependencies]
131
+
132
+ === utils.py ===
133
+ [utility functions - optional]
134
+ ```
135
+
136
+ **🚨 CRITICAL: Dockerfile Requirements (MANDATORY for HuggingFace Spaces)**
137
+ Your Dockerfile MUST follow these exact specifications:
138
+ - Use Python 3.11+ base image (e.g., FROM python:3.11-slim)
139
+ - Set up a user with ID 1000 for proper permissions:
140
+ ```
141
+ RUN useradd -m -u 1000 user
142
+ USER user
143
+ ENV HOME=/home/user \\
144
+ PATH=/home/user/.local/bin:$PATH
145
+ WORKDIR $HOME/app
146
+ ```
147
+ - ALWAYS use --chown=user with COPY and ADD commands:
148
+ ```
149
+ COPY --chown=user requirements.txt .
150
+ COPY --chown=user . .
151
+ ```
152
+ - Install dependencies: RUN pip install --no-cache-dir -r requirements.txt
153
+ - Expose port 7860 (HuggingFace Spaces default): EXPOSE 7860
154
+ - Start with: CMD ["streamlit", "run", "streamlit_app.py", "--server.port=7860", "--server.address=0.0.0.0"]
155
+
156
+ **Example Dockerfile structure (USE THIS AS TEMPLATE):**
157
+ ```dockerfile
158
+ FROM python:3.11-slim
159
+
160
+ # Set up user with ID 1000
161
+ RUN useradd -m -u 1000 user
162
+ USER user
163
+ ENV HOME=/home/user \\
164
+ PATH=/home/user/.local/bin:$PATH
165
+
166
+ # Set working directory
167
+ WORKDIR $HOME/app
168
+
169
+ # Copy requirements file with proper ownership
170
+ COPY --chown=user requirements.txt .
171
+
172
+ # Install dependencies
173
+ RUN pip install --no-cache-dir -r requirements.txt
174
+
175
+ # Copy application files with proper ownership
176
+ COPY --chown=user . .
177
+
178
+ # Expose port 7860
179
+ EXPOSE 7860
180
+
181
+ # Start Streamlit app
182
+ CMD ["streamlit", "run", "streamlit_app.py", "--server.port=7860", "--server.address=0.0.0.0"]
183
  ```
184
 
185
  **🚨 CRITICAL: requirements.txt Formatting Rules**
 
199
  - pandas
200
  ```
201
 
 
 
 
 
 
 
 
 
 
202
  **Multi-Page Apps:**
203
  For multi-page Streamlit apps, use the pages/ directory structure:
204
  ```
205
+ === Dockerfile ===
206
+ [Dockerfile content]
207
+
208
  === streamlit_app.py ===
209
  [main page]
210
 
211
+ === requirements.txt ===
212
+ [dependencies]
213
+
214
  === pages/1_πŸ“Š_Analytics.py ===
215
  [analytics page]
216
 
 
219
  ```
220
 
221
  Requirements:
222
+ 1. ALWAYS include Dockerfile, streamlit_app.py, and requirements.txt in your output
223
+ 2. Create a modern, responsive Streamlit application
224
+ 3. Use appropriate Streamlit components and layouts
225
+ 4. Include proper error handling and loading states
226
+ 5. Follow Streamlit best practices for performance
227
+ 6. Use caching (@st.cache_data, @st.cache_resource) appropriately
228
+ 7. Include proper session state management when needed
229
+ 8. Make the UI intuitive and user-friendly
230
+ 9. Add helpful tooltips and documentation
231
 
232
  IMPORTANT: Always include "Built with anycoder" as clickable text in the header/top section of your application that links to https://huggingface.co/spaces/akhaliq/anycoder
233
  """
anycoder_app/ui.py CHANGED
@@ -1161,85 +1161,110 @@ with gr.Blocks(
1161
  action_text = "Updated" if is_update else "Deployed"
1162
  return gr.update(value=f"βœ… {action_text}! [Open your React Space here]({space_url})", visible=True)
1163
 
1164
- # Streamlit logic
1165
- # Generate requirements.txt for Streamlit apps and upload only if needed
1166
- import_statements = extract_import_statements(code)
1167
- requirements_content = generate_requirements_txt_with_llm(import_statements)
 
 
 
 
 
 
 
 
1168
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1169
  import tempfile
 
1170
 
1171
- # Check if we need to upload requirements.txt
1172
- should_upload_requirements = True
1173
- if is_update:
1174
- try:
1175
- # Try to get existing requirements.txt content
1176
- existing_requirements = api.hf_hub_download(
1177
- repo_id=repo_id,
1178
- filename="requirements.txt",
1179
- repo_type="space"
1180
- )
1181
- with open(existing_requirements, 'r') as f:
1182
- existing_content = f.read().strip()
1183
 
1184
- # Compare with new content
1185
- if existing_content == requirements_content.strip():
1186
- should_upload_requirements = False
 
 
 
 
 
 
 
 
1187
 
1188
- except Exception:
1189
- # File doesn't exist or can't be accessed, so we should upload
1190
- should_upload_requirements = True
1191
-
1192
- # Upload requirements.txt only if needed
1193
- if should_upload_requirements:
1194
- try:
1195
- with tempfile.NamedTemporaryFile("w", suffix=".txt", delete=False) as f:
1196
- f.write(requirements_content)
1197
- requirements_temp_path = f.name
1198
-
1199
- api.upload_file(
1200
- path_or_fileobj=requirements_temp_path,
1201
- path_in_repo="requirements.txt",
1202
- repo_id=repo_id,
1203
- repo_type="space"
1204
- )
1205
- except Exception as e:
1206
- error_msg = str(e)
1207
- if "403 Forbidden" in error_msg and "write token" in error_msg:
1208
- return gr.update(value=f"Error uploading requirements.txt: Permission denied. Please ensure you have write access to {repo_id} and your token has the correct permissions.", visible=True)
1209
- else:
1210
- return gr.update(value=f"Error uploading requirements.txt: {e}", visible=True)
1211
- finally:
1212
- import os
1213
- if 'requirements_temp_path' in locals():
1214
- os.unlink(requirements_temp_path)
1215
-
1216
- # Add anycoder tag to existing README
1217
- add_anycoder_tag_to_readme(api, repo_id)
1218
 
1219
- # Upload the user's code to src/streamlit_app.py (for both new and existing spaces)
1220
- with tempfile.NamedTemporaryFile("w", suffix=".py", delete=False) as f:
1221
- f.write(code)
1222
- temp_path = f.name
1223
 
1224
- try:
1225
- api.upload_file(
1226
- path_or_fileobj=temp_path,
1227
- path_in_repo="src/streamlit_app.py",
1228
- repo_id=repo_id,
1229
- repo_type="space"
1230
- )
1231
- space_url = f"https://huggingface.co/spaces/{repo_id}"
1232
- action_text = "Updated" if is_update else "Deployed"
1233
- return gr.update(value=f"βœ… {action_text}! [Open your Space here]({space_url})", visible=True)
1234
- except Exception as e:
1235
- error_msg = str(e)
1236
- if "403 Forbidden" in error_msg and "write token" in error_msg:
1237
- return gr.update(value=f"Error: Permission denied. Please ensure you have write access to {repo_id} and your token has the correct permissions.", visible=True)
1238
- else:
1239
- return gr.update(value=f"Error uploading Streamlit app: {e}", visible=True)
1240
- finally:
1241
- import os
1242
- os.unlink(temp_path)
1243
 
1244
  except Exception as e:
1245
  error_prefix = "Error duplicating Streamlit space" if not is_update else "Error updating Streamlit space"
 
1161
  action_text = "Updated" if is_update else "Deployed"
1162
  return gr.update(value=f"βœ… {action_text}! [Open your React Space here]({space_url})", visible=True)
1163
 
1164
+ # Streamlit logic - Parse multi-file structure
1165
+ files = parse_multi_file_python_output(code)
1166
+ if not files:
1167
+ return gr.update(value="Error: Could not parse Streamlit output. Please regenerate the code.", visible=True)
1168
+
1169
+ # Verify required files exist
1170
+ has_streamlit_app = 'streamlit_app.py' in files or 'app.py' in files
1171
+ has_requirements = 'requirements.txt' in files
1172
+ has_dockerfile = 'Dockerfile' in files
1173
+
1174
+ if not has_streamlit_app:
1175
+ return gr.update(value="Error: Missing streamlit_app.py. Please regenerate the code.", visible=True)
1176
 
1177
+ # If Dockerfile or requirements.txt is missing, generate them
1178
+ if not has_dockerfile:
1179
+ # Generate default Dockerfile
1180
+ files['Dockerfile'] = """FROM python:3.11-slim
1181
+
1182
+ # Set up user with ID 1000
1183
+ RUN useradd -m -u 1000 user
1184
+ USER user
1185
+ ENV HOME=/home/user \\
1186
+ PATH=/home/user/.local/bin:$PATH
1187
+
1188
+ # Set working directory
1189
+ WORKDIR $HOME/app
1190
+
1191
+ # Copy requirements file with proper ownership
1192
+ COPY --chown=user requirements.txt .
1193
+
1194
+ # Install dependencies
1195
+ RUN pip install --no-cache-dir -r requirements.txt
1196
+
1197
+ # Copy application files with proper ownership
1198
+ COPY --chown=user . .
1199
+
1200
+ # Expose port 7860
1201
+ EXPOSE 7860
1202
+
1203
+ # Start Streamlit app
1204
+ CMD ["streamlit", "run", "streamlit_app.py", "--server.port=7860", "--server.address=0.0.0.0"]
1205
+ """
1206
+
1207
+ if not has_requirements:
1208
+ # Generate requirements.txt from imports in the main app file
1209
+ main_app = files.get('streamlit_app.py') or files.get('app.py', '')
1210
+ import_statements = extract_import_statements(main_app)
1211
+ files['requirements.txt'] = generate_requirements_txt_with_llm(import_statements)
1212
+
1213
+ # Upload Streamlit files
1214
  import tempfile
1215
+ import time
1216
 
1217
+ for file_name, file_content in files.items():
1218
+ if not file_content:
1219
+ continue
 
 
 
 
 
 
 
 
 
1220
 
1221
+ success = False
1222
+ last_error = None
1223
+ max_attempts = 3
1224
+
1225
+ for attempt in range(max_attempts):
1226
+ try:
1227
+ # Determine file extension
1228
+ if file_name == 'Dockerfile':
1229
+ suffix = ''
1230
+ else:
1231
+ suffix = f".{file_name.split('.')[-1]}"
1232
 
1233
+ with tempfile.NamedTemporaryFile("w", suffix=suffix, delete=False) as f:
1234
+ f.write(file_content)
1235
+ temp_path = f.name
1236
+
1237
+ api.upload_file(
1238
+ path_or_fileobj=temp_path,
1239
+ path_in_repo=file_name,
1240
+ repo_id=repo_id,
1241
+ repo_type="space"
1242
+ )
1243
+ success = True
1244
+ break
1245
+
1246
+ except Exception as e:
1247
+ last_error = e
1248
+ error_msg = str(e)
1249
+ if "403 Forbidden" in error_msg and "write token" in error_msg:
1250
+ return gr.update(value=f"Error: Permission denied. Please ensure you have write access to {repo_id} and your token has the correct permissions.", visible=True)
1251
+
1252
+ if attempt < max_attempts - 1:
1253
+ time.sleep(2)
1254
+ finally:
1255
+ import os
1256
+ if 'temp_path' in locals():
1257
+ os.unlink(temp_path)
1258
+
1259
+ if not success:
1260
+ return gr.update(value=f"Error uploading {file_name}: {last_error}", visible=True)
 
 
1261
 
1262
+ # Add anycoder tag and app_port to existing README
1263
+ add_anycoder_tag_to_readme(api, repo_id, app_port=7860)
 
 
1264
 
1265
+ space_url = f"https://huggingface.co/spaces/{repo_id}"
1266
+ action_text = "Updated" if is_update else "Deployed"
1267
+ return gr.update(value=f"βœ… {action_text}! [Open your Streamlit Space here]({space_url})", visible=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1268
 
1269
  except Exception as e:
1270
  error_prefix = "Error duplicating Streamlit space" if not is_update else "Error updating Streamlit space"