|
|
""" |
|
|
Gradio user interface for AnyCoder. |
|
|
Defines the main UI layout, components, and event handlers. |
|
|
""" |
|
|
import os |
|
|
import gradio as gr |
|
|
from typing import Dict, Optional |
|
|
from huggingface_hub import HfApi |
|
|
import httpx |
|
|
|
|
|
|
|
|
|
|
|
_original_client_init = httpx.AsyncClient.__init__ |
|
|
|
|
|
def _patched_client_init(self, *args, **kwargs): |
|
|
|
|
|
if 'timeout' not in kwargs: |
|
|
kwargs['timeout'] = httpx.Timeout( |
|
|
connect=30.0, |
|
|
read=60.0, |
|
|
write=30.0, |
|
|
pool=30.0 |
|
|
) |
|
|
return _original_client_init(self, *args, **kwargs) |
|
|
|
|
|
httpx.AsyncClient.__init__ = _patched_client_init |
|
|
|
|
|
from .config import ( |
|
|
AVAILABLE_MODELS, DEFAULT_MODEL, DEFAULT_MODEL_NAME, |
|
|
LANGUAGE_CHOICES, get_gradio_language |
|
|
) |
|
|
from .themes import THEME_CONFIGS, get_saved_theme, current_theme |
|
|
from .prompts import HTML_SYSTEM_PROMPT |
|
|
from .models import history_to_chatbot_messages |
|
|
from .parsers import ( |
|
|
history_render, clear_history, create_multimodal_message, |
|
|
parse_multipage_html_output, parse_transformers_js_output, |
|
|
parse_react_output, format_transformers_js_output, |
|
|
validate_and_autofix_files, parse_multi_file_python_output, |
|
|
is_streamlit_code, is_gradio_code |
|
|
) |
|
|
from .deploy import ( |
|
|
check_authentication, update_ui_for_auth_status, |
|
|
generation_code, deploy_to_spaces, add_anycoder_tag_to_readme, |
|
|
_parse_repo_or_model_url, load_project_from_url, check_hf_space_url, |
|
|
import_repo_to_app, extract_import_statements, |
|
|
generate_requirements_txt_with_llm, prettify_comfyui_json_for_html, |
|
|
get_trending_models, import_model_from_hf, get_trending_spaces, import_space_from_hf, |
|
|
switch_model_code_type |
|
|
) |
|
|
from .agent import ( |
|
|
agent_generate_with_questions, agent_process_answers_and_generate |
|
|
) |
|
|
|
|
|
|
|
|
with gr.Blocks( |
|
|
title="AnyCoder - AI Code Generator", |
|
|
theme=current_theme, |
|
|
css=""" |
|
|
.theme-info { font-size: 0.9em; opacity: 0.8; } |
|
|
.theme-description { padding: 8px 0; } |
|
|
.theme-status { |
|
|
padding: 10px; |
|
|
border-radius: 8px; |
|
|
background: rgba(34, 197, 94, 0.1); |
|
|
border: 1px solid rgba(34, 197, 94, 0.2); |
|
|
margin: 8px 0; |
|
|
} |
|
|
.restart-needed { |
|
|
padding: 12px; |
|
|
border-radius: 8px; |
|
|
background: rgba(255, 193, 7, 0.1); |
|
|
border: 1px solid rgba(255, 193, 7, 0.3); |
|
|
margin: 8px 0; |
|
|
text-align: center; |
|
|
} |
|
|
/* Authentication status styling */ |
|
|
.auth-status { |
|
|
padding: 8px 12px; |
|
|
border-radius: 6px; |
|
|
margin: 8px 0; |
|
|
font-weight: 500; |
|
|
text-align: center; |
|
|
} |
|
|
.auth-status:has-text("🔒") { |
|
|
background: rgba(231, 76, 60, 0.1); |
|
|
border: 1px solid rgba(231, 76, 60, 0.3); |
|
|
color: #e74c3c; |
|
|
} |
|
|
.auth-status:has-text("✅") { |
|
|
background: rgba(46, 204, 113, 0.1); |
|
|
border: 1px solid rgba(46, 204, 113, 0.3); |
|
|
color: #2ecc71; |
|
|
} |
|
|
/* App link styling (visible on all devices) */ |
|
|
.app-link { |
|
|
display: block; |
|
|
padding: 12px; |
|
|
border-radius: 8px; |
|
|
background: rgba(59, 130, 246, 0.1); |
|
|
border: 1px solid rgba(59, 130, 246, 0.3); |
|
|
margin: 12px 0; |
|
|
text-align: center; |
|
|
} |
|
|
""" |
|
|
) as demo: |
|
|
history = gr.State([]) |
|
|
setting = gr.State({ |
|
|
"system": HTML_SYSTEM_PROMPT, |
|
|
}) |
|
|
current_model = gr.State(DEFAULT_MODEL) |
|
|
open_panel = gr.State(None) |
|
|
last_login_state = gr.State(None) |
|
|
models_first_change = gr.State(True) |
|
|
spaces_first_change = gr.State(True) |
|
|
agent_mode_enabled = gr.State(False) |
|
|
current_trending_model_id = gr.State("") |
|
|
agent_conversation_state = gr.State({ |
|
|
"stage": "initial", |
|
|
"original_query": "", |
|
|
"questions": "" |
|
|
}) |
|
|
|
|
|
with gr.Sidebar() as sidebar: |
|
|
login_button = gr.LoginButton() |
|
|
|
|
|
|
|
|
mobile_link = gr.HTML( |
|
|
""" |
|
|
<div class="app-link"> |
|
|
📱 <strong>Using Mobile?</strong><br/> |
|
|
<a href="https://akhaliq-anycoder.hf.space" target="_blank" style="color: #007bff; text-decoration: underline;"> |
|
|
Use the app here |
|
|
</a> |
|
|
</div> |
|
|
""", |
|
|
visible=True |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
import_header_md = gr.Markdown("📥 Import Project (Space, GitHub, or Model)", visible=False) |
|
|
load_project_url = gr.Textbox( |
|
|
label="Project URL", |
|
|
placeholder="https://huggingface.co/spaces/user/space OR https://huggingface.co/user/model OR https://github.com/owner/repo", |
|
|
lines=1 |
|
|
, visible=False) |
|
|
load_project_btn = gr.Button("📥 Import Project", variant="secondary", size="sm", visible=True) |
|
|
load_project_status = gr.Markdown(visible=False) |
|
|
|
|
|
|
|
|
trending_models_dropdown = gr.Dropdown( |
|
|
label="🔥 Trending HuggingFace Models", |
|
|
choices=[], |
|
|
value=None, |
|
|
interactive=True, |
|
|
visible=True |
|
|
) |
|
|
trending_models_status = gr.Markdown(visible=False) |
|
|
switch_model_code_btn = gr.Button("🔄 Switch Code Type", visible=False, size="sm", variant="secondary") |
|
|
|
|
|
|
|
|
trending_spaces_dropdown = gr.Dropdown( |
|
|
label="🚀 Trending HuggingFace Spaces", |
|
|
choices=[], |
|
|
value=None, |
|
|
interactive=True, |
|
|
visible=True |
|
|
) |
|
|
trending_spaces_status = gr.Markdown(visible=False) |
|
|
|
|
|
|
|
|
chat_history = gr.Chatbot( |
|
|
label="Conversation History", |
|
|
type="messages", |
|
|
height=300, |
|
|
show_copy_button=True, |
|
|
visible=True |
|
|
) |
|
|
|
|
|
|
|
|
input = gr.Textbox( |
|
|
label="What would you like to build?", |
|
|
placeholder="🔒 Please log in with Hugging Face to use AnyCoder...", |
|
|
lines=2, |
|
|
visible=True, |
|
|
interactive=False |
|
|
) |
|
|
|
|
|
language_choices = [ |
|
|
"html", "gradio", "transformers.js", "streamlit", "comfyui", "react" |
|
|
] |
|
|
language_dropdown = gr.Dropdown( |
|
|
choices=language_choices, |
|
|
value="html", |
|
|
label="Code Language", |
|
|
visible=True |
|
|
) |
|
|
|
|
|
|
|
|
agent_mode_checkbox = gr.Checkbox( |
|
|
label="🤖 Enable Agent Mode", |
|
|
value=False, |
|
|
info="Agent will ask follow-up questions and create a task list before coding", |
|
|
visible=True |
|
|
) |
|
|
|
|
|
|
|
|
with gr.Row(): |
|
|
btn = gr.Button("Generate", variant="secondary", size="lg", scale=2, visible=True, interactive=False) |
|
|
clear_btn = gr.Button("Clear", variant="secondary", size="sm", scale=1, visible=True) |
|
|
|
|
|
deploy_header_md = gr.Markdown("", visible=False) |
|
|
deploy_btn = gr.Button("Publish", variant="primary", visible=True) |
|
|
deploy_status = gr.Markdown(visible=False, label="Deploy status") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
model_dropdown = gr.Dropdown( |
|
|
choices=[model['name'] for model in AVAILABLE_MODELS], |
|
|
value=DEFAULT_MODEL_NAME, |
|
|
label="Model", |
|
|
visible=True |
|
|
) |
|
|
provider_state = gr.State("auto") |
|
|
|
|
|
def on_model_change(model_name): |
|
|
for m in AVAILABLE_MODELS: |
|
|
if m['name'] == model_name: |
|
|
return m |
|
|
return AVAILABLE_MODELS[0] |
|
|
def save_prompt(input): |
|
|
return {setting: {"system": input}} |
|
|
model_dropdown.change( |
|
|
lambda model_name: on_model_change(model_name), |
|
|
inputs=model_dropdown, |
|
|
outputs=[current_model] |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
with gr.Column() as main_column: |
|
|
with gr.Tabs(): |
|
|
with gr.Tab("Code"): |
|
|
code_output = gr.Code( |
|
|
language="html", |
|
|
lines=25, |
|
|
interactive=True, |
|
|
label="Generated code" |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
with gr.Group(visible=False) as tjs_group: |
|
|
with gr.Tabs(): |
|
|
with gr.Tab("index.html"): |
|
|
tjs_html_code = gr.Code(language="html", lines=20, interactive=True, label="index.html") |
|
|
with gr.Tab("index.js"): |
|
|
tjs_js_code = gr.Code(language="javascript", lines=20, interactive=True, label="index.js") |
|
|
with gr.Tab("style.css"): |
|
|
tjs_css_code = gr.Code(language="css", lines=20, interactive=True, label="style.css") |
|
|
|
|
|
|
|
|
with gr.Group(visible=False) as python_group_2: |
|
|
with gr.Tabs(): |
|
|
with gr.Tab("app.py") as python_tab_2_1: |
|
|
python_code_2_1 = gr.Code(language="python", lines=20, interactive=True, label="app.py") |
|
|
with gr.Tab("file 2") as python_tab_2_2: |
|
|
python_code_2_2 = gr.Code(language="python", lines=18, interactive=True, label="file 2") |
|
|
|
|
|
with gr.Group(visible=False) as python_group_3: |
|
|
with gr.Tabs(): |
|
|
with gr.Tab("app.py") as python_tab_3_1: |
|
|
python_code_3_1 = gr.Code(language="python", lines=20, interactive=True, label="app.py") |
|
|
with gr.Tab("file 2") as python_tab_3_2: |
|
|
python_code_3_2 = gr.Code(language="python", lines=18, interactive=True, label="file 2") |
|
|
with gr.Tab("file 3") as python_tab_3_3: |
|
|
python_code_3_3 = gr.Code(language="python", lines=18, interactive=True, label="file 3") |
|
|
|
|
|
with gr.Group(visible=False) as python_group_4: |
|
|
with gr.Tabs(): |
|
|
with gr.Tab("app.py") as python_tab_4_1: |
|
|
python_code_4_1 = gr.Code(language="python", lines=20, interactive=True, label="app.py") |
|
|
with gr.Tab("file 2") as python_tab_4_2: |
|
|
python_code_4_2 = gr.Code(language="python", lines=18, interactive=True, label="file 2") |
|
|
with gr.Tab("file 3") as python_tab_4_3: |
|
|
python_code_4_3 = gr.Code(language="python", lines=18, interactive=True, label="file 3") |
|
|
with gr.Tab("file 4") as python_tab_4_4: |
|
|
python_code_4_4 = gr.Code(language="python", lines=18, interactive=True, label="file 4") |
|
|
|
|
|
with gr.Group(visible=False) as python_group_5plus: |
|
|
with gr.Tabs(): |
|
|
with gr.Tab("app.py") as python_tab_5_1: |
|
|
python_code_5_1 = gr.Code(language="python", lines=20, interactive=True, label="app.py") |
|
|
with gr.Tab("file 2") as python_tab_5_2: |
|
|
python_code_5_2 = gr.Code(language="python", lines=18, interactive=True, label="file 2") |
|
|
with gr.Tab("file 3") as python_tab_5_3: |
|
|
python_code_5_3 = gr.Code(language="python", lines=18, interactive=True, label="file 3") |
|
|
with gr.Tab("file 4") as python_tab_5_4: |
|
|
python_code_5_4 = gr.Code(language="python", lines=18, interactive=True, label="file 4") |
|
|
with gr.Tab("file 5") as python_tab_5_5: |
|
|
python_code_5_5 = gr.Code(language="python", lines=18, interactive=True, label="file 5") |
|
|
|
|
|
|
|
|
with gr.Group(visible=False) as static_group_2: |
|
|
with gr.Tabs(): |
|
|
with gr.Tab("index.html") as static_tab_2_1: |
|
|
static_code_2_1 = gr.Code(language="html", lines=20, interactive=True, label="index.html") |
|
|
with gr.Tab("file 2") as static_tab_2_2: |
|
|
static_code_2_2 = gr.Code(language="html", lines=18, interactive=True, label="file 2") |
|
|
|
|
|
with gr.Group(visible=False) as static_group_3: |
|
|
with gr.Tabs(): |
|
|
with gr.Tab("index.html") as static_tab_3_1: |
|
|
static_code_3_1 = gr.Code(language="html", lines=20, interactive=True, label="index.html") |
|
|
with gr.Tab("file 2") as static_tab_3_2: |
|
|
static_code_3_2 = gr.Code(language="html", lines=18, interactive=True, label="file 2") |
|
|
with gr.Tab("file 3") as static_tab_3_3: |
|
|
static_code_3_3 = gr.Code(language="html", lines=18, interactive=True, label="file 3") |
|
|
|
|
|
with gr.Group(visible=False) as static_group_4: |
|
|
with gr.Tabs(): |
|
|
with gr.Tab("index.html") as static_tab_4_1: |
|
|
static_code_4_1 = gr.Code(language="html", lines=20, interactive=True, label="index.html") |
|
|
with gr.Tab("file 2") as static_tab_4_2: |
|
|
static_code_4_2 = gr.Code(language="html", lines=18, interactive=True, label="file 2") |
|
|
with gr.Tab("file 3") as static_tab_4_3: |
|
|
static_code_4_3 = gr.Code(language="html", lines=18, interactive=True, label="file 3") |
|
|
with gr.Tab("file 4") as static_tab_4_4: |
|
|
static_code_4_4 = gr.Code(language="html", lines=18, interactive=True, label="file 4") |
|
|
|
|
|
with gr.Group(visible=False) as static_group_5plus: |
|
|
with gr.Tabs(): |
|
|
with gr.Tab("index.html") as static_tab_5_1: |
|
|
static_code_5_1 = gr.Code(language="html", lines=20, interactive=True, label="index.html") |
|
|
with gr.Tab("file 2") as static_tab_5_2: |
|
|
static_code_5_2 = gr.Code(language="html", lines=18, interactive=True, label="file 2") |
|
|
with gr.Tab("file 3") as static_tab_5_3: |
|
|
static_code_5_3 = gr.Code(language="html", lines=18, interactive=True, label="file 3") |
|
|
with gr.Tab("file 4") as static_tab_5_4: |
|
|
static_code_5_4 = gr.Code(language="html", lines=18, interactive=True, label="file 4") |
|
|
with gr.Tab("file 5") as static_tab_5_5: |
|
|
static_code_5_5 = gr.Code(language="html", lines=18, interactive=True, label="file 5") |
|
|
|
|
|
with gr.Group(visible=False) as react_group: |
|
|
with gr.Tabs(): |
|
|
with gr.Tab("Dockerfile"): |
|
|
react_code_dockerfile = gr.Code(language="dockerfile", lines=15, interactive=True, label="Dockerfile") |
|
|
with gr.Tab("package.json"): |
|
|
react_code_package_json = gr.Code(language="json", lines=20, interactive=True, label="package.json") |
|
|
with gr.Tab("next.config.js"): |
|
|
react_code_next_config = gr.Code(language="javascript", lines=15, interactive=True, label="next.config.js") |
|
|
with gr.Tab("postcss.config.js"): |
|
|
react_code_postcss_config = gr.Code(language="javascript", lines=10, interactive=True, label="postcss.config.js") |
|
|
with gr.Tab("tailwind.config.js"): |
|
|
react_code_tailwind_config = gr.Code(language="javascript", lines=15, interactive=True, label="tailwind.config.js") |
|
|
with gr.Tab("pages/_app.js"): |
|
|
react_code_pages_app = gr.Code(language="javascript", lines=15, interactive=True, label="pages/_app.js") |
|
|
with gr.Tab("pages/index.js"): |
|
|
react_code_pages_index = gr.Code(language="javascript", lines=20, interactive=True, label="pages/index.js") |
|
|
with gr.Tab("components/ChatApp.jsx"): |
|
|
react_code_components = gr.Code(language="javascript", lines=25, interactive=True, label="components/ChatApp.jsx") |
|
|
with gr.Tab("styles/globals.css"): |
|
|
react_code_styles = gr.Code(language="css", lines=20, interactive=True, label="styles/globals.css") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
history_output = gr.Chatbot(show_label=False, height=400, type="messages", visible=False) |
|
|
|
|
|
|
|
|
generating_status = gr.Markdown("", visible=False) |
|
|
|
|
|
|
|
|
def handle_import_project(url): |
|
|
if not url.strip(): |
|
|
return [ |
|
|
gr.update(value="Please enter a URL.", visible=True), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
[], |
|
|
[], |
|
|
gr.update(value="Publish", visible=False), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
[] |
|
|
] |
|
|
|
|
|
kind, meta = _parse_repo_or_model_url(url) |
|
|
if kind == "hf_space": |
|
|
status, code = load_project_from_url(url) |
|
|
|
|
|
is_valid, username, project_name = check_hf_space_url(url) |
|
|
space_name = f"{username}/{project_name}" if is_valid else "" |
|
|
loaded_history = [[f"Imported Space from {url}", code]] |
|
|
|
|
|
|
|
|
code_lang = "html" |
|
|
framework_type = "html" |
|
|
|
|
|
|
|
|
if is_streamlit_code(code): |
|
|
code_lang = "python" |
|
|
framework_type = "streamlit" |
|
|
elif is_gradio_code(code): |
|
|
code_lang = "python" |
|
|
framework_type = "gradio" |
|
|
elif "=== index.html ===" in code and "=== index.js ===" in code and "=== style.css ===" in code: |
|
|
|
|
|
code_lang = "html" |
|
|
framework_type = "transformers.js" |
|
|
elif ("import " in code or "def " in code) and not ("<!DOCTYPE html>" in code or "<html" in code): |
|
|
|
|
|
|
|
|
code_lang = "python" |
|
|
framework_type = "gradio" |
|
|
|
|
|
|
|
|
return [ |
|
|
gr.update(value=status, visible=True), |
|
|
gr.update(value=code, language=code_lang), |
|
|
gr.update(value="", visible=False), |
|
|
loaded_history, |
|
|
history_to_chatbot_messages(loaded_history), |
|
|
gr.update(value="Publish", visible=True), |
|
|
gr.update(visible=False), |
|
|
gr.update(visible=False), |
|
|
gr.update(value=framework_type), |
|
|
history_to_chatbot_messages(loaded_history) |
|
|
] |
|
|
else: |
|
|
|
|
|
status, code, _ = import_repo_to_app(url) |
|
|
loaded_history = [[f"Imported Repo/Model from {url}", code]] |
|
|
code_lang = "python" |
|
|
framework_type = "gradio" |
|
|
lower = (code or "").lower() |
|
|
if code.strip().startswith("<!doctype html>") or code.strip().startswith("<html"): |
|
|
code_lang = "html" |
|
|
framework_type = "html" |
|
|
elif "```json" in lower: |
|
|
code_lang = "json" |
|
|
framework_type = "json" |
|
|
return [ |
|
|
gr.update(value=status, visible=True), |
|
|
gr.update(value=code, language=code_lang), |
|
|
gr.update(value="", visible=False), |
|
|
loaded_history, |
|
|
history_to_chatbot_messages(loaded_history), |
|
|
gr.update(value="Publish", visible=False), |
|
|
gr.update(visible=False), |
|
|
gr.update(visible=False), |
|
|
gr.update(value=framework_type), |
|
|
history_to_chatbot_messages(loaded_history) |
|
|
] |
|
|
|
|
|
|
|
|
def handle_import_repo(url, framework): |
|
|
status, code, preview = import_repo_to_app(url, framework) |
|
|
|
|
|
code_lang = "python" |
|
|
lowered = (code or "").lower() |
|
|
if code.strip().startswith("<!doctype html>") or code.strip().startswith("<html"): |
|
|
code_lang = "html" |
|
|
elif "import gradio" in lowered or "from gradio" in lowered: |
|
|
code_lang = "python" |
|
|
elif "streamlit as st" in lowered or "import streamlit" in lowered: |
|
|
code_lang = "python" |
|
|
elif "from transformers" in lowered or "import transformers" in lowered: |
|
|
code_lang = "python" |
|
|
elif "from diffusers" in lowered or "import diffusers" in lowered: |
|
|
code_lang = "python" |
|
|
return [ |
|
|
gr.update(value=status, visible=True), |
|
|
gr.update(value=code, language=code_lang), |
|
|
gr.update(value=""), |
|
|
gr.update(value=f"URL: {url}\n\n{status}"), |
|
|
] |
|
|
|
|
|
|
|
|
def update_code_language(language): |
|
|
return gr.update(language=get_gradio_language(language)) |
|
|
|
|
|
|
|
|
language_dropdown.change(update_code_language, inputs=language_dropdown, outputs=code_output) |
|
|
|
|
|
|
|
|
def toggle_editors(language, code_text): |
|
|
if language == "transformers.js": |
|
|
files = parse_transformers_js_output(code_text or "") |
|
|
|
|
|
editors_visible = True if (files.get('index.html') and files.get('index.js') and files.get('style.css')) else False |
|
|
return [ |
|
|
gr.update(visible=not editors_visible), |
|
|
gr.update(visible=editors_visible), |
|
|
gr.update(value=files.get('index.html', '')), |
|
|
gr.update(value=files.get('index.js', '')), |
|
|
gr.update(value=files.get('style.css', '')), |
|
|
|
|
|
gr.update(visible=False), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
] |
|
|
elif language == "react": |
|
|
files = parse_react_output(code_text or "") |
|
|
|
|
|
editors_visible = True if files else False |
|
|
if editors_visible: |
|
|
return [ |
|
|
gr.update(visible=False), |
|
|
gr.update(visible=False), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
|
|
|
gr.update(visible=editors_visible), |
|
|
gr.update(value=files.get('Dockerfile', '')), |
|
|
gr.update(value=files.get('package.json', '')), |
|
|
gr.update(value=files.get('next.config.js', '')), |
|
|
gr.update(value=files.get('postcss.config.js', '')), |
|
|
gr.update(value=files.get('tailwind.config.js', '')), |
|
|
gr.update(value=files.get('pages/_app.js', '')), |
|
|
gr.update(value=files.get('pages/index.js', '')), |
|
|
gr.update(value=files.get('components/ChatApp.jsx', '')), |
|
|
gr.update(value=files.get('styles/globals.css', '')), |
|
|
] |
|
|
else: |
|
|
return [ |
|
|
gr.update(visible=True), |
|
|
gr.update(visible=False), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
|
|
|
gr.update(visible=False), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
] |
|
|
else: |
|
|
return [ |
|
|
gr.update(visible=True), |
|
|
gr.update(visible=False), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
|
|
|
gr.update(visible=False), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
] |
|
|
|
|
|
language_dropdown.change( |
|
|
toggle_editors, |
|
|
inputs=[language_dropdown, code_output], |
|
|
outputs=[code_output, tjs_group, tjs_html_code, tjs_js_code, tjs_css_code, react_group, react_code_dockerfile, react_code_package_json, react_code_next_config, react_code_postcss_config, react_code_tailwind_config, react_code_pages_app, react_code_pages_index, react_code_components, react_code_styles], |
|
|
) |
|
|
|
|
|
def toggle_python_editors(language, code_text): |
|
|
if language not in ["gradio", "streamlit"]: |
|
|
return [ |
|
|
gr.update(visible=True), |
|
|
gr.update(visible=False), |
|
|
gr.update(visible=False), |
|
|
gr.update(visible=False), |
|
|
gr.update(visible=False), |
|
|
|
|
|
gr.update(), gr.update(), gr.update(), gr.update(), |
|
|
gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), |
|
|
gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), |
|
|
gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update() |
|
|
] |
|
|
|
|
|
files = parse_multi_file_python_output(code_text or "") |
|
|
|
|
|
if not isinstance(files, dict) or len(files) <= 1: |
|
|
|
|
|
return [ |
|
|
gr.update(visible=True), |
|
|
gr.update(visible=False), |
|
|
gr.update(visible=False), |
|
|
gr.update(visible=False), |
|
|
gr.update(visible=False), |
|
|
|
|
|
gr.update(), gr.update(), gr.update(), gr.update(), |
|
|
gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), |
|
|
gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), |
|
|
gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update() |
|
|
] |
|
|
|
|
|
|
|
|
|
|
|
ordered_paths = [] |
|
|
main_files = ['app.py', 'streamlit_app.py', 'main.py'] |
|
|
for main_file in main_files: |
|
|
if main_file in files: |
|
|
ordered_paths.append(main_file) |
|
|
break |
|
|
|
|
|
for p in sorted(files.keys()): |
|
|
if p not in ordered_paths: |
|
|
ordered_paths.append(p) |
|
|
|
|
|
num_files = len(ordered_paths) |
|
|
|
|
|
|
|
|
updates = [gr.update(visible=False)] |
|
|
|
|
|
if num_files == 2: |
|
|
updates.extend([ |
|
|
gr.update(visible=True), |
|
|
gr.update(visible=False), |
|
|
gr.update(visible=False), |
|
|
gr.update(visible=False), |
|
|
]) |
|
|
|
|
|
path1, path2 = ordered_paths[0], ordered_paths[1] |
|
|
updates.extend([ |
|
|
gr.update(label=path1), gr.update(value=files.get(path1, ''), label=path1, language="python"), |
|
|
gr.update(label=path2), gr.update(value=files.get(path2, ''), label=path2, language="python"), |
|
|
|
|
|
gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), |
|
|
gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), |
|
|
gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update() |
|
|
]) |
|
|
elif num_files == 3: |
|
|
updates.extend([ |
|
|
gr.update(visible=False), |
|
|
gr.update(visible=True), |
|
|
gr.update(visible=False), |
|
|
gr.update(visible=False), |
|
|
]) |
|
|
|
|
|
path1, path2, path3 = ordered_paths[0], ordered_paths[1], ordered_paths[2] |
|
|
updates.extend([ |
|
|
|
|
|
gr.update(), gr.update(), gr.update(), gr.update(), |
|
|
|
|
|
gr.update(label=path1), gr.update(value=files.get(path1, ''), label=path1, language="python"), |
|
|
gr.update(label=path2), gr.update(value=files.get(path2, ''), label=path2, language="python"), |
|
|
gr.update(label=path3), gr.update(value=files.get(path3, ''), label=path3, language="python"), |
|
|
|
|
|
gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), |
|
|
gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update() |
|
|
]) |
|
|
elif num_files == 4: |
|
|
updates.extend([ |
|
|
gr.update(visible=False), |
|
|
gr.update(visible=False), |
|
|
gr.update(visible=True), |
|
|
gr.update(visible=False), |
|
|
]) |
|
|
|
|
|
paths = ordered_paths[:4] |
|
|
updates.extend([ |
|
|
|
|
|
gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), |
|
|
|
|
|
gr.update(label=paths[0]), gr.update(value=files.get(paths[0], ''), label=paths[0], language="python"), |
|
|
gr.update(label=paths[1]), gr.update(value=files.get(paths[1], ''), label=paths[1], language="python"), |
|
|
gr.update(label=paths[2]), gr.update(value=files.get(paths[2], ''), label=paths[2], language="python"), |
|
|
gr.update(label=paths[3]), gr.update(value=files.get(paths[3], ''), label=paths[3], language="python"), |
|
|
|
|
|
gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update() |
|
|
]) |
|
|
else: |
|
|
updates.extend([ |
|
|
gr.update(visible=False), |
|
|
gr.update(visible=False), |
|
|
gr.update(visible=False), |
|
|
gr.update(visible=True), |
|
|
]) |
|
|
|
|
|
paths = ordered_paths[:5] |
|
|
updates.extend([ |
|
|
|
|
|
gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), |
|
|
|
|
|
gr.update(label=paths[0]), gr.update(value=files.get(paths[0], ''), label=paths[0], language="python"), |
|
|
gr.update(label=paths[1]), gr.update(value=files.get(paths[1], ''), label=paths[1], language="python"), |
|
|
gr.update(label=paths[2]), gr.update(value=files.get(paths[2], ''), label=paths[2], language="python"), |
|
|
gr.update(label=paths[3]), gr.update(value=files.get(paths[3], ''), label=paths[3], language="python"), |
|
|
gr.update(label=paths[4]), gr.update(value=files.get(paths[4], ''), label=paths[4], language="python"), |
|
|
]) |
|
|
|
|
|
return updates |
|
|
|
|
|
language_dropdown.change( |
|
|
toggle_python_editors, |
|
|
inputs=[language_dropdown, code_output], |
|
|
outputs=[ |
|
|
code_output, python_group_2, python_group_3, python_group_4, python_group_5plus, |
|
|
python_tab_2_1, python_code_2_1, python_tab_2_2, python_code_2_2, |
|
|
python_tab_3_1, python_code_3_1, python_tab_3_2, python_code_3_2, python_tab_3_3, python_code_3_3, |
|
|
python_tab_4_1, python_code_4_1, python_tab_4_2, python_code_4_2, python_tab_4_3, python_code_4_3, python_tab_4_4, python_code_4_4, |
|
|
python_tab_5_1, python_code_5_1, python_tab_5_2, python_code_5_2, python_tab_5_3, python_code_5_3, python_tab_5_4, python_code_5_4, python_tab_5_5, python_code_5_5 |
|
|
], |
|
|
) |
|
|
|
|
|
|
|
|
def toggle_static_editors(language, code_text): |
|
|
|
|
|
if language != "html": |
|
|
return [ |
|
|
gr.update(visible=True), |
|
|
gr.update(visible=False), |
|
|
gr.update(visible=False), |
|
|
gr.update(visible=False), |
|
|
gr.update(visible=False), |
|
|
|
|
|
gr.update(), gr.update(), gr.update(), gr.update(), |
|
|
gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), |
|
|
gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), |
|
|
gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update() |
|
|
] |
|
|
|
|
|
|
|
|
original_files = parse_multipage_html_output(code_text or "") |
|
|
|
|
|
|
|
|
|
|
|
if not isinstance(original_files, dict) or len(original_files) <= 1: |
|
|
|
|
|
return [ |
|
|
gr.update(visible=True), |
|
|
gr.update(visible=False), |
|
|
gr.update(visible=False), |
|
|
gr.update(visible=False), |
|
|
gr.update(visible=False), |
|
|
|
|
|
gr.update(), gr.update(), gr.update(), gr.update(), |
|
|
gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), |
|
|
gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), |
|
|
gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update() |
|
|
] |
|
|
|
|
|
|
|
|
files = validate_and_autofix_files(original_files) |
|
|
|
|
|
|
|
|
|
|
|
ordered_paths = [] |
|
|
if 'index.html' in files: |
|
|
ordered_paths.append('index.html') |
|
|
for p in sorted(files.keys()): |
|
|
if p == 'index.html': |
|
|
continue |
|
|
ordered_paths.append(p) |
|
|
|
|
|
|
|
|
def _lang_for(path: str): |
|
|
p = (path or '').lower() |
|
|
if p.endswith('.html'): |
|
|
return 'html' |
|
|
if p.endswith('.css'): |
|
|
return 'css' |
|
|
if p.endswith('.js'): |
|
|
return 'javascript' |
|
|
if p.endswith('.json'): |
|
|
return 'json' |
|
|
if p.endswith('.md') or p.endswith('.markdown'): |
|
|
return 'markdown' |
|
|
return 'html' |
|
|
|
|
|
num_files = len(ordered_paths) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
updates = [ |
|
|
gr.update(visible=True), |
|
|
gr.update(visible=False), |
|
|
gr.update(visible=False), |
|
|
gr.update(visible=False), |
|
|
gr.update(visible=False), |
|
|
] |
|
|
|
|
|
|
|
|
updates.extend([ |
|
|
|
|
|
gr.update(), gr.update(), gr.update(), gr.update(), |
|
|
gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), |
|
|
gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), |
|
|
gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update() |
|
|
]) |
|
|
|
|
|
return updates |
|
|
|
|
|
|
|
|
language_dropdown.change( |
|
|
toggle_static_editors, |
|
|
inputs=[language_dropdown, code_output], |
|
|
outputs=[ |
|
|
code_output, |
|
|
static_group_2, static_group_3, static_group_4, static_group_5plus, |
|
|
static_tab_2_1, static_code_2_1, static_tab_2_2, static_code_2_2, |
|
|
static_tab_3_1, static_code_3_1, static_tab_3_2, static_code_3_2, static_tab_3_3, static_code_3_3, |
|
|
static_tab_4_1, static_code_4_1, static_tab_4_2, static_code_4_2, static_tab_4_3, static_code_4_3, static_tab_4_4, static_code_4_4, |
|
|
static_tab_5_1, static_code_5_1, static_tab_5_2, static_code_5_2, static_tab_5_3, static_code_5_3, static_tab_5_4, static_code_5_4, static_tab_5_5, static_code_5_5, |
|
|
], |
|
|
) |
|
|
|
|
|
def sync_tjs_from_code(code_text, language): |
|
|
if language != "transformers.js": |
|
|
return [gr.update(), gr.update(), gr.update(), gr.update()] |
|
|
files = parse_transformers_js_output(code_text or "") |
|
|
|
|
|
editors_visible = True if (files.get('index.html') and files.get('index.js') and files.get('style.css')) else None |
|
|
return [ |
|
|
gr.update(value=files.get('index.html', '')), |
|
|
gr.update(value=files.get('index.js', '')), |
|
|
gr.update(value=files.get('style.css', '')), |
|
|
gr.update(visible=editors_visible) if editors_visible is not None else gr.update(), |
|
|
] |
|
|
|
|
|
|
|
|
code_output.change( |
|
|
sync_tjs_from_code, |
|
|
inputs=[code_output, language_dropdown], |
|
|
outputs=[tjs_html_code, tjs_js_code, tjs_css_code, tjs_group], |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def show_tjs_deployment_message(*args): |
|
|
return """ |
|
|
<div style='padding: 1.5em; text-align: center; background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%); color: white; border-radius: 10px;'> |
|
|
<h3 style='margin-top: 0; color: white;'>🚀 Transformers.js App Ready!</h3> |
|
|
<p style='margin: 0.5em 0; opacity: 0.9;'>Your multi-file Transformers.js application is ready for deployment.</p> |
|
|
<p style='margin: 0.5em 0; font-weight: bold;'>👉 Use the Deploy button in the sidebar to publish your app!</p> |
|
|
</div> |
|
|
""" |
|
|
|
|
|
|
|
|
def show_deploy_components(*args): |
|
|
return gr.Button(visible=True) |
|
|
|
|
|
def hide_deploy_components(*args): |
|
|
return gr.Button(visible=True) |
|
|
|
|
|
|
|
|
def toggle_import_textbox(url_visible): |
|
|
|
|
|
|
|
|
return gr.update(visible=True) |
|
|
|
|
|
load_project_btn.click( |
|
|
fn=toggle_import_textbox, |
|
|
inputs=[load_project_url], |
|
|
outputs=[load_project_url] |
|
|
).then( |
|
|
handle_import_project, |
|
|
inputs=[load_project_url], |
|
|
outputs=[ |
|
|
load_project_status, |
|
|
code_output, |
|
|
load_project_url, |
|
|
history, |
|
|
history_output, |
|
|
deploy_btn, |
|
|
import_header_md, |
|
|
load_project_btn, |
|
|
language_dropdown, |
|
|
chat_history, |
|
|
], |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def begin_generation_ui(agent_enabled): |
|
|
|
|
|
|
|
|
if agent_enabled: |
|
|
return [gr.update(), gr.update(visible=False)] |
|
|
else: |
|
|
|
|
|
return [gr.update(open=False), gr.update(visible=False)] |
|
|
|
|
|
def end_generation_ui(): |
|
|
|
|
|
return [gr.update(open=True), gr.update(visible=False)] |
|
|
|
|
|
def close_sidebar_for_coding(): |
|
|
|
|
|
return gr.update(open=False) |
|
|
|
|
|
def generation_code_wrapper(inp, sett, hist, model, lang, prov, agent_enabled, agent_state, profile: Optional[gr.OAuthProfile] = None, token: Optional[gr.OAuthToken] = None): |
|
|
"""Wrapper to call generation_code or agent mode based on settings""" |
|
|
|
|
|
|
|
|
if agent_enabled and agent_state["stage"] == "initial": |
|
|
|
|
|
|
|
|
for updated_hist, chatbot_msgs in agent_generate_with_questions( |
|
|
inp, sett, hist, model, lang, prov, profile, token |
|
|
): |
|
|
|
|
|
new_agent_state = { |
|
|
"stage": "waiting_for_answers", |
|
|
"original_query": inp, |
|
|
"questions": updated_hist[-1][1] if updated_hist else "" |
|
|
} |
|
|
|
|
|
yield "", updated_hist, chatbot_msgs, chatbot_msgs, new_agent_state, gr.update() |
|
|
return |
|
|
|
|
|
elif agent_enabled and agent_state["stage"] == "waiting_for_answers": |
|
|
|
|
|
original_query = agent_state.get("original_query", "") |
|
|
questions = agent_state.get("questions", "") |
|
|
|
|
|
|
|
|
started_code_generation = False |
|
|
|
|
|
|
|
|
for result in agent_process_answers_and_generate( |
|
|
inp, original_query, questions, sett, hist, model, lang, prov, |
|
|
profile, token, code_output, history_output, history |
|
|
): |
|
|
|
|
|
code_val = result.get(code_output, "") |
|
|
hist_val = result.get(history, hist) |
|
|
history_output_val = result.get(history_output, []) |
|
|
|
|
|
|
|
|
reset_agent_state = { |
|
|
"stage": "initial", |
|
|
"original_query": "", |
|
|
"questions": "" |
|
|
} |
|
|
|
|
|
|
|
|
if code_val and not started_code_generation: |
|
|
sidebar_update = gr.update(open=False) |
|
|
started_code_generation = True |
|
|
else: |
|
|
sidebar_update = gr.update() |
|
|
|
|
|
|
|
|
yield code_val, hist_val, history_output_val, history_output_val, reset_agent_state, sidebar_update |
|
|
return |
|
|
|
|
|
else: |
|
|
|
|
|
|
|
|
for result in generation_code(inp, sett, hist, model, lang, prov, profile, token, code_output, history_output, history): |
|
|
|
|
|
|
|
|
code_val = result.get(code_output, "") |
|
|
hist_val = result.get(history, hist) |
|
|
history_output_val = result.get(history_output, []) |
|
|
|
|
|
yield code_val, hist_val, history_output_val, history_output_val, agent_state, gr.update() |
|
|
|
|
|
|
|
|
agent_mode_checkbox.change( |
|
|
lambda enabled: enabled, |
|
|
inputs=[agent_mode_checkbox], |
|
|
outputs=[agent_mode_enabled] |
|
|
) |
|
|
|
|
|
btn.click( |
|
|
begin_generation_ui, |
|
|
inputs=[agent_mode_enabled], |
|
|
outputs=[sidebar, generating_status], |
|
|
show_progress="hidden", |
|
|
).then( |
|
|
generation_code_wrapper, |
|
|
inputs=[input, setting, history, current_model, language_dropdown, provider_state, agent_mode_enabled, agent_conversation_state], |
|
|
outputs=[code_output, history, history_output, chat_history, agent_conversation_state, sidebar] |
|
|
).then( |
|
|
end_generation_ui, |
|
|
inputs=None, |
|
|
outputs=[sidebar, generating_status] |
|
|
).then( |
|
|
|
|
|
toggle_editors, |
|
|
inputs=[language_dropdown, code_output], |
|
|
outputs=[code_output, tjs_group, tjs_html_code, tjs_js_code, tjs_css_code, react_group, react_code_dockerfile, react_code_package_json, react_code_next_config, react_code_postcss_config, react_code_tailwind_config, react_code_pages_app, react_code_pages_index, react_code_components, react_code_styles] |
|
|
).then( |
|
|
|
|
|
toggle_static_editors, |
|
|
inputs=[language_dropdown, code_output], |
|
|
outputs=[ |
|
|
code_output, |
|
|
static_group_2, static_group_3, static_group_4, static_group_5plus, |
|
|
static_tab_2_1, static_code_2_1, static_tab_2_2, static_code_2_2, |
|
|
static_tab_3_1, static_code_3_1, static_tab_3_2, static_code_3_2, static_tab_3_3, static_code_3_3, |
|
|
static_tab_4_1, static_code_4_1, static_tab_4_2, static_code_4_2, static_tab_4_3, static_code_4_3, static_tab_4_4, static_code_4_4, |
|
|
static_tab_5_1, static_code_5_1, static_tab_5_2, static_code_5_2, static_tab_5_3, static_code_5_3, static_tab_5_4, static_code_5_4, static_tab_5_5, static_code_5_5, |
|
|
] |
|
|
).then( |
|
|
|
|
|
toggle_python_editors, |
|
|
inputs=[language_dropdown, code_output], |
|
|
outputs=[ |
|
|
code_output, python_group_2, python_group_3, python_group_4, python_group_5plus, |
|
|
python_tab_2_1, python_code_2_1, python_tab_2_2, python_code_2_2, |
|
|
python_tab_3_1, python_code_3_1, python_tab_3_2, python_code_3_2, python_tab_3_3, python_code_3_3, |
|
|
python_tab_4_1, python_code_4_1, python_tab_4_2, python_code_4_2, python_tab_4_3, python_code_4_3, python_tab_4_4, python_code_4_4, |
|
|
python_tab_5_1, python_code_5_1, python_tab_5_2, python_code_5_2, python_tab_5_3, python_code_5_3, python_tab_5_4, python_code_5_4, python_tab_5_5, python_code_5_5 |
|
|
] |
|
|
).then( |
|
|
show_deploy_components, |
|
|
None, |
|
|
[deploy_btn] |
|
|
) |
|
|
|
|
|
|
|
|
input.submit( |
|
|
begin_generation_ui, |
|
|
inputs=[agent_mode_enabled], |
|
|
outputs=[sidebar, generating_status], |
|
|
show_progress="hidden", |
|
|
).then( |
|
|
generation_code_wrapper, |
|
|
inputs=[input, setting, history, current_model, language_dropdown, provider_state, agent_mode_enabled, agent_conversation_state], |
|
|
outputs=[code_output, history, history_output, chat_history, agent_conversation_state, sidebar] |
|
|
).then( |
|
|
end_generation_ui, |
|
|
inputs=None, |
|
|
outputs=[sidebar, generating_status] |
|
|
).then( |
|
|
|
|
|
toggle_editors, |
|
|
inputs=[language_dropdown, code_output], |
|
|
outputs=[code_output, tjs_group, tjs_html_code, tjs_js_code, tjs_css_code, react_group, react_code_dockerfile, react_code_package_json, react_code_next_config, react_code_postcss_config, react_code_tailwind_config, react_code_pages_app, react_code_pages_index, react_code_components, react_code_styles] |
|
|
).then( |
|
|
|
|
|
toggle_static_editors, |
|
|
inputs=[language_dropdown, code_output], |
|
|
outputs=[ |
|
|
code_output, |
|
|
static_group_2, static_group_3, static_group_4, static_group_5plus, |
|
|
static_tab_2_1, static_code_2_1, static_tab_2_2, static_code_2_2, |
|
|
static_tab_3_1, static_code_3_1, static_tab_3_2, static_code_3_2, static_tab_3_3, static_code_3_3, |
|
|
static_tab_4_1, static_code_4_1, static_tab_4_2, static_code_4_2, static_tab_4_3, static_code_4_3, static_tab_4_4, static_code_4_4, |
|
|
static_tab_5_1, static_code_5_1, static_tab_5_2, static_code_5_2, static_tab_5_3, static_code_5_3, static_tab_5_4, static_code_5_4, static_tab_5_5, static_code_5_5, |
|
|
] |
|
|
).then( |
|
|
|
|
|
toggle_python_editors, |
|
|
inputs=[language_dropdown, code_output], |
|
|
outputs=[ |
|
|
code_output, python_group_2, python_group_3, python_group_4, python_group_5plus, |
|
|
python_tab_2_1, python_code_2_1, python_tab_2_2, python_code_2_2, |
|
|
python_tab_3_1, python_code_3_1, python_tab_3_2, python_code_3_2, python_tab_3_3, python_code_3_3, |
|
|
python_tab_4_1, python_code_4_1, python_tab_4_2, python_code_4_2, python_tab_4_3, python_code_4_3, python_tab_4_4, python_code_4_4, |
|
|
python_tab_5_1, python_code_5_1, python_tab_5_2, python_code_5_2, python_tab_5_3, python_code_5_3, python_tab_5_4, python_code_5_4, python_tab_5_5, python_code_5_5 |
|
|
] |
|
|
).then( |
|
|
show_deploy_components, |
|
|
None, |
|
|
[deploy_btn] |
|
|
) |
|
|
|
|
|
|
|
|
def _find_model_by_name(name: str): |
|
|
for m in AVAILABLE_MODELS: |
|
|
if m["name"].lower() == name.lower(): |
|
|
return m |
|
|
return None |
|
|
|
|
|
def _extract_url(text: str) -> Optional[str]: |
|
|
import re |
|
|
match = re.search(r"https?://[^\s]+", text or "") |
|
|
return match.group(0) if match else None |
|
|
|
|
|
|
|
|
|
|
|
def show_deployment_message(code, language, *args): |
|
|
if not code or not code.strip(): |
|
|
return "<div style='padding:1em;color:#888;text-align:center;'>Generate some code to see deployment options.</div>" |
|
|
return f""" |
|
|
<div style='padding: 1.5em; text-align: center; background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%); color: white; border-radius: 10px;'> |
|
|
<h3 style='margin-top: 0; color: white;'>Ready to Deploy!</h3> |
|
|
<p style='margin: 0.5em 0; opacity: 0.9;'>Your {language.upper()} code is ready for deployment.</p> |
|
|
<p style='margin: 0.5em 0; font-weight: bold;'>👉 Use the Deploy button in the sidebar to publish your app!</p> |
|
|
</div> |
|
|
""" |
|
|
|
|
|
def reset_agent_state(): |
|
|
"""Reset agent conversation state when clearing history""" |
|
|
return { |
|
|
"stage": "initial", |
|
|
"original_query": "", |
|
|
"questions": "" |
|
|
} |
|
|
|
|
|
clear_btn.click(clear_history, outputs=[history, history_output, chat_history]) |
|
|
clear_btn.click(hide_deploy_components, None, [deploy_btn]) |
|
|
clear_btn.click(reset_agent_state, outputs=[agent_conversation_state]) |
|
|
|
|
|
clear_btn.click( |
|
|
lambda: gr.update(value="Publish"), |
|
|
outputs=[deploy_btn] |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
def generate_random_app_name(): |
|
|
"""Generate a random app name that's unlikely to clash with existing apps""" |
|
|
import random |
|
|
import string |
|
|
|
|
|
|
|
|
prefixes = ["my", "cool", "awesome", "smart", "quick", "super", "mini", "auto", "fast", "easy"] |
|
|
|
|
|
suffixes = ["app", "tool", "hub", "space", "demo", "ai", "gen", "bot", "lab", "studio"] |
|
|
|
|
|
adjectives = ["blue", "red", "green", "bright", "dark", "light", "swift", "bold", "clean", "fresh"] |
|
|
|
|
|
|
|
|
patterns = [ |
|
|
lambda: f"{random.choice(prefixes)}-{random.choice(suffixes)}-{random.randint(100, 999)}", |
|
|
lambda: f"{random.choice(adjectives)}-{random.choice(suffixes)}-{random.randint(10, 99)}", |
|
|
lambda: f"{random.choice(prefixes)}-{random.choice(adjectives)}-{random.choice(suffixes)}", |
|
|
lambda: f"app-{''.join(random.choices(string.ascii_lowercase, k=6))}-{random.randint(10, 99)}", |
|
|
lambda: f"{random.choice(suffixes)}-{''.join(random.choices(string.ascii_lowercase + string.digits, k=8))}" |
|
|
] |
|
|
|
|
|
return random.choice(patterns)() |
|
|
|
|
|
def deploy_with_history_tracking( |
|
|
code, |
|
|
language, |
|
|
history, |
|
|
profile: Optional[gr.OAuthProfile] = None, |
|
|
token: Optional[gr.OAuthToken] = None |
|
|
): |
|
|
"""Wrapper function that handles history tracking for deployments""" |
|
|
|
|
|
username = profile.username if profile else None |
|
|
existing_space = None |
|
|
|
|
|
|
|
|
if history and username: |
|
|
for user_msg, assistant_msg in history: |
|
|
if assistant_msg and "✅ Deployed!" in assistant_msg: |
|
|
import re |
|
|
|
|
|
match = re.search(r'huggingface\.co/spaces/([^/\s\)]+/[^/\s\)]+)', assistant_msg) |
|
|
if match: |
|
|
existing_space = match.group(1) |
|
|
break |
|
|
elif assistant_msg and "✅ Updated!" in assistant_msg: |
|
|
import re |
|
|
|
|
|
match = re.search(r'huggingface\.co/spaces/([^/\s\)]+/[^/\s\)]+)', assistant_msg) |
|
|
if match: |
|
|
existing_space = match.group(1) |
|
|
break |
|
|
elif user_msg and user_msg.startswith("Imported Space from"): |
|
|
import re |
|
|
|
|
|
match = re.search(r'huggingface\.co/spaces/([^/\s\)]+/[^/\s\)]+)', user_msg) |
|
|
if match: |
|
|
imported_space = match.group(1) |
|
|
|
|
|
if imported_space.startswith(f"{username}/"): |
|
|
existing_space = imported_space |
|
|
break |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
status = deploy_to_user_space_original(code, language, existing_space, profile, token) |
|
|
|
|
|
|
|
|
updated_history = history |
|
|
if isinstance(status, dict) and "value" in status and "✅" in status["value"]: |
|
|
action_type = "Deploy" if "Deployed!" in status["value"] else "Update" |
|
|
if existing_space: |
|
|
updated_history = history + [[f"{action_type} {language} app to {existing_space}", status["value"]]] |
|
|
else: |
|
|
updated_history = history + [[f"{action_type} {language} app", status["value"]]] |
|
|
|
|
|
return [status, updated_history] |
|
|
|
|
|
def deploy_to_user_space_original( |
|
|
code, |
|
|
language, |
|
|
existing_space_name=None, |
|
|
profile: Optional[gr.OAuthProfile] = None, |
|
|
token: Optional[gr.OAuthToken] = None |
|
|
): |
|
|
import shutil |
|
|
if not code or not code.strip(): |
|
|
return gr.update(value="No code to deploy.", visible=True) |
|
|
if profile is None or token is None: |
|
|
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) |
|
|
|
|
|
|
|
|
if not token.token or token.token == "hf_": |
|
|
return gr.update(value="Error: Invalid token. Please log in again with your Hugging Face account to get a valid write token.", visible=True) |
|
|
|
|
|
|
|
|
username = profile.username |
|
|
if existing_space_name and existing_space_name.startswith(f"{username}/"): |
|
|
|
|
|
repo_id = existing_space_name |
|
|
space_name = existing_space_name.split('/')[-1] |
|
|
is_update = True |
|
|
else: |
|
|
|
|
|
space_name = generate_random_app_name() |
|
|
repo_id = f"{username}/{space_name}" |
|
|
is_update = False |
|
|
|
|
|
language_to_sdk_map = { |
|
|
"gradio": "gradio", |
|
|
"streamlit": "docker", |
|
|
"react": "docker", |
|
|
"html": "static", |
|
|
"transformers.js": "static", |
|
|
"comfyui": "static" |
|
|
} |
|
|
sdk = language_to_sdk_map.get(language, "gradio") |
|
|
|
|
|
|
|
|
api = HfApi(token=token.token) |
|
|
|
|
|
if not is_update and sdk != "docker" and language not in ["transformers.js"]: |
|
|
try: |
|
|
api.create_repo( |
|
|
repo_id=repo_id, |
|
|
repo_type="space", |
|
|
space_sdk=sdk, |
|
|
exist_ok=True |
|
|
) |
|
|
except Exception as e: |
|
|
return gr.update(value=f"Error creating Space: {e}", visible=True) |
|
|
|
|
|
if sdk == "docker" and language in ["streamlit", "react"]: |
|
|
try: |
|
|
|
|
|
if not is_update: |
|
|
|
|
|
from huggingface_hub import create_repo |
|
|
|
|
|
if language == "react": |
|
|
|
|
|
created_repo = create_repo( |
|
|
repo_id=repo_id, |
|
|
repo_type="space", |
|
|
space_sdk="docker", |
|
|
token=token.token, |
|
|
exist_ok=True |
|
|
) |
|
|
else: |
|
|
|
|
|
created_repo = create_repo( |
|
|
repo_id=repo_id, |
|
|
repo_type="space", |
|
|
space_sdk="docker", |
|
|
token=token.token, |
|
|
exist_ok=True |
|
|
) |
|
|
|
|
|
|
|
|
if language == "react": |
|
|
|
|
|
files = parse_react_output(code) |
|
|
if not files: |
|
|
return gr.update(value="Error: Could not parse React output. Please regenerate the code.", visible=True) |
|
|
|
|
|
|
|
|
if 'Dockerfile' not in files: |
|
|
files['Dockerfile'] = """FROM node:18-slim |
|
|
|
|
|
# Use the existing node user (UID 1000) |
|
|
USER node |
|
|
|
|
|
# Set environment variables |
|
|
ENV HOME=/home/node \\ |
|
|
PATH=/home/node/.local/bin:$PATH |
|
|
|
|
|
# Set working directory |
|
|
WORKDIR /home/node/app |
|
|
|
|
|
# Copy package files with proper ownership |
|
|
COPY --chown=node:node package*.json ./ |
|
|
|
|
|
# Install dependencies |
|
|
RUN npm install |
|
|
|
|
|
# Copy rest of the application with proper ownership |
|
|
COPY --chown=node:node . . |
|
|
|
|
|
# Build the Next.js app |
|
|
RUN npm run build |
|
|
|
|
|
# Expose port 7860 |
|
|
EXPOSE 7860 |
|
|
|
|
|
# Start the application on port 7860 |
|
|
CMD ["npm", "start", "--", "-p", "7860"] |
|
|
""" |
|
|
|
|
|
|
|
|
import tempfile |
|
|
import time |
|
|
|
|
|
for file_name, file_content in files.items(): |
|
|
if not file_content: |
|
|
continue |
|
|
|
|
|
success = False |
|
|
last_error = None |
|
|
max_attempts = 3 |
|
|
|
|
|
for attempt in range(max_attempts): |
|
|
try: |
|
|
|
|
|
if file_name == 'Dockerfile': |
|
|
suffix = '' |
|
|
else: |
|
|
suffix = f".{file_name.split('.')[-1]}" |
|
|
|
|
|
with tempfile.NamedTemporaryFile("w", suffix=suffix, delete=False) as f: |
|
|
f.write(file_content) |
|
|
temp_path = f.name |
|
|
|
|
|
api.upload_file( |
|
|
path_or_fileobj=temp_path, |
|
|
path_in_repo=file_name, |
|
|
repo_id=repo_id, |
|
|
repo_type="space" |
|
|
) |
|
|
success = True |
|
|
break |
|
|
|
|
|
except Exception as e: |
|
|
last_error = e |
|
|
error_msg = str(e) |
|
|
if "403 Forbidden" in error_msg and "write token" in error_msg: |
|
|
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) |
|
|
|
|
|
if attempt < max_attempts - 1: |
|
|
time.sleep(2) |
|
|
finally: |
|
|
import os |
|
|
if 'temp_path' in locals(): |
|
|
os.unlink(temp_path) |
|
|
|
|
|
if not success: |
|
|
return gr.update(value=f"Error uploading {file_name}: {last_error}", visible=True) |
|
|
|
|
|
|
|
|
add_anycoder_tag_to_readme(api, repo_id, app_port=7860) |
|
|
|
|
|
space_url = f"https://huggingface.co/spaces/{repo_id}" |
|
|
action_text = "Updated" if is_update else "Deployed" |
|
|
return gr.update(value=f"✅ {action_text}! [Open your React Space here]({space_url})", visible=True) |
|
|
|
|
|
|
|
|
files = parse_multi_file_python_output(code) |
|
|
if not files: |
|
|
return gr.update(value="Error: Could not parse Streamlit output. Please regenerate the code.", visible=True) |
|
|
|
|
|
|
|
|
has_streamlit_app = 'streamlit_app.py' in files or 'app.py' in files |
|
|
has_requirements = 'requirements.txt' in files |
|
|
has_dockerfile = 'Dockerfile' in files |
|
|
|
|
|
if not has_streamlit_app: |
|
|
return gr.update(value="Error: Missing streamlit_app.py. Please regenerate the code.", visible=True) |
|
|
|
|
|
|
|
|
if not has_dockerfile: |
|
|
|
|
|
files['Dockerfile'] = """FROM python:3.11-slim |
|
|
|
|
|
# Set up user with ID 1000 |
|
|
RUN useradd -m -u 1000 user |
|
|
USER user |
|
|
ENV HOME=/home/user \\ |
|
|
PATH=/home/user/.local/bin:$PATH |
|
|
|
|
|
# Set working directory |
|
|
WORKDIR $HOME/app |
|
|
|
|
|
# Copy requirements file with proper ownership |
|
|
COPY --chown=user requirements.txt . |
|
|
|
|
|
# Install dependencies |
|
|
RUN pip install --no-cache-dir -r requirements.txt |
|
|
|
|
|
# Copy application files with proper ownership |
|
|
COPY --chown=user . . |
|
|
|
|
|
# Expose port 7860 |
|
|
EXPOSE 7860 |
|
|
|
|
|
# Start Streamlit app |
|
|
CMD ["streamlit", "run", "streamlit_app.py", "--server.port=7860", "--server.address=0.0.0.0"] |
|
|
""" |
|
|
|
|
|
if not has_requirements: |
|
|
|
|
|
main_app = files.get('streamlit_app.py') or files.get('app.py', '') |
|
|
import_statements = extract_import_statements(main_app) |
|
|
files['requirements.txt'] = generate_requirements_txt_with_llm(import_statements) |
|
|
|
|
|
|
|
|
import tempfile |
|
|
import time |
|
|
|
|
|
for file_name, file_content in files.items(): |
|
|
if not file_content: |
|
|
continue |
|
|
|
|
|
success = False |
|
|
last_error = None |
|
|
max_attempts = 3 |
|
|
|
|
|
for attempt in range(max_attempts): |
|
|
try: |
|
|
|
|
|
if file_name == 'Dockerfile': |
|
|
suffix = '' |
|
|
else: |
|
|
suffix = f".{file_name.split('.')[-1]}" |
|
|
|
|
|
with tempfile.NamedTemporaryFile("w", suffix=suffix, delete=False) as f: |
|
|
f.write(file_content) |
|
|
temp_path = f.name |
|
|
|
|
|
api.upload_file( |
|
|
path_or_fileobj=temp_path, |
|
|
path_in_repo=file_name, |
|
|
repo_id=repo_id, |
|
|
repo_type="space" |
|
|
) |
|
|
success = True |
|
|
break |
|
|
|
|
|
except Exception as e: |
|
|
last_error = e |
|
|
error_msg = str(e) |
|
|
if "403 Forbidden" in error_msg and "write token" in error_msg: |
|
|
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) |
|
|
|
|
|
if attempt < max_attempts - 1: |
|
|
time.sleep(2) |
|
|
finally: |
|
|
import os |
|
|
if 'temp_path' in locals(): |
|
|
os.unlink(temp_path) |
|
|
|
|
|
if not success: |
|
|
return gr.update(value=f"Error uploading {file_name}: {last_error}", visible=True) |
|
|
|
|
|
|
|
|
add_anycoder_tag_to_readme(api, repo_id, app_port=7860) |
|
|
|
|
|
space_url = f"https://huggingface.co/spaces/{repo_id}" |
|
|
action_text = "Updated" if is_update else "Deployed" |
|
|
return gr.update(value=f"✅ {action_text}! [Open your Streamlit Space here]({space_url})", visible=True) |
|
|
|
|
|
except Exception as e: |
|
|
error_prefix = "Error duplicating Streamlit space" if not is_update else "Error updating Streamlit space" |
|
|
return gr.update(value=f"{error_prefix}: {e}", visible=True) |
|
|
|
|
|
elif language == "transformers.js": |
|
|
try: |
|
|
|
|
|
if not is_update: |
|
|
|
|
|
from huggingface_hub import duplicate_space |
|
|
|
|
|
|
|
|
duplicated_repo = duplicate_space( |
|
|
from_id="static-templates/transformers.js", |
|
|
to_id=space_name.strip(), |
|
|
token=token.token, |
|
|
exist_ok=True |
|
|
) |
|
|
print("Duplicated repo result:", duplicated_repo, type(duplicated_repo)) |
|
|
else: |
|
|
|
|
|
try: |
|
|
space_info = api.space_info(repo_id) |
|
|
if not space_info: |
|
|
return gr.update(value=f"Error: Could not access space {repo_id} for update.", visible=True) |
|
|
except Exception as e: |
|
|
return gr.update(value=f"Error: Cannot update space {repo_id}. {str(e)}", visible=True) |
|
|
|
|
|
files = parse_transformers_js_output(code) |
|
|
|
|
|
if not files['index.html'] or not files['index.js'] or not files['style.css']: |
|
|
return gr.update(value="Error: Could not parse transformers.js output. Please regenerate the code.", visible=True) |
|
|
|
|
|
|
|
|
import tempfile |
|
|
import time |
|
|
|
|
|
|
|
|
files_to_upload = [ |
|
|
("index.html", files['index.html']), |
|
|
("index.js", files['index.js']), |
|
|
("style.css", files['style.css']) |
|
|
] |
|
|
|
|
|
|
|
|
max_attempts = 3 |
|
|
for file_name, file_content in files_to_upload: |
|
|
success = False |
|
|
last_error = None |
|
|
|
|
|
for attempt in range(max_attempts): |
|
|
try: |
|
|
with tempfile.NamedTemporaryFile("w", suffix=f".{file_name.split('.')[-1]}", delete=False) as f: |
|
|
f.write(file_content) |
|
|
temp_path = f.name |
|
|
|
|
|
api.upload_file( |
|
|
path_or_fileobj=temp_path, |
|
|
path_in_repo=file_name, |
|
|
repo_id=repo_id, |
|
|
repo_type="space" |
|
|
) |
|
|
success = True |
|
|
break |
|
|
|
|
|
except Exception as e: |
|
|
last_error = e |
|
|
error_msg = str(e) |
|
|
if "403 Forbidden" in error_msg and "write token" in error_msg: |
|
|
|
|
|
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) |
|
|
|
|
|
if attempt < max_attempts - 1: |
|
|
time.sleep(2) |
|
|
finally: |
|
|
import os |
|
|
if 'temp_path' in locals(): |
|
|
os.unlink(temp_path) |
|
|
|
|
|
if not success: |
|
|
return gr.update(value=f"Error uploading {file_name}: {last_error}", visible=True) |
|
|
|
|
|
|
|
|
add_anycoder_tag_to_readme(api, repo_id) |
|
|
|
|
|
|
|
|
if is_update: |
|
|
try: |
|
|
api.restart_space(repo_id=repo_id) |
|
|
except Exception as restart_error: |
|
|
|
|
|
print(f"Note: Could not restart space after update: {restart_error}") |
|
|
|
|
|
space_url = f"https://huggingface.co/spaces/{repo_id}" |
|
|
action_text = "Updated" if is_update else "Deployed" |
|
|
return gr.update(value=f"✅ {action_text}! [Open your Transformers.js Space here]({space_url})", visible=True) |
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
error_msg = str(e) |
|
|
if "'url'" in error_msg or "RepoUrl" in error_msg: |
|
|
|
|
|
try: |
|
|
|
|
|
space_url = f"https://huggingface.co/spaces/{repo_id}" |
|
|
test_api = HfApi(token=token.token) |
|
|
space_exists = test_api.space_info(repo_id) |
|
|
|
|
|
if space_exists and not is_update: |
|
|
|
|
|
return gr.update(value=f"✅ Deployed! Space was created successfully despite a technical error. [Open your Transformers.js Space here]({space_url})", visible=True) |
|
|
elif space_exists and is_update: |
|
|
|
|
|
return gr.update(value=f"✅ Updated! Space was updated successfully despite a technical error. [Open your Transformers.js Space here]({space_url})", visible=True) |
|
|
else: |
|
|
|
|
|
return gr.update(value=f"Error: Could not create/update space. Please try again manually at https://huggingface.co/new-space", visible=True) |
|
|
except: |
|
|
|
|
|
repo_url = f"https://huggingface.co/spaces/{repo_id}" |
|
|
return gr.update(value=f"Error: Could not properly handle space creation response. Space may have been created successfully. Check: {repo_url}", visible=True) |
|
|
|
|
|
|
|
|
action_verb = "updating" if is_update else "duplicating" |
|
|
return gr.update(value=f"Error {action_verb} Transformers.js space: {error_msg}", visible=True) |
|
|
|
|
|
if sdk == "static": |
|
|
import time |
|
|
|
|
|
|
|
|
add_anycoder_tag_to_readme(api, repo_id) |
|
|
|
|
|
|
|
|
files = {} |
|
|
parse_error = None |
|
|
try: |
|
|
files = parse_multipage_html_output(code) |
|
|
print(f"[Deploy] Parsed files: {list(files.keys())}") |
|
|
files = validate_and_autofix_files(files) |
|
|
print(f"[Deploy] After validation: {list(files.keys())}") |
|
|
except Exception as e: |
|
|
parse_error = str(e) |
|
|
print(f"[Deploy] Parse error: {parse_error}") |
|
|
files = {} |
|
|
|
|
|
|
|
|
if isinstance(files, dict) and len(files) > 0 and files.get('index.html'): |
|
|
import tempfile |
|
|
import os |
|
|
|
|
|
try: |
|
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
|
|
|
|
for rel_path, content in files.items(): |
|
|
safe_rel_path = rel_path.strip().lstrip('/') |
|
|
abs_path = os.path.join(tmpdir, safe_rel_path) |
|
|
os.makedirs(os.path.dirname(abs_path), exist_ok=True) |
|
|
with open(abs_path, 'w') as fh: |
|
|
fh.write(content) |
|
|
|
|
|
|
|
|
api.upload_folder( |
|
|
folder_path=tmpdir, |
|
|
repo_id=repo_id, |
|
|
repo_type="space" |
|
|
) |
|
|
space_url = f"https://huggingface.co/spaces/{repo_id}" |
|
|
action_text = "Updated" if is_update else "Deployed" |
|
|
return gr.update(value=f"✅ {action_text}! [Open your Space here]({space_url})", visible=True) |
|
|
except Exception as e: |
|
|
error_msg = str(e) |
|
|
if "403 Forbidden" in error_msg and "write token" in error_msg: |
|
|
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) |
|
|
else: |
|
|
return gr.update(value=f"Error uploading static app folder: {e}", visible=True) |
|
|
|
|
|
|
|
|
file_name = "index.html" |
|
|
|
|
|
|
|
|
if language == "comfyui": |
|
|
print("[Deploy] Converting ComfyUI JSON to prettified HTML display") |
|
|
code = prettify_comfyui_json_for_html(code) |
|
|
|
|
|
max_attempts = 3 |
|
|
for attempt in range(max_attempts): |
|
|
import tempfile |
|
|
with tempfile.NamedTemporaryFile("w", suffix=".html", delete=False) as f: |
|
|
f.write(code) |
|
|
temp_path = f.name |
|
|
try: |
|
|
api.upload_file( |
|
|
path_or_fileobj=temp_path, |
|
|
path_in_repo=file_name, |
|
|
repo_id=repo_id, |
|
|
repo_type="space" |
|
|
) |
|
|
space_url = f"https://huggingface.co/spaces/{repo_id}" |
|
|
action_text = "Updated" if is_update else "Deployed" |
|
|
return gr.update(value=f"✅ {action_text}! [Open your Space here]({space_url})", visible=True) |
|
|
except Exception as e: |
|
|
error_msg = str(e) |
|
|
if "403 Forbidden" in error_msg and "write token" in error_msg: |
|
|
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) |
|
|
elif attempt < max_attempts - 1: |
|
|
time.sleep(2) |
|
|
else: |
|
|
return gr.update(value=f"Error uploading file after {max_attempts} attempts: {e}. Please check your permissions and try again.", visible=True) |
|
|
finally: |
|
|
import os |
|
|
os.unlink(temp_path) |
|
|
else: |
|
|
|
|
|
import_statements = extract_import_statements(code) |
|
|
requirements_content = generate_requirements_txt_with_llm(import_statements) |
|
|
|
|
|
import tempfile |
|
|
|
|
|
|
|
|
should_upload_requirements = True |
|
|
if is_update: |
|
|
try: |
|
|
|
|
|
existing_requirements = api.hf_hub_download( |
|
|
repo_id=repo_id, |
|
|
filename="requirements.txt", |
|
|
repo_type="space" |
|
|
) |
|
|
with open(existing_requirements, 'r') as f: |
|
|
existing_content = f.read().strip() |
|
|
|
|
|
|
|
|
if existing_content == requirements_content.strip(): |
|
|
should_upload_requirements = False |
|
|
|
|
|
except Exception: |
|
|
|
|
|
should_upload_requirements = True |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
add_anycoder_tag_to_readme(api, repo_id) |
|
|
|
|
|
|
|
|
if ('=== app.py ===' in code or '=== requirements.txt ===' in code): |
|
|
|
|
|
files = parse_multi_file_python_output(code) |
|
|
if files: |
|
|
|
|
|
if 'app.py' in files and 'requirements.txt' not in files: |
|
|
import_statements = extract_import_statements(files['app.py']) |
|
|
requirements_content = generate_requirements_txt_with_llm(import_statements) |
|
|
files['requirements.txt'] = requirements_content |
|
|
try: |
|
|
from huggingface_hub import CommitOperationAdd |
|
|
operations = [] |
|
|
temp_files = [] |
|
|
|
|
|
|
|
|
for filename, content in files.items(): |
|
|
|
|
|
cleaned_content = content |
|
|
if filename.endswith('.txt') or filename.endswith('.py'): |
|
|
|
|
|
lines = cleaned_content.split('\n') |
|
|
clean_lines = [] |
|
|
for line in lines: |
|
|
stripped = line.strip() |
|
|
|
|
|
if stripped == '```' or (stripped.startswith('```') and len(stripped) <= 10): |
|
|
continue |
|
|
clean_lines.append(line) |
|
|
cleaned_content = '\n'.join(clean_lines) |
|
|
|
|
|
|
|
|
with tempfile.NamedTemporaryFile("w", suffix=f".{filename.split('.')[-1]}", delete=False) as f: |
|
|
f.write(cleaned_content) |
|
|
temp_path = f.name |
|
|
temp_files.append(temp_path) |
|
|
|
|
|
|
|
|
operations.append(CommitOperationAdd( |
|
|
path_in_repo=filename, |
|
|
path_or_fileobj=temp_path |
|
|
)) |
|
|
|
|
|
|
|
|
api.create_commit( |
|
|
repo_id=repo_id, |
|
|
operations=operations, |
|
|
commit_message=f"{'Update' if is_update else 'Deploy'} Gradio app with multiple files", |
|
|
repo_type="space" |
|
|
) |
|
|
|
|
|
|
|
|
for temp_path in temp_files: |
|
|
try: |
|
|
os.unlink(temp_path) |
|
|
except Exception: |
|
|
pass |
|
|
|
|
|
space_url = f"https://huggingface.co/spaces/{repo_id}" |
|
|
action_text = "Updated" if is_update else "Deployed" |
|
|
return gr.update(value=f"✅ {action_text}! [Open your Space here]({space_url})", visible=True) |
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
for temp_path in temp_files: |
|
|
try: |
|
|
os.unlink(temp_path) |
|
|
except Exception: |
|
|
pass |
|
|
|
|
|
error_msg = str(e) |
|
|
if "403 Forbidden" in error_msg and "write token" in error_msg: |
|
|
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) |
|
|
else: |
|
|
return gr.update(value=f"Error uploading multi-file app: {e}", visible=True) |
|
|
else: |
|
|
|
|
|
pass |
|
|
|
|
|
|
|
|
file_name = "app.py" |
|
|
with tempfile.NamedTemporaryFile("w", suffix=f".{file_name.split('.')[-1]}", delete=False) as f: |
|
|
f.write(code) |
|
|
temp_path = f.name |
|
|
try: |
|
|
api.upload_file( |
|
|
path_or_fileobj=temp_path, |
|
|
path_in_repo=file_name, |
|
|
repo_id=repo_id, |
|
|
repo_type="space" |
|
|
) |
|
|
space_url = f"https://huggingface.co/spaces/{repo_id}" |
|
|
action_text = "Updated" if is_update else "Deployed" |
|
|
return gr.update(value=f"✅ {action_text}! [Open your Space here]({space_url})", visible=True) |
|
|
except Exception as e: |
|
|
error_msg = str(e) |
|
|
if "403 Forbidden" in error_msg and "write token" in error_msg: |
|
|
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) |
|
|
else: |
|
|
return gr.update(value=f"Error uploading file: {e}", visible=True) |
|
|
finally: |
|
|
import os |
|
|
os.unlink(temp_path) |
|
|
|
|
|
|
|
|
def gather_code_for_deploy(code_text, language, html_part, js_part, css_part): |
|
|
|
|
|
if language == "transformers.js": |
|
|
|
|
|
files = { |
|
|
'index.html': html_part or '', |
|
|
'index.js': js_part or '', |
|
|
'style.css': css_part or '', |
|
|
} |
|
|
if files['index.html'] and files['index.js'] and files['style.css']: |
|
|
return format_transformers_js_output(files) |
|
|
return code_text |
|
|
deploy_btn.click( |
|
|
gather_code_for_deploy, |
|
|
inputs=[code_output, language_dropdown, tjs_html_code, tjs_js_code, tjs_css_code], |
|
|
outputs=[code_output], |
|
|
queue=False, |
|
|
).then( |
|
|
deploy_with_history_tracking, |
|
|
inputs=[code_output, language_dropdown, history], |
|
|
outputs=[deploy_status, history] |
|
|
).then( |
|
|
lambda hist: history_to_chatbot_messages(hist), |
|
|
inputs=[history], |
|
|
outputs=[chat_history] |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def handle_auth_update(profile: Optional[gr.OAuthProfile] = None, token: Optional[gr.OAuthToken] = None): |
|
|
return update_ui_for_auth_status(profile, token) |
|
|
|
|
|
|
|
|
login_button.click( |
|
|
handle_auth_update, |
|
|
inputs=[], |
|
|
outputs=[input, btn], |
|
|
queue=False |
|
|
) |
|
|
|
|
|
|
|
|
demo.load( |
|
|
handle_auth_update, |
|
|
inputs=[], |
|
|
outputs=[input, btn], |
|
|
queue=False |
|
|
) |
|
|
|
|
|
|
|
|
def load_trending_models(): |
|
|
"""Load trending models from HuggingFace Hub""" |
|
|
models = get_trending_models(limit=10) |
|
|
|
|
|
choices = [(display, model_id) for display, model_id in models] |
|
|
|
|
|
default_value = models[0][1] if models and len(models) > 0 and models[0][1] != "" else None |
|
|
return gr.update(choices=choices, value=default_value) |
|
|
|
|
|
demo.load( |
|
|
load_trending_models, |
|
|
inputs=[], |
|
|
outputs=[trending_models_dropdown], |
|
|
queue=False |
|
|
) |
|
|
|
|
|
|
|
|
def load_trending_spaces(): |
|
|
"""Load trending spaces from HuggingFace Hub""" |
|
|
spaces = get_trending_spaces(limit=10) |
|
|
|
|
|
choices = [(display, space_id) for display, space_id in spaces] |
|
|
|
|
|
default_value = spaces[0][1] if spaces and len(spaces) > 0 and spaces[0][1] != "" else None |
|
|
return gr.update(choices=choices, value=default_value) |
|
|
|
|
|
demo.load( |
|
|
load_trending_spaces, |
|
|
inputs=[], |
|
|
outputs=[trending_spaces_dropdown], |
|
|
queue=False |
|
|
) |
|
|
|
|
|
|
|
|
def handle_trending_model_selection(model_id, hist, is_first): |
|
|
"""Handle when user selects a trending model""" |
|
|
|
|
|
if is_first: |
|
|
return [ |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
hist, |
|
|
history_to_chatbot_messages(hist), |
|
|
history_to_chatbot_messages(hist), |
|
|
False, |
|
|
gr.update(visible=False), |
|
|
"" |
|
|
] |
|
|
|
|
|
if not model_id or model_id == "": |
|
|
return [ |
|
|
gr.update(value="Please select a model.", visible=True), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
hist, |
|
|
history_to_chatbot_messages(hist), |
|
|
history_to_chatbot_messages(hist), |
|
|
False, |
|
|
gr.update(visible=False), |
|
|
"" |
|
|
] |
|
|
|
|
|
|
|
|
status, code, language, model_url = import_model_from_hf(model_id) |
|
|
|
|
|
|
|
|
loaded_history = hist + [[f"Imported model: {model_id}", code]] |
|
|
|
|
|
|
|
|
code_lang = "python" |
|
|
|
|
|
|
|
|
show_switch_btn = "Found multiple code options" in status |
|
|
|
|
|
return [ |
|
|
gr.update(value=status, visible=True), |
|
|
gr.update(value=code, language=code_lang), |
|
|
gr.update(value=language), |
|
|
loaded_history, |
|
|
history_to_chatbot_messages(loaded_history), |
|
|
history_to_chatbot_messages(loaded_history), |
|
|
False, |
|
|
gr.update(visible=show_switch_btn), |
|
|
model_id |
|
|
] |
|
|
|
|
|
trending_models_dropdown.change( |
|
|
handle_trending_model_selection, |
|
|
inputs=[trending_models_dropdown, history, models_first_change], |
|
|
outputs=[ |
|
|
trending_models_status, |
|
|
code_output, |
|
|
language_dropdown, |
|
|
history, |
|
|
history_output, |
|
|
chat_history, |
|
|
models_first_change, |
|
|
switch_model_code_btn, |
|
|
current_trending_model_id |
|
|
] |
|
|
) |
|
|
|
|
|
|
|
|
def handle_switch_model_code(model_id, current_code, hist): |
|
|
"""Switch between inference provider and local transformers/diffusers code""" |
|
|
if not model_id: |
|
|
return [ |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
hist, |
|
|
history_to_chatbot_messages(hist), |
|
|
history_to_chatbot_messages(hist) |
|
|
] |
|
|
|
|
|
status_msg, new_code = switch_model_code_type(model_id, current_code) |
|
|
|
|
|
|
|
|
switch_history = hist + [[f"Switched code type for {model_id}", new_code]] |
|
|
|
|
|
return [ |
|
|
gr.update(value=status_msg, visible=True), |
|
|
gr.update(value=new_code, language="python"), |
|
|
switch_history, |
|
|
history_to_chatbot_messages(switch_history), |
|
|
history_to_chatbot_messages(switch_history) |
|
|
] |
|
|
|
|
|
switch_model_code_btn.click( |
|
|
handle_switch_model_code, |
|
|
inputs=[current_trending_model_id, code_output, history], |
|
|
outputs=[ |
|
|
trending_models_status, |
|
|
code_output, |
|
|
history, |
|
|
history_output, |
|
|
chat_history |
|
|
] |
|
|
) |
|
|
|
|
|
|
|
|
def handle_trending_space_selection(space_id, hist, is_first): |
|
|
"""Handle when user selects a trending space""" |
|
|
|
|
|
if is_first: |
|
|
return [ |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
hist, |
|
|
history_to_chatbot_messages(hist), |
|
|
history_to_chatbot_messages(hist), |
|
|
gr.update(), |
|
|
False |
|
|
] |
|
|
|
|
|
if not space_id or space_id == "": |
|
|
return [ |
|
|
gr.update(value="Please select a space.", visible=True), |
|
|
gr.update(), |
|
|
gr.update(), |
|
|
hist, |
|
|
history_to_chatbot_messages(hist), |
|
|
history_to_chatbot_messages(hist), |
|
|
gr.update(visible=True), |
|
|
False |
|
|
] |
|
|
|
|
|
|
|
|
status, code, language, space_url = import_space_from_hf(space_id) |
|
|
|
|
|
|
|
|
loaded_history = hist + [[f"Imported space: {space_id}", code]] |
|
|
|
|
|
|
|
|
if language == "gradio" or language == "streamlit": |
|
|
code_lang = "python" |
|
|
elif language == "transformers.js": |
|
|
code_lang = "html" |
|
|
else: |
|
|
code_lang = "html" |
|
|
|
|
|
return [ |
|
|
gr.update(value=status, visible=True), |
|
|
gr.update(value=code, language=code_lang), |
|
|
gr.update(value=language), |
|
|
loaded_history, |
|
|
history_to_chatbot_messages(loaded_history), |
|
|
history_to_chatbot_messages(loaded_history), |
|
|
gr.update(value="Publish", visible=True), |
|
|
False |
|
|
] |
|
|
|
|
|
trending_spaces_dropdown.change( |
|
|
handle_trending_space_selection, |
|
|
inputs=[trending_spaces_dropdown, history, spaces_first_change], |
|
|
outputs=[ |
|
|
trending_spaces_status, |
|
|
code_output, |
|
|
language_dropdown, |
|
|
history, |
|
|
history_output, |
|
|
chat_history, |
|
|
deploy_btn, |
|
|
spaces_first_change |
|
|
] |
|
|
) |
|
|
|
|
|
|