akhaliq HF Staff commited on
Commit
eb9b233
Β·
1 Parent(s): df98f56
Files changed (1) hide show
  1. app.py +285 -48
app.py CHANGED
@@ -513,10 +513,10 @@ def create_multimodal_message(text, image=None):
513
 
514
  return {"role": "user", "content": content}
515
 
516
- def apply_search_replace_changes(original_html: str, changes_text: str) -> str:
517
- """Apply search/replace changes to HTML content"""
518
  if not changes_text.strip():
519
- return original_html
520
 
521
  # Split the changes text into individual search/replace blocks
522
  blocks = []
@@ -538,7 +538,7 @@ def apply_search_replace_changes(original_html: str, changes_text: str) -> str:
538
  if current_block.strip():
539
  blocks.append(current_block.strip())
540
 
541
- modified_html = original_html
542
 
543
  for block in blocks:
544
  if not block.strip():
@@ -570,12 +570,12 @@ def apply_search_replace_changes(original_html: str, changes_text: str) -> str:
570
  search_text = '\n'.join(search_lines).strip()
571
  replace_text = '\n'.join(replace_lines).strip()
572
 
573
- if search_text in modified_html:
574
- modified_html = modified_html.replace(search_text, replace_text)
575
  else:
576
- print(f"Warning: Search text not found in HTML: {search_text[:100]}...")
577
 
578
- return modified_html
579
 
580
  # Updated for faster Tavily search and closer prompt usage
581
  # Uses 'advanced' search_depth and auto_parameters=True for speed and relevance
@@ -1094,17 +1094,23 @@ def generation_code(query: Optional[str], image: Optional[gr.Image], file: Optio
1094
  _history = []
1095
  _history = [h for h in _history if isinstance(h, list) and len(h) == 2]
1096
 
1097
- # Check if there's existing HTML content in history to determine if this is a modification request
1098
- has_existing_html = False
1099
  last_assistant_msg = ""
1100
  if _history and len(_history[-1]) > 1:
1101
  last_assistant_msg = _history[-1][1]
1102
- if '<!DOCTYPE html>' in last_assistant_msg or '<html' in last_assistant_msg:
1103
- has_existing_html = True
 
 
 
 
 
 
1104
 
1105
  # Choose system prompt based on context
1106
- if has_existing_html:
1107
- # Use follow-up prompt for modifying existing HTML
1108
  system_prompt = FollowUpSystemPrompt
1109
  else:
1110
  # Use language-specific prompt
@@ -1260,22 +1266,24 @@ This will help me create a better design for you."""
1260
  }
1261
  else:
1262
  clean_code = remove_code_block(content)
1263
- if has_existing_html:
1264
- # Fallback: If the model returns a full HTML file, use it directly
1265
  if clean_code.strip().startswith("<!DOCTYPE html>") or clean_code.strip().startswith("<html"):
 
1266
  yield {
1267
  code_output: gr.update(value=clean_code, language=get_gradio_language(language)),
1268
  history_output: history_to_chatbot_messages(_history),
1269
  sandbox: send_to_sandbox(clean_code) if language == "html" else "<div style='padding:1em;color:#888;text-align:center;'>Preview is only available for HTML. Please download your code using the download button above.</div>",
1270
  }
1271
  else:
1272
- last_html = _history[-1][1] if _history and len(_history[-1]) > 1 else ""
1273
- modified_html = apply_search_replace_changes(last_html, clean_code)
1274
- clean_html = remove_code_block(modified_html)
 
1275
  yield {
1276
- code_output: gr.update(value=clean_html, language=get_gradio_language(language)),
1277
  history_output: history_to_chatbot_messages(_history),
1278
- sandbox: send_to_sandbox(clean_html) if language == "html" else "<div style='padding:1em;color:#888;text-align:center;'>Preview is only available for HTML. Please download your code using the download button above.</div>",
1279
  }
1280
  else:
1281
  yield {
@@ -1307,21 +1315,23 @@ This will help me create a better design for you."""
1307
  sandbox: "<div style='padding:1em;color:#888;text-align:center;'>Error parsing transformers.js output. Please try again.</div>",
1308
  history_output: history_to_chatbot_messages(_history),
1309
  }
