akhaliq HF Staff commited on
Commit
3d9f57c
Β·
1 Parent(s): ba8977c

Fix backend_deploy: Let HuggingFace auto-create README, only add anycoder tag

Browse files

Issue: Previously was creating README with hardcoded SDK version (4.44.1)
Fix: Follow the original deploy.py pattern

Changes:
- Removed create_minimal_readme() function - not needed
- Don't manually create or upload README.md during deployment
- Let HuggingFace automatically generate README.md with proper defaults
- After deployment, only modify the auto-generated README to add:
* tags: anycoder (preserves all existing content)
* app_port: 7860 (only for Docker spaces)

Deployment flow now:
1. Parse code based on language (html, gradio, streamlit, react, etc.)
2. Write code files to temp directory (no README)
3. Create space with create_repo() - HF auto-generates README
4. Upload files with upload_folder()
5. Wait 2 seconds for README generation
6. Call add_anycoder_tag_to_readme() to modify existing README
7. Preserves all HF defaults (versions, metadata, etc.)

This ensures:
- No hardcoded versions (HF uses latest compatible versions)
- Existing README content is preserved
- Only adds anycoder attribution tag
- Works with all SDK types (static, gradio, docker)

Files changed (1) hide show
  1. backend_deploy.py +89 -47
backend_deploy.py CHANGED
@@ -135,30 +135,78 @@ def detect_sdk_from_code(code: str, language: str) -> str:
135
  return "gradio" # Default
136
 
137
 
138
- def create_space_readme(space_name: str, sdk: str, description: str = None) -> str:
139
- """Create README.md for HuggingFace Space"""
140
- readme = f"""---
141
- title: {space_name}
142
- emoji: πŸš€
143
- colorFrom: blue
144
- colorTo: purple
145
- sdk: {sdk}
146
- sdk_version: 4.44.1
147
- app_file: app.py
148
- pinned: false
149
- """
150
-
151
- if sdk == "docker":
152
- readme += "app_port: 7860\n"
153
-
154
- readme += "---\n\n"
155
-
156
- if description:
157
- readme += f"{description}\n\n"
158
- else:
159
- readme += f"# {space_name}\n\nBuilt with [anycoder](https://huggingface.co/spaces/akhaliq/anycoder)\n"
160
 
161
- return readme
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
 
163
 
164
  def create_dockerfile_for_streamlit(space_name: str) -> str:
@@ -259,6 +307,8 @@ def deploy_to_huggingface_space(
259
  temp_path = Path(temp_dir)
260
 
261
  # Parse code based on language
 
 
262
  if language == "transformers.js":
263
  files = parse_transformers_js_output(code)
264
 
@@ -266,26 +316,14 @@ def deploy_to_huggingface_space(
266
  for filename, content in files.items():
267
  (temp_path / filename).write_text(content, encoding='utf-8')
268
 
269
- # Create README
270
- readme = create_space_readme(space_name, "static", description)
271
- (temp_path / "README.md").write_text(readme, encoding='utf-8')
272
-
273
  elif language == "html":
274
  html_code = parse_html_code(code)
275
  (temp_path / "index.html").write_text(html_code, encoding='utf-8')
276
 
277
- # Create README
278
- readme = create_space_readme(space_name, "static", description)
279
- (temp_path / "README.md").write_text(readme, encoding='utf-8')
280
-
281
  elif language == "comfyui":
282
  # ComfyUI is JSON, wrap in HTML viewer
283
  (temp_path / "index.html").write_text(code, encoding='utf-8')
284
 
285
- # Create README
286
- readme = create_space_readme(space_name, "static", description)
287
- (temp_path / "README.md").write_text(readme, encoding='utf-8')
288
-
289
  elif language in ["gradio", "streamlit"]:
290
  files = parse_multi_file_python_output(code)
291
 
@@ -305,10 +343,7 @@ def deploy_to_huggingface_space(
305
  if language == "streamlit":
306
  dockerfile = create_dockerfile_for_streamlit(space_name)
307
  (temp_path / "Dockerfile").write_text(dockerfile, encoding='utf-8')
308
-
309
- # Create README
310
- readme = create_space_readme(space_name, sdk, description)
311
- (temp_path / "README.md").write_text(readme, encoding='utf-8')
312
 
313
  elif language == "react":
314
  # For React, we'd need package.json and other files
@@ -321,10 +356,7 @@ def deploy_to_huggingface_space(
321
  # Create Dockerfile
322
  dockerfile = create_dockerfile_for_react(space_name)
323
  (temp_path / "Dockerfile").write_text(dockerfile, encoding='utf-8')
324
-
325
- # Create README
326
- readme = create_space_readme(space_name, "docker", description)
327
- (temp_path / "README.md").write_text(readme, encoding='utf-8')
328
 
329
  else:
330
  # Default: treat as Gradio app
@@ -335,10 +367,9 @@ def deploy_to_huggingface_space(
335
 
336
  if "requirements.txt" not in files:
337
  (temp_path / "requirements.txt").write_text("gradio>=4.0.0\n", encoding='utf-8')
338
-
339
- # Create README
340
- readme = create_space_readme(space_name, "gradio", description)
341
- (temp_path / "README.md").write_text(readme, encoding='utf-8')
342
 
343
  # Create the space
344
  try:
@@ -367,6 +398,17 @@ def deploy_to_huggingface_space(
367
  except Exception as e:
368
  return False, f"Failed to upload files: {str(e)}", None
369
 
 
 
 
 
 
 
 
 
 
 
 
370
  space_url = f"https://huggingface.co/spaces/{repo_id}"
371
  return True, f"βœ… Successfully deployed to {repo_id}!", space_url
372
 
 
135
  return "gradio" # Default
136
 
137
 
138
+ def add_anycoder_tag_to_readme(api, repo_id: str, app_port: Optional[int] = None) -> None:
139
+ """
140
+ Download existing README, add anycoder tag and app_port if needed, and upload back.
141
+ Preserves all existing README content and frontmatter.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
142
 
143
+ Args:
144
+ api: HuggingFace API client
145
+ repo_id: Repository ID (username/space-name)
146
+ app_port: Optional port number to set for Docker spaces (e.g., 7860)
147
+ """
148
+ try:
149
+ import tempfile
150
+ import re
151
+
152
+ # Download the existing README
153
+ readme_path = api.hf_hub_download(
154
+ repo_id=repo_id,
155
+ filename="README.md",
156
+ repo_type="space"
157
+ )
158
+
159
+ # Read the existing README content
160
+ with open(readme_path, 'r', encoding='utf-8') as f:
161
+ content = f.read()
162
+
163
+ # Parse frontmatter and content
164
+ if content.startswith('---'):
165
+ # Split frontmatter and body
166
+ parts = content.split('---', 2)
167
+ if len(parts) >= 3:
168
+ frontmatter = parts[1].strip()
169
+ body = parts[2] if len(parts) > 2 else ""
170
+
171
+ # Check if tags already exist
172
+ if 'tags:' in frontmatter:
173
+ # Add anycoder to existing tags if not present
174
+ if '- anycoder' not in frontmatter:
175
+ frontmatter = re.sub(r'(tags:\s*\n(?:\s*-\s*[^\n]+\n)*)', r'\1- anycoder\n', frontmatter)
176
+ else:
177
+ # Add tags section with anycoder
178
+ frontmatter += '\ntags:\n- anycoder'
179
+
180
+ # Add app_port if specified and not already present
181
+ if app_port is not None and 'app_port:' not in frontmatter:
182
+ frontmatter += f'\napp_port: {app_port}'
183
+
184
+ # Reconstruct the README
185
+ new_content = f"---\n{frontmatter}\n---{body}"
186
+ else:
187
+ # Malformed frontmatter, just add tags at the end of frontmatter
188
+ new_content = content.replace('---', '---\ntags:\n- anycoder\n---', 1)
189
+ else:
190
+ # No frontmatter, add it at the beginning
191
+ app_port_line = f'\napp_port: {app_port}' if app_port else ''
192
+ new_content = f"---\ntags:\n- anycoder{app_port_line}\n---\n\n{content}"
193
+
194
+ # Upload the modified README
195
+ with tempfile.NamedTemporaryFile("w", suffix=".md", delete=False, encoding='utf-8') as f:
196
+ f.write(new_content)
197
+ temp_path = f.name
198
+
199
+ api.upload_file(
200
+ path_or_fileobj=temp_path,
201
+ path_in_repo="README.md",
202
+ repo_id=repo_id,
203
+ repo_type="space"
204
+ )
205
+
206
+ os.unlink(temp_path)
207
+
208
+ except Exception as e:
209
+ print(f"Warning: Could not modify README.md to add anycoder tag: {e}")
210
 
211
 
212
  def create_dockerfile_for_streamlit(space_name: str) -> str:
 
307
  temp_path = Path(temp_dir)
308
 
309
  # Parse code based on language
310
+ app_port = None # Track if we need app_port for Docker spaces
311
+
312
  if language == "transformers.js":
313
  files = parse_transformers_js_output(code)
314
 
 
316
  for filename, content in files.items():
317
  (temp_path / filename).write_text(content, encoding='utf-8')
318
 
 
 
 
 
319
  elif language == "html":
320
  html_code = parse_html_code(code)
321
  (temp_path / "index.html").write_text(html_code, encoding='utf-8')
322
 
 
 
 
 
323
  elif language == "comfyui":
324
  # ComfyUI is JSON, wrap in HTML viewer
325
  (temp_path / "index.html").write_text(code, encoding='utf-8')
326
 
 
 
 
 
327
  elif language in ["gradio", "streamlit"]:
328
  files = parse_multi_file_python_output(code)
329
 
 
343
  if language == "streamlit":
344
  dockerfile = create_dockerfile_for_streamlit(space_name)
345
  (temp_path / "Dockerfile").write_text(dockerfile, encoding='utf-8')
346
+ app_port = 7860 # Set app_port for Docker spaces
 
 
 
347
 
348
  elif language == "react":
349
  # For React, we'd need package.json and other files
 
356
  # Create Dockerfile
357
  dockerfile = create_dockerfile_for_react(space_name)
358
  (temp_path / "Dockerfile").write_text(dockerfile, encoding='utf-8')
359
+ app_port = 7860 # Set app_port for Docker spaces
 
 
 
360
 
361
  else:
362
  # Default: treat as Gradio app
 
367
 
368
  if "requirements.txt" not in files:
369
  (temp_path / "requirements.txt").write_text("gradio>=4.0.0\n", encoding='utf-8')
370
+
371
+ # Don't create README - HuggingFace will auto-generate it
372
+ # We'll add the anycoder tag after deployment
 
373
 
374
  # Create the space
375
  try:
 
398
  except Exception as e:
399
  return False, f"Failed to upload files: {str(e)}", None
400
 
401
+ # After successful upload, modify the auto-generated README to add anycoder tag
402
+ # HuggingFace automatically creates README.md when space is created
403
+ # Wait a moment for it to be generated, then modify it
404
+ try:
405
+ import time
406
+ time.sleep(2) # Give HF time to generate README
407
+ add_anycoder_tag_to_readme(api, repo_id, app_port)
408
+ except Exception as e:
409
+ # Don't fail deployment if README modification fails
410
+ print(f"Warning: Could not add anycoder tag to README: {e}")
411
+
412
  space_url = f"https://huggingface.co/spaces/{repo_id}"
413
  return True, f"βœ… Successfully deployed to {repo_id}!", space_url
414