Spaces:
Running
Running
update
Browse files
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(
|
517 |
-
"""Apply search/replace changes to HTML
|
518 |
if not changes_text.strip():
|
519 |
-
return
|
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 |
-
|
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
|
574 |
-
|
575 |
else:
|
576 |
-
print(f"Warning: Search text not found in
|
577 |
|
578 |
-
return
|
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
|
1098 |
-
|
1099 |
last_assistant_msg = ""
|
1100 |
if _history and len(_history[-1]) > 1:
|
1101 |
last_assistant_msg = _history[-1][1]
|
1102 |
-
|
1103 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
1104 |
|
1105 |
# Choose system prompt based on context
|
1106 |
-
if
|
1107 |
-
# Use follow-up prompt for modifying existing
|
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
|
1264 |
-
#
|
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 |
-
|
1273 |
-
|
1274 |
-
|
|
|
1275 |
yield {
|
1276 |
-
code_output: gr.update(value=
|
1277 |
history_output: history_to_chatbot_messages(_history),
|
1278 |
-
sandbox: send_to_sandbox(
|
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
|
1311 |
-
#
|
1312 |
final_code = remove_code_block(content)
|
1313 |
if final_code.strip().startswith("<!DOCTYPE html>") or final_code.strip().startswith("<html"):
|
1314 |
-
|
|
|
1315 |
else:
|
1316 |
-
|
1317 |
-
|
1318 |
-
|
1319 |
-
|
1320 |
-
|
|
|
1321 |
yield {
|
1322 |
-
code_output:
|
1323 |
history: _history,
|
1324 |
-
sandbox: send_to_sandbox(
|
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 |
-
|
1596 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
-
|
|
|
1646 |
except Exception as e:
|
1647 |
-
|
|
|
|
|
|
|
|
|
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 |
-
|
|
|
|
|
|
|
|
|
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 |
-
|
|
|
|
|
|
|
|
|
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 |
-
|
|
|
1729 |
except Exception as e:
|
1730 |
-
|
|
|
|
|
|
|
|
|
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 |
-
|
|
|
1757 |
except Exception as e:
|
1758 |
-
|
|
|
|
|
|
|
1759 |
time.sleep(2) # Wait before retrying
|
1760 |
else:
|
1761 |
-
return gr.update(value=f"Error uploading file after {max_attempts} attempts: {e}.
|
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 |
-
|
|
|
1780 |
except Exception as e:
|
1781 |
-
|
|
|
|
|
|
|
|
|
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)
|