1310
- elif has_existing_html:
1311
- # Fallback: If the model returns a full HTML file, use it directly
1312
  final_code = remove_code_block(content)
1313
  if final_code.strip().startswith("<!DOCTYPE html>") or final_code.strip().startswith("<html"):
1314
- clean_html = final_code
 
1315
  else:
1316
- last_html = _history[-1][1] if _history and len(_history[-1]) > 1 else ""
1317
- modified_html = apply_search_replace_changes(last_html, final_code)
1318
- clean_html = remove_code_block(modified_html)
1319
- # Update history with the cleaned HTML
1320
- _history.append([query, clean_html])
 
1321
  yield {
1322
- code_output: clean_html,
1323
  history: _history,
1324
- sandbox: send_to_sandbox(clean_html),
1325
  history_output: history_to_chatbot_messages(_history),
1326
  }
1327
  else:
@@ -1393,6 +1403,114 @@ def deploy_to_spaces_static(code):
1393
  full_url = f"{base_url}?{params}&{files_params}"
1394
  webbrowser.open_new_tab(full_url)
1395
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1396
  # Main application
1397
  with gr.Blocks(
1398
  theme=gr.themes.Base(
@@ -1417,6 +1535,20 @@ with gr.Blocks(
1417
 
1418
  with gr.Sidebar():
1419
  login_button = gr.LoginButton()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1420
  input = gr.Textbox(
1421
  label="What would you like to build?",
1422
  placeholder="Describe your application...",
@@ -1529,6 +1661,44 @@ with gr.Blocks(
1529
  with gr.Tab("History"):
1530
  history_output = gr.Chatbot(show_label=False, height=400, type="messages")
1531
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1532
  # Event handlers
1533
  def update_code_language(language):
1534
  return gr.update(language=get_gradio_language(language))
@@ -1563,6 +1733,13 @@ with gr.Blocks(
1563
  def hide_deploy_components(*args):
1564
  return [gr.Textbox(visible=False), gr.Dropdown(visible=False), gr.Button(visible=False)]
1565
 
 
 
 
 
 
 
 
1566
  btn.click(
1567
  generation_code,
1568
  inputs=[input, image_input, file_input, website_url_input, setting, history, current_model, search_toggle, language_dropdown, provider_state],
@@ -1577,6 +1754,11 @@ with gr.Blocks(
1577
  language_dropdown.change(preview_logic, inputs=[code_output, language_dropdown], outputs=sandbox)
1578
  clear_btn.click(clear_history, outputs=[history, history_output, file_input, website_url_input])
1579
  clear_btn.click(hide_deploy_components, None, [space_name_input, sdk_dropdown, deploy_btn])
 
 
 
 
 
1580
 
1581
  # Deploy to Spaces logic
1582
 
@@ -1592,8 +1774,34 @@ with gr.Blocks(
1592
  return gr.update(value="No code to deploy.", visible=True)
1593
  if profile is None or token is None:
1594
  return gr.update(value="Please log in with your Hugging Face account to deploy to your own Space. Otherwise, use the default deploy (opens in new tab).", visible=True)
1595
- username = profile.username
1596
- repo_id = f"{username}/{space_name.strip()}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1597
  # Map SDK name to HF SDK slug
1598
  sdk_map = {
1599
  "Gradio (Python)": "gradio",
@@ -1602,9 +1810,11 @@ with gr.Blocks(
1602
  "Transformers.js": "static" # Transformers.js uses static SDK
1603
  }
1604
  sdk = sdk_map.get(sdk_name, "gradio")
 
 
1605
  api = HfApi(token=token.token)
1606
- # Only create the repo for non-Transformers.js and non-Streamlit SDKs
1607
- if sdk != "docker" and sdk_name != "Transformers.js":
1608
  try:
1609
  api.create_repo(
1610
  repo_id=repo_id, # e.g. username/space_name
@@ -1615,7 +1825,7 @@ with gr.Blocks(
1615
  except Exception as e:
1616
  return gr.update(value=f"Error creating Space: {e}", visible=True)
1617
  # Streamlit/docker logic
1618
- if sdk == "docker":
1619
  try:
1620
  # Use duplicate_space to create a Streamlit template space
1621
  from huggingface_hub import duplicate_space
@@ -1642,9 +1852,14 @@ with gr.Blocks(
1642
  repo_type="space"
1643
  )
1644
  space_url = f"https://huggingface.co/spaces/{repo_id}"
1645
- return gr.update(value=f"βœ… Deployed! [Open your Space here]({space_url})", visible=True)
 
1646
  except Exception as e:
1647
- return gr.update(value=f"Error uploading Streamlit app: {e}", visible=True)
 
 
 
 
1648
  finally:
1649
  import os
1650
  os.unlink(temp_path)
@@ -1652,7 +1867,7 @@ with gr.Blocks(
1652
  except Exception as e:
1653
  return gr.update(value=f"Error duplicating Streamlit space: {e}", visible=True)
1654
  # Transformers.js logic
1655
- elif sdk_name == "Transformers.js":
1656
  try:
1657
  # Use duplicate_space to create a transformers.js template space
1658
  from huggingface_hub import duplicate_space
@@ -1689,7 +1904,11 @@ with gr.Blocks(
1689
  repo_type="space"
1690
  )
1691
  except Exception as e:
1692
- return gr.update(value=f"Error uploading index.html: {e}", visible=True)
 
 
 
 
1693
  finally:
1694
  import os
1695
  os.unlink(temp_path)
@@ -1707,7 +1926,11 @@ with gr.Blocks(
1707
  repo_type="space"
1708
  )
1709
  except Exception as e:
1710
- return gr.update(value=f"Error uploading index.js: {e}", visible=True)
 
 
 
 
1711
  finally:
1712
  import os
1713
  os.unlink(temp_path)
@@ -1725,9 +1948,14 @@ with gr.Blocks(
1725
  repo_type="space"
1726
  )
1727
  space_url = f"https://huggingface.co/spaces/{repo_id}"
1728
- return gr.update(value=f"βœ… Deployed! [Open your Transformers.js Space here]({space_url})", visible=True)
 
1729
  except Exception as e:
1730
- return gr.update(value=f"Error uploading style.css: {e}", visible=True)
 
 
 
 
1731
  finally:
1732
  import os
1733
  os.unlink(temp_path)
@@ -1753,12 +1981,16 @@ with gr.Blocks(
1753
  repo_type="space"
1754
  )
1755
  space_url = f"https://huggingface.co/spaces/{repo_id}"
1756
- return gr.update(value=f"βœ… Deployed! [Open your Space here]({space_url})", visible=True)
 
1757
  except Exception as e:
1758
- if attempt < max_attempts - 1:
 
 
 
1759
  time.sleep(2) # Wait before retrying
1760
  else:
1761
- return gr.update(value=f"Error uploading file after {max_attempts} attempts: {e}. The Space was created, but the file could not be uploaded. Please try again in a few seconds from the Hugging Face UI.", visible=True)
1762
  finally:
1763
  import os
1764
  os.unlink(temp_path)
@@ -1776,9 +2008,14 @@ with gr.Blocks(
1776
  repo_type="space"
1777
  )
1778
  space_url = f"https://huggingface.co/spaces/{repo_id}"
1779
- return gr.update(value=f"βœ… Deployed! [Open your Space here]({space_url})", visible=True)
 
1780
  except Exception as e:
1781
- return gr.update(value=f"Error uploading file: {e}", visible=True)
 
 
 
 
1782
  finally:
1783
  import os
1784
  os.unlink(temp_path)
 
513
 
514
  return {"role": "user", "content": content}
515
 
516
+ def apply_search_replace_changes(original_content: str, changes_text: str) -> str:
517
+ """Apply search/replace changes to content (HTML, Python, etc.)"""
518
  if not changes_text.strip():
519
+ return original_content
520
 
521
  # Split the changes text into individual search/replace blocks
522
  blocks = []
 
538
  if current_block.strip():
539
  blocks.append(current_block.strip())
540
 
541
+ modified_content = original_content
542
 
543
  for block in blocks:
544
  if not block.strip():
 
570
  search_text = '\n'.join(search_lines).strip()
571
  replace_text = '\n'.join(replace_lines).strip()
572
 
573
+ if search_text in modified_content:
574
+ modified_content = modified_content.replace(search_text, replace_text)
575
  else:
576
+ print(f"Warning: Search text not found in content: {search_text[:100]}...")
577
 
578
+ return modified_content
579
 
580
  # Updated for faster Tavily search and closer prompt usage
581
  # Uses 'advanced' search_depth and auto_parameters=True for speed and relevance
 
1094
  _history = []
1095
  _history = [h for h in _history if isinstance(h, list) and len(h) == 2]
1096
 
1097
+ # Check if there's existing content in history to determine if this is a modification request
1098
+ has_existing_content = False
1099
  last_assistant_msg = ""
1100
  if _history and len(_history[-1]) > 1:
1101
  last_assistant_msg = _history[-1][1]
1102
+ # Check for various content types that indicate an existing project
1103
+ if ('<!DOCTYPE html>' in last_assistant_msg or
1104
+ '<html' in last_assistant_msg or
1105
+ 'import gradio' in last_assistant_msg or
1106
+ 'import streamlit' in last_assistant_msg or
1107
+ 'def ' in last_assistant_msg and 'app' in last_assistant_msg or
1108
+ 'IMPORTED PROJECT FROM HUGGING FACE SPACE' in last_assistant_msg):
1109
+ has_existing_content = True
1110
 
1111
  # Choose system prompt based on context
1112
+ if has_existing_content:
1113
+ # Use follow-up prompt for modifying existing content
1114
  system_prompt = FollowUpSystemPrompt
1115
  else:
1116
  # Use language-specific prompt
 
1266
  }
1267
  else:
1268
  clean_code = remove_code_block(content)
1269
+ if has_existing_content:
1270
+ # Handle modification of existing content
1271
  if clean_code.strip().startswith("<!DOCTYPE html>") or clean_code.strip().startswith("<html"):
1272
+ # Model returned a complete HTML file
1273
  yield {
1274
  code_output: gr.update(value=clean_code, language=get_gradio_language(language)),
1275
  history_output: history_to_chatbot_messages(_history),
1276
  sandbox: send_to_sandbox(clean_code) if language == "html" else "<div style='padding:1em;color:#888;text-align:center;'>Preview is only available for HTML. Please download your code using the download button above.</div>",
1277
  }
1278
  else:
1279
+ # Model returned search/replace changes - apply them
1280
+ last_content = _history[-1][1] if _history and len(_history[-1]) > 1 else ""
1281
+ modified_content = apply_search_replace_changes(last_content, clean_code)
1282
+ clean_content = remove_code_block(modified_content)
1283
  yield {
1284
+ code_output: gr.update(value=clean_content, language=get_gradio_language(language)),
1285
  history_output: history_to_chatbot_messages(_history),
1286
+ sandbox: send_to_sandbox(clean_content) if language == "html" else "<div style='padding:1em;color:#888;text-align:center;'>Preview is only available for HTML. Please download your code using the download button above.</div>",
1287
  }
1288
  else:
1289
  yield {
 
1315
  sandbox: "<div style='padding:1em;color:#888;text-align:center;'>Error parsing transformers.js output. Please try again.</div>",
1316
  history_output: history_to_chatbot_messages(_history),
1317
  }
1318
+ elif has_existing_content:
1319
+ # Handle modification of existing content
1320
  final_code = remove_code_block(content)
1321
  if final_code.strip().startswith("<!DOCTYPE html>") or final_code.strip().startswith("<html"):
1322
+ # Model returned a complete HTML file
1323
+ clean_content = final_code
1324
  else:
1325
+ # Model returned search/replace changes - apply them
1326
+ last_content = _history[-1][1] if _history and len(_history[-1]) > 1 else ""
1327
+ modified_content = apply_search_replace_changes(last_content, final_code)
1328
+ clean_content = remove_code_block(modified_content)
1329
+ # Update history with the cleaned content
1330
+ _history.append([query, clean_content])
1331
  yield {
1332
+ code_output: clean_content,
1333
  history: _history,
1334
+ sandbox: send_to_sandbox(clean_content) if language == "html" else "<div style='padding:1em;color:#888;text-align:center;'>Preview is only available for HTML. Please download your code using the download button above.</div>",
1335
  history_output: history_to_chatbot_messages(_history),
1336
  }
1337
  else:
 
1403
  full_url = f"{base_url}?{params}&{files_params}"
1404
  webbrowser.open_new_tab(full_url)
1405
 
1406
+ def check_hf_space_url(url: str) -> Tuple[bool, Optional[str], Optional[str]]:
1407
+ """Check if URL is a valid Hugging Face Spaces URL and extract username/project"""
1408
+ import re
1409
+
1410
+ # Pattern to match HF Spaces URLs
1411
+ url_pattern = re.compile(
1412
+ r'^(https?://)?(huggingface\.co|hf\.co)/spaces/([\w-]+)/([\w-]+)$',
1413
+ re.IGNORECASE
1414
+ )
1415
+
1416
+ match = url_pattern.match(url.strip())
1417
+ if match:
1418
+ username = match.group(3)
1419
+ project_name = match.group(4)
1420
+ return True, username, project_name
1421
+ return False, None, None
1422
+
1423
+ def fetch_hf_space_content(username: str, project_name: str) -> str:
1424
+ """Fetch content from a Hugging Face Space"""
1425
+ try:
1426
+ import requests
1427
+ from huggingface_hub import HfApi
1428
+
1429
+ # Try to get space info first
1430
+ api = HfApi()
1431
+ space_info = api.space_info(f"{username}/{project_name}")
1432
+
1433
+ # Try to fetch the main file based on SDK
1434
+ sdk = space_info.sdk
1435
+ main_file = None
1436
+
1437
+ if sdk == "static":
1438
+ main_file = "index.html"
1439
+ elif sdk == "gradio":
1440
+ main_file = "app.py"
1441
+ elif sdk == "streamlit":
1442
+ main_file = "streamlit_app.py"
1443
+ else:
1444
+ # Try common files
1445
+ for file in ["app.py", "index.html", "streamlit_app.py", "main.py"]:
1446
+ try:
1447
+ content = api.hf_hub_download(
1448
+ repo_id=f"{username}/{project_name}",
1449
+ filename=file,
1450
+ repo_type="space"
1451
+ )
1452
+ main_file = file
1453
+ break
1454
+ except:
1455
+ continue
1456
+
1457
+ if main_file:
1458
+ content = api.hf_hub_download(
1459
+ repo_id=f"{username}/{project_name}",
1460
+ filename=main_file,
1461
+ repo_type="space"
1462
+ )
1463
+
1464
+ # Read the file content
1465
+ with open(content, 'r', encoding='utf-8') as f:
1466
+ file_content = f.read()
1467
+
1468
+ return f"""IMPORTED PROJECT FROM HUGGING FACE SPACE
1469
+ ==============================================
1470
+
1471
+ Space: {username}/{project_name}
1472
+ SDK: {sdk}
1473
+ Main File: {main_file}
1474
+
1475
+ {file_content}"""
1476
+ else:
1477
+ return f"Error: Could not find main file in space {username}/{project_name}"
1478
+
1479
+ except Exception as e:
1480
+ return f"Error fetching space content: {str(e)}"
1481
+
1482
+ def load_project_from_url(url: str) -> Tuple[str, str]:
1483
+ """Load project from Hugging Face Space URL"""
1484
+ # Validate URL
1485
+ is_valid, username, project_name = check_hf_space_url(url)
1486
+
1487
+ if not is_valid:
1488
+ return "Error: Please enter a valid Hugging Face Spaces URL.\n\nExpected format: https://huggingface.co/spaces/username/project", ""
1489
+
1490
+ # Fetch content
1491
+ content = fetch_hf_space_content(username, project_name)
1492
+
1493
+ if content.startswith("Error:"):
1494
+ return content, ""
1495
+
1496
+ # Extract the actual code content by removing metadata
1497
+ lines = content.split('\n')
1498
+ code_start = 0
1499
+ for i, line in enumerate(lines):
1500
+ # Skip metadata lines and find the start of actual code
1501
+ if (line.strip() and
1502
+ not line.startswith('=') and
1503
+ not line.startswith('IMPORTED PROJECT') and
1504
+ not line.startswith('Space:') and
1505
+ not line.startswith('SDK:') and
1506
+ not line.startswith('Main File:')):
1507
+ code_start = i
1508
+ break
1509
+
1510
+ code_content = '\n'.join(lines[code_start:])
1511
+
1512
+ return f"βœ… Successfully imported project from {username}/{project_name}", code_content
1513
+
1514
  # Main application
1515
  with gr.Blocks(
1516
  theme=gr.themes.Base(
 
1535
 
1536
  with gr.Sidebar():
1537
  login_button = gr.LoginButton()
1538
+
1539
+ # Add Load Project section
1540
+ with gr.Group():
1541
+ gr.Markdown("**πŸ“₯ Load Existing Project**")
1542
+ load_project_url = gr.Textbox(
1543
+ label="Hugging Face Space URL",
1544
+ placeholder="https://huggingface.co/spaces/username/project",
1545
+ lines=1
1546
+ )
1547
+ load_project_btn = gr.Button("Import Project", variant="secondary", size="sm")
1548
+ load_project_status = gr.Markdown(visible=False)
1549
+
1550
+ gr.Markdown("---")
1551
+
1552
  input = gr.Textbox(
1553
  label="What would you like to build?",
1554
  placeholder="Describe your application...",
 
1661
  with gr.Tab("History"):
1662
  history_output = gr.Chatbot(show_label=False, height=400, type="messages")
1663
 
1664
+ # Load project function
1665
+ def handle_load_project(url):
1666
+ if not url.strip():
1667
+ return gr.update(value="Please enter a URL.", visible=True)
1668
+
1669
+ status, code = load_project_from_url(url)
1670
+
1671
+ if code:
1672
+ # Extract space info for deployment
1673
+ is_valid, username, project_name = check_hf_space_url(url)
1674
+ space_info = f"{username}/{project_name}" if is_valid else ""
1675
+
1676
+ # Success - update the code output and show success message
1677
+ # Also update history to include the loaded project
1678
+ loaded_history = [[f"Loaded project from {url}", code]]
1679
+ return [
1680
+ gr.update(value=status, visible=True),
1681
+ gr.update(value=code, language="html"),
1682
+ gr.update(value=send_to_sandbox(code) if code.strip().startswith('<!DOCTYPE html>') or code.strip().startswith('<html') else "<div style='padding:1em;color:#888;text-align:center;'>Preview not available for this file type.</div>"),
1683
+ gr.update(value=""),
1684
+ loaded_history,
1685
+ history_to_chatbot_messages(loaded_history),
1686
+ gr.update(value=space_info, visible=True), # Update space name with loaded project
1687
+ gr.update(value="Update Existing Space", visible=True) # Change button text
1688
+ ]
1689
+ else:
1690
+ # Error - just show error message
1691
+ return [
1692
+ gr.update(value=status, visible=True),
1693
+ gr.update(),
1694
+ gr.update(),
1695
+ gr.update(),
1696
+ [],
1697
+ [],
1698
+ gr.update(value="", visible=False),
1699
+ gr.update(value="πŸš€ Deploy App", visible=False)
1700
+ ]
1701
+
1702
  # Event handlers
1703
  def update_code_language(language):
1704
  return gr.update(language=get_gradio_language(language))
 
1733
  def hide_deploy_components(*args):
1734
  return [gr.Textbox(visible=False), gr.Dropdown(visible=False), gr.Button(visible=False)]
1735
 
1736
+ # Load project button event
1737
+ load_project_btn.click(
1738
+ handle_load_project,
1739
+ inputs=[load_project_url],
1740
+ outputs=[load_project_status, code_output, sandbox, load_project_url, history, history_output, space_name_input, deploy_btn]
1741
+ )
1742
+
1743
  btn.click(
1744
  generation_code,
1745
  inputs=[input, image_input, file_input, website_url_input, setting, history, current_model, search_toggle, language_dropdown, provider_state],
 
1754
  language_dropdown.change(preview_logic, inputs=[code_output, language_dropdown], outputs=sandbox)
1755
  clear_btn.click(clear_history, outputs=[history, history_output, file_input, website_url_input])
1756
  clear_btn.click(hide_deploy_components, None, [space_name_input, sdk_dropdown, deploy_btn])
1757
+ # Reset space name and button text when clearing
1758
+ clear_btn.click(
1759
+ lambda: [gr.update(value=""), gr.update(value="πŸš€ Deploy App")],
1760
+ outputs=[space_name_input, deploy_btn]
1761
+ )
1762
 
1763
  # Deploy to Spaces logic
1764
 
 
1774
  return gr.update(value="No code to deploy.", visible=True)
1775
  if profile is None or token is None:
1776
  return gr.update(value="Please log in with your Hugging Face account to deploy to your own Space. Otherwise, use the default deploy (opens in new tab).", visible=True)
1777
+
1778
+ # Check if token has write permissions
1779
+ if not token.token or token.token == "hf_":
1780
+ return gr.update(value="Error: Invalid token. Please log in again with your Hugging Face account to get a valid write token.", visible=True)
1781
+
1782
+ # Check if this is an update to an existing space (contains /)
1783
+ is_update = "/" in space_name.strip()
1784
+ if is_update:
1785
+ # This is an existing space, use the provided space_name as repo_id
1786
+ repo_id = space_name.strip()
1787
+ # Extract username from repo_id for permission check
1788
+ space_username = repo_id.split('/')[0]
1789
+ if space_username != profile.username:
1790
+ return gr.update(value=f"Error: You can only update your own spaces. This space belongs to {space_username}.", visible=True)
1791
+
1792
+ # Verify the user has write access to this space
1793
+ try:
1794
+ api = HfApi(token=token.token)
1795
+ # Try to get space info to verify access
1796
+ space_info = api.space_info(repo_id)
1797
+ if not space_info:
1798
+ return gr.update(value=f"Error: Could not access space {repo_id}. Please check your permissions.", visible=True)
1799
+ except Exception as e:
1800
+ return gr.update(value=f"Error: No write access to space {repo_id}. Please ensure you have the correct permissions. Error: {str(e)}", visible=True)
1801
+ else:
1802
+ # This is a new space, create repo_id with current user
1803
+ username = profile.username
1804
+ repo_id = f"{username}/{space_name.strip()}"
1805
  # Map SDK name to HF SDK slug
1806
  sdk_map = {
1807
  "Gradio (Python)": "gradio",
 
1810
  "Transformers.js": "static" # Transformers.js uses static SDK
1811
  }
1812
  sdk = sdk_map.get(sdk_name, "gradio")
1813
+
1814
+ # Create API client with user's token for proper authentication
1815
  api = HfApi(token=token.token)
1816
+ # Only create the repo for new spaces (not updates) and non-Transformers.js and non-Streamlit SDKs
1817
+ if not is_update and sdk != "docker" and sdk_name != "Transformers.js":
1818
  try:
1819
  api.create_repo(
1820
  repo_id=repo_id, # e.g. username/space_name
 
1825
  except Exception as e:
1826
  return gr.update(value=f"Error creating Space: {e}", visible=True)
1827
  # Streamlit/docker logic
1828
+ if sdk == "docker" and not is_update:
1829
  try:
1830
  # Use duplicate_space to create a Streamlit template space
1831
  from huggingface_hub import duplicate_space
 
1852
  repo_type="space"
1853
  )
1854
  space_url = f"https://huggingface.co/spaces/{repo_id}"
1855
+ action_text = "Updated" if is_update else "Deployed"
1856
+ return gr.update(value=f"βœ… {action_text}! [Open your Space here]({space_url})", visible=True)
1857
  except Exception as e:
1858
+ error_msg = str(e)
1859
+ if "403 Forbidden" in error_msg and "write token" in error_msg:
1860
+ 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)
1861
+ else:
1862
+ return gr.update(value=f"Error uploading Streamlit app: {e}", visible=True)
1863
  finally:
1864
  import os
1865
  os.unlink(temp_path)
 
1867
  except Exception as e:
1868
  return gr.update(value=f"Error duplicating Streamlit space: {e}", visible=True)
1869
  # Transformers.js logic
1870
+ elif sdk_name == "Transformers.js" and not is_update:
1871
  try:
1872
  # Use duplicate_space to create a transformers.js template space
1873
  from huggingface_hub import duplicate_space
 
1904
  repo_type="space"
1905
  )
1906
  except Exception as e:
1907
+ error_msg = str(e)
1908
+ if "403 Forbidden" in error_msg and "write token" in error_msg:
1909
+ 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)
1910
+ else:
1911
+ return gr.update(value=f"Error uploading index.html: {e}", visible=True)
1912
  finally:
1913
  import os
1914
  os.unlink(temp_path)
 
1926
  repo_type="space"
1927
  )
1928
  except Exception as e:
1929
+ error_msg = str(e)
1930
+ if "403 Forbidden" in error_msg and "write token" in error_msg:
1931
+ 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)
1932
+ else:
1933
+ return gr.update(value=f"Error uploading index.js: {e}", visible=True)
1934
  finally:
1935
  import os
1936
  os.unlink(temp_path)
 
1948
  repo_type="space"
1949
  )
1950
  space_url = f"https://huggingface.co/spaces/{repo_id}"
1951
+ action_text = "Updated" if is_update else "Deployed"
1952
+ return gr.update(value=f"βœ… {action_text}! [Open your Transformers.js Space here]({space_url})", visible=True)
1953
  except Exception as e:
1954
+ error_msg = str(e)
1955
+ if "403 Forbidden" in error_msg and "write token" in error_msg:
1956
+ 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)
1957
+ else:
1958
+ return gr.update(value=f"Error uploading style.css: {e}", visible=True)
1959
  finally:
1960
  import os
1961
  os.unlink(temp_path)
 
1981
  repo_type="space"
1982
  )
1983
  space_url = f"https://huggingface.co/spaces/{repo_id}"
1984
+ action_text = "Updated" if is_update else "Deployed"
1985
+ return gr.update(value=f"βœ… {action_text}! [Open your Space here]({space_url})", visible=True)
1986
  except Exception as e:
1987
+ error_msg = str(e)
1988
+ if "403 Forbidden" in error_msg and "write token" in error_msg:
1989
+ 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)
1990
+ elif attempt < max_attempts - 1:
1991
  time.sleep(2) # Wait before retrying
1992
  else:
1993
+ return gr.update(value=f"Error uploading file after {max_attempts} attempts: {e}. Please check your permissions and try again.", visible=True)
1994
  finally:
1995
  import os
1996
  os.unlink(temp_path)
 
2008
  repo_type="space"
2009
  )
2010
  space_url = f"https://huggingface.co/spaces/{repo_id}"
2011
+ action_text = "Updated" if is_update else "Deployed"
2012
+ return gr.update(value=f"βœ… {action_text}! [Open your Space here]({space_url})", visible=True)
2013
  except Exception as e:
2014
+ error_msg = str(e)
2015
+ if "403 Forbidden" in error_msg and "write token" in error_msg:
2016
+ 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)
2017
+ else:
2018
+ return gr.update(value=f"Error uploading file: {e}", visible=True)
2019
  finally:
2020
  import os
2021
  os.unlink(temp_path)