Spaces:
Running
Fix backend_deploy: Let HuggingFace auto-create README, only add anycoder tag
Browse filesIssue: 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)
- backend_deploy.py +89 -47
|
@@ -135,30 +135,78 @@ def detect_sdk_from_code(code: str, language: str) -> str:
|
|
| 135 |
return "gradio" # Default
|
| 136 |
|
| 137 |
|
| 138 |
-
def
|
| 139 |
-
"""
|
| 140 |
-
|
| 141 |
-
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
| 340 |
-
|
| 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 |
|