Spaces:
Running
Running
add react support
Browse files
app.py
CHANGED
|
@@ -38,7 +38,7 @@ from dashscope.utils.oss_utils import check_and_upload_local
|
|
| 38 |
|
| 39 |
# Gradio supported languages for syntax highlighting
|
| 40 |
GRADIO_SUPPORTED_LANGUAGES = [
|
| 41 |
-
"python", "json", "html"
|
| 42 |
]
|
| 43 |
|
| 44 |
def get_gradio_language(language):
|
|
@@ -49,6 +49,8 @@ def get_gradio_language(language):
|
|
| 49 |
return "python"
|
| 50 |
if language == "comfyui":
|
| 51 |
return "json"
|
|
|
|
|
|
|
| 52 |
return language if language in GRADIO_SUPPORTED_LANGUAGES else None
|
| 53 |
|
| 54 |
# Search/Replace Constants
|
|
@@ -1863,6 +1865,78 @@ Requirements:
|
|
| 1863 |
IMPORTANT: Always include "Built with anycoder" as clickable text in the header/top section of your application that links to https://huggingface.co/spaces/akhaliq/anycoder
|
| 1864 |
"""
|
| 1865 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1866 |
|
| 1867 |
# Gradio system prompts will be dynamically populated by update_gradio_system_prompts()
|
| 1868 |
GRADIO_SYSTEM_PROMPT = ""
|
|
@@ -3068,6 +3142,22 @@ def parse_svelte_output(text):
|
|
| 3068 |
results['src/app.css'] = css_match.group(1).strip()
|
| 3069 |
return results
|
| 3070 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3071 |
def format_svelte_output(files):
|
| 3072 |
"""Format Svelte files into === filename === sections (generic)."""
|
| 3073 |
return format_multipage_output(files)
|
|
@@ -6213,6 +6303,8 @@ Generate the exact search/replace blocks needed to make these changes."""
|
|
| 6213 |
system_prompt = GradioFollowUpSystemPrompt
|
| 6214 |
elif language == "svelte":
|
| 6215 |
system_prompt = FollowUpSystemPrompt # Use generic follow-up for Svelte
|
|
|
|
|
|
|
| 6216 |
else:
|
| 6217 |
system_prompt = FollowUpSystemPrompt
|
| 6218 |
else:
|
|
@@ -6224,6 +6316,8 @@ Generate the exact search/replace blocks needed to make these changes."""
|
|
| 6224 |
system_prompt = TRANSFORMERS_JS_SYSTEM_PROMPT
|
| 6225 |
elif language == "svelte":
|
| 6226 |
system_prompt = SVELTE_SYSTEM_PROMPT
|
|
|
|
|
|
|
| 6227 |
elif language == "gradio":
|
| 6228 |
system_prompt = GRADIO_SYSTEM_PROMPT
|
| 6229 |
elif language == "streamlit":
|
|
@@ -8338,7 +8432,7 @@ with gr.Blocks(
|
|
| 8338 |
)
|
| 8339 |
# Language dropdown for code generation (add Streamlit and Gradio as first-class options)
|
| 8340 |
language_choices = [
|
| 8341 |
-
"html", "gradio", "transformers.js", "streamlit", "comfyui"
|
| 8342 |
]
|
| 8343 |
language_dropdown = gr.Dropdown(
|
| 8344 |
choices=language_choices,
|
|
@@ -8513,6 +8607,28 @@ with gr.Blocks(
|
|
| 8513 |
static_code_5_4 = gr.Code(language="html", lines=18, interactive=True, label="file 4")
|
| 8514 |
with gr.Tab("file 5") as static_tab_5_5:
|
| 8515 |
static_code_5_5 = gr.Code(language="html", lines=18, interactive=True, label="file 5")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8516 |
# Removed Import Logs tab for cleaner UI
|
| 8517 |
# History tab hidden per user request
|
| 8518 |
# with gr.Tab("History"):
|
|
@@ -8647,7 +8763,60 @@ with gr.Blocks(
|
|
| 8647 |
gr.update(value=files.get('index.html', '')),
|
| 8648 |
gr.update(value=files.get('index.js', '')),
|
| 8649 |
gr.update(value=files.get('style.css', '')),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8650 |
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8651 |
else:
|
| 8652 |
return [
|
| 8653 |
gr.update(visible=True), # code_output shown
|
|
@@ -8655,12 +8824,23 @@ with gr.Blocks(
|
|
| 8655 |
gr.update(),
|
| 8656 |
gr.update(),
|
| 8657 |
gr.update(),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8658 |
]
|
| 8659 |
|
| 8660 |
language_dropdown.change(
|
| 8661 |
toggle_editors,
|
| 8662 |
inputs=[language_dropdown, code_output],
|
| 8663 |
-
outputs=[code_output, tjs_group, tjs_html_code, tjs_js_code, tjs_css_code],
|
| 8664 |
)
|
| 8665 |
|
| 8666 |
# Toggle Python multi-file editors for Gradio/Streamlit
|
|
@@ -9279,6 +9459,7 @@ with gr.Blocks(
|
|
| 9279 |
language_to_sdk_map = {
|
| 9280 |
"gradio": "gradio",
|
| 9281 |
"streamlit": "docker", # Use 'docker' for Streamlit Spaces
|
|
|
|
| 9282 |
"html": "static",
|
| 9283 |
"transformers.js": "static", # Transformers.js uses static SDK
|
| 9284 |
"svelte": "static", # Svelte uses static SDK
|
|
@@ -9299,22 +9480,89 @@ with gr.Blocks(
|
|
| 9299 |
)
|
| 9300 |
except Exception as e:
|
| 9301 |
return gr.update(value=f"Error creating Space: {e}", visible=True)
|
| 9302 |
-
# Streamlit/docker logic
|
| 9303 |
-
if sdk == "docker":
|
| 9304 |
try:
|
| 9305 |
# For new spaces, duplicate the template first
|
| 9306 |
if not is_update:
|
| 9307 |
-
# Use duplicate_space to create a Streamlit template space
|
| 9308 |
from huggingface_hub import duplicate_space
|
| 9309 |
|
| 9310 |
-
|
| 9311 |
-
|
| 9312 |
-
|
| 9313 |
-
|
| 9314 |
-
|
| 9315 |
-
|
| 9316 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9317 |
|
|
|
|
| 9318 |
# Generate requirements.txt for Streamlit apps and upload only if needed
|
| 9319 |
import_statements = extract_import_statements(code)
|
| 9320 |
requirements_content = generate_requirements_txt_with_llm(import_statements)
|
|
|
|
| 38 |
|
| 39 |
# Gradio supported languages for syntax highlighting
|
| 40 |
GRADIO_SUPPORTED_LANGUAGES = [
|
| 41 |
+
"python", "json", "html", "javascript"
|
| 42 |
]
|
| 43 |
|
| 44 |
def get_gradio_language(language):
|
|
|
|
| 49 |
return "python"
|
| 50 |
if language == "comfyui":
|
| 51 |
return "json"
|
| 52 |
+
if language == "react":
|
| 53 |
+
return "javascript"
|
| 54 |
return language if language in GRADIO_SUPPORTED_LANGUAGES else None
|
| 55 |
|
| 56 |
# Search/Replace Constants
|
|
|
|
| 1865 |
IMPORTANT: Always include "Built with anycoder" as clickable text in the header/top section of your application that links to https://huggingface.co/spaces/akhaliq/anycoder
|
| 1866 |
"""
|
| 1867 |
|
| 1868 |
+
REACT_SYSTEM_PROMPT = """You are an expert React and Next.js developer creating a modern Next.js application.
|
| 1869 |
+
|
| 1870 |
+
**🚨 CRITICAL: DO NOT Generate README.md Files**
|
| 1871 |
+
|- NEVER generate README.md files under any circumstances
|
| 1872 |
+
|- A template README.md is automatically provided and will be overridden by the deployment system
|
| 1873 |
+
|- Generating a README.md will break the deployment process
|
| 1874 |
+
|
| 1875 |
+
You will generate a Next.js project with TypeScript/JSX components. Follow this exact structure:
|
| 1876 |
+
|
| 1877 |
+
Project Structure:
|
| 1878 |
+
- Dockerfile (Docker configuration for deployment)
|
| 1879 |
+
- package.json (dependencies and scripts)
|
| 1880 |
+
- next.config.js (Next.js configuration)
|
| 1881 |
+
- postcss.config.js (PostCSS configuration)
|
| 1882 |
+
- tailwind.config.js (Tailwind CSS configuration)
|
| 1883 |
+
- components/[Component files as needed]
|
| 1884 |
+
- pages/_app.js (Next.js app wrapper)
|
| 1885 |
+
- pages/index.js (home page)
|
| 1886 |
+
- pages/api/[API routes as needed]
|
| 1887 |
+
- styles/globals.css (global styles)
|
| 1888 |
+
|
| 1889 |
+
Output format (CRITICAL):
|
| 1890 |
+
- Return ONLY a series of file sections, each starting with a filename line:
|
| 1891 |
+
=== Dockerfile ===
|
| 1892 |
+
...file content...
|
| 1893 |
+
|
| 1894 |
+
=== package.json ===
|
| 1895 |
+
...file content...
|
| 1896 |
+
|
| 1897 |
+
(repeat for all files)
|
| 1898 |
+
- Do NOT wrap files in Markdown code fences or use === markers inside file content
|
| 1899 |
+
|
| 1900 |
+
CRITICAL Requirements:
|
| 1901 |
+
1. Always include a Dockerfile configured for Node.js deployment
|
| 1902 |
+
2. Use Next.js with TypeScript/JSX (.jsx files for components)
|
| 1903 |
+
3. Include Tailwind CSS for styling (in postcss.config.js and tailwind.config.js)
|
| 1904 |
+
4. Create necessary components in the components/ directory
|
| 1905 |
+
5. Create API routes in pages/api/ directory for backend logic
|
| 1906 |
+
6. pages/_app.js should import and use globals.css
|
| 1907 |
+
7. pages/index.js should be the main entry point
|
| 1908 |
+
8. Keep package.json with essential dependencies
|
| 1909 |
+
9. Use modern React patterns and best practices
|
| 1910 |
+
10. Make the application fully responsive
|
| 1911 |
+
11. Include proper error handling and loading states
|
| 1912 |
+
12. Follow accessibility best practices
|
| 1913 |
+
|
| 1914 |
+
Dockerfile Requirements:
|
| 1915 |
+
- Use Node.js 18+ base image
|
| 1916 |
+
- Install dependencies with npm install
|
| 1917 |
+
- Run "npm run build" to build Next.js app
|
| 1918 |
+
- Expose port 3000
|
| 1919 |
+
- Start with "npm start"
|
| 1920 |
+
|
| 1921 |
+
IMPORTANT: Always include "Built with anycoder" as clickable text in the header/top section of your application that links to https://huggingface.co/spaces/akhaliq/anycoder
|
| 1922 |
+
"""
|
| 1923 |
+
|
| 1924 |
+
REACT_FOLLOW_UP_SYSTEM_PROMPT = """You are an expert React and Next.js developer modifying an existing Next.js application.
|
| 1925 |
+
The user wants to apply changes based on their request.
|
| 1926 |
+
You MUST output ONLY the changes required using the following SEARCH/REPLACE block format. Do NOT output the entire file.
|
| 1927 |
+
Explain the changes briefly *before* the blocks if necessary, but the code changes THEMSELVES MUST be within the blocks.
|
| 1928 |
+
|
| 1929 |
+
Format Rules:
|
| 1930 |
+
1. Start with <<<<<<< SEARCH
|
| 1931 |
+
2. Include the exact lines that need to be changed (with full context, at least 3 lines before and after)
|
| 1932 |
+
3. Follow with =======
|
| 1933 |
+
4. Include the replacement lines
|
| 1934 |
+
5. End with >>>>>>> REPLACE
|
| 1935 |
+
6. Generate multiple blocks if multiple sections need changes
|
| 1936 |
+
|
| 1937 |
+
IMPORTANT: Always include "Built with anycoder" as clickable text in the header/top section of your application that links to https://huggingface.co/spaces/akhaliq/anycoder"""
|
| 1938 |
+
|
| 1939 |
+
|
| 1940 |
|
| 1941 |
# Gradio system prompts will be dynamically populated by update_gradio_system_prompts()
|
| 1942 |
GRADIO_SYSTEM_PROMPT = ""
|
|
|
|
| 3142 |
results['src/app.css'] = css_match.group(1).strip()
|
| 3143 |
return results
|
| 3144 |
|
| 3145 |
+
def parse_react_output(text):
|
| 3146 |
+
"""Parse React/Next.js output to extract individual files.
|
| 3147 |
+
|
| 3148 |
+
Supports multi-file sections using === filename === sections.
|
| 3149 |
+
"""
|
| 3150 |
+
if not text:
|
| 3151 |
+
return {}
|
| 3152 |
+
|
| 3153 |
+
# Use the generic multipage parser
|
| 3154 |
+
try:
|
| 3155 |
+
files = parse_multipage_html_output(text) or {}
|
| 3156 |
+
except Exception:
|
| 3157 |
+
files = {}
|
| 3158 |
+
|
| 3159 |
+
return files if isinstance(files, dict) and files else {}
|
| 3160 |
+
|
| 3161 |
def format_svelte_output(files):
|
| 3162 |
"""Format Svelte files into === filename === sections (generic)."""
|
| 3163 |
return format_multipage_output(files)
|
|
|
|
| 6303 |
system_prompt = GradioFollowUpSystemPrompt
|
| 6304 |
elif language == "svelte":
|
| 6305 |
system_prompt = FollowUpSystemPrompt # Use generic follow-up for Svelte
|
| 6306 |
+
elif language == "react":
|
| 6307 |
+
system_prompt = REACT_FOLLOW_UP_SYSTEM_PROMPT
|
| 6308 |
else:
|
| 6309 |
system_prompt = FollowUpSystemPrompt
|
| 6310 |
else:
|
|
|
|
| 6316 |
system_prompt = TRANSFORMERS_JS_SYSTEM_PROMPT
|
| 6317 |
elif language == "svelte":
|
| 6318 |
system_prompt = SVELTE_SYSTEM_PROMPT
|
| 6319 |
+
elif language == "react":
|
| 6320 |
+
system_prompt = REACT_SYSTEM_PROMPT
|
| 6321 |
elif language == "gradio":
|
| 6322 |
system_prompt = GRADIO_SYSTEM_PROMPT
|
| 6323 |
elif language == "streamlit":
|
|
|
|
| 8432 |
)
|
| 8433 |
# Language dropdown for code generation (add Streamlit and Gradio as first-class options)
|
| 8434 |
language_choices = [
|
| 8435 |
+
"html", "gradio", "transformers.js", "streamlit", "comfyui", "react"
|
| 8436 |
]
|
| 8437 |
language_dropdown = gr.Dropdown(
|
| 8438 |
choices=language_choices,
|
|
|
|
| 8607 |
static_code_5_4 = gr.Code(language="html", lines=18, interactive=True, label="file 4")
|
| 8608 |
with gr.Tab("file 5") as static_tab_5_5:
|
| 8609 |
static_code_5_5 = gr.Code(language="html", lines=18, interactive=True, label="file 5")
|
| 8610 |
+
# React Next.js multi-file editors (hidden by default)
|
| 8611 |
+
with gr.Group(visible=False) as react_group:
|
| 8612 |
+
with gr.Tabs():
|
| 8613 |
+
with gr.Tab("Dockerfile"):
|
| 8614 |
+
react_code_dockerfile = gr.Code(language="bash", lines=15, interactive=True, label="Dockerfile")
|
| 8615 |
+
with gr.Tab("package.json"):
|
| 8616 |
+
react_code_package_json = gr.Code(language="json", lines=20, interactive=True, label="package.json")
|
| 8617 |
+
with gr.Tab("next.config.js"):
|
| 8618 |
+
react_code_next_config = gr.Code(language="javascript", lines=15, interactive=True, label="next.config.js")
|
| 8619 |
+
with gr.Tab("postcss.config.js"):
|
| 8620 |
+
react_code_postcss_config = gr.Code(language="javascript", lines=10, interactive=True, label="postcss.config.js")
|
| 8621 |
+
with gr.Tab("tailwind.config.js"):
|
| 8622 |
+
react_code_tailwind_config = gr.Code(language="javascript", lines=15, interactive=True, label="tailwind.config.js")
|
| 8623 |
+
with gr.Tab("pages/_app.js"):
|
| 8624 |
+
react_code_pages_app = gr.Code(language="javascript", lines=15, interactive=True, label="pages/_app.js")
|
| 8625 |
+
with gr.Tab("pages/index.js"):
|
| 8626 |
+
react_code_pages_index = gr.Code(language="javascript", lines=20, interactive=True, label="pages/index.js")
|
| 8627 |
+
with gr.Tab("components/ChatApp.jsx"):
|
| 8628 |
+
react_code_components = gr.Code(language="javascript", lines=25, interactive=True, label="components/ChatApp.jsx")
|
| 8629 |
+
with gr.Tab("styles/globals.css"):
|
| 8630 |
+
react_code_styles = gr.Code(language="css", lines=20, interactive=True, label="styles/globals.css")
|
| 8631 |
+
|
| 8632 |
# Removed Import Logs tab for cleaner UI
|
| 8633 |
# History tab hidden per user request
|
| 8634 |
# with gr.Tab("History"):
|
|
|
|
| 8763 |
gr.update(value=files.get('index.html', '')),
|
| 8764 |
gr.update(value=files.get('index.js', '')),
|
| 8765 |
gr.update(value=files.get('style.css', '')),
|
| 8766 |
+
# React group hidden
|
| 8767 |
+
gr.update(visible=False),
|
| 8768 |
+
gr.update(),
|
| 8769 |
+
gr.update(),
|
| 8770 |
+
gr.update(),
|
| 8771 |
+
gr.update(),
|
| 8772 |
+
gr.update(),
|
| 8773 |
+
gr.update(),
|
| 8774 |
+
gr.update(),
|
| 8775 |
+
gr.update(),
|
| 8776 |
+
gr.update(),
|
| 8777 |
]
|
| 8778 |
+
elif language == "react":
|
| 8779 |
+
files = parse_react_output(code_text or "")
|
| 8780 |
+
# Show react group if we have files, else show single code editor
|
| 8781 |
+
editors_visible = True if files else False
|
| 8782 |
+
if editors_visible:
|
| 8783 |
+
return [
|
| 8784 |
+
gr.update(visible=False), # code_output hidden
|
| 8785 |
+
gr.update(visible=False), # tjs_group hidden
|
| 8786 |
+
gr.update(),
|
| 8787 |
+
gr.update(),
|
| 8788 |
+
gr.update(),
|
| 8789 |
+
# React group shown
|
| 8790 |
+
gr.update(visible=editors_visible), # react_group shown
|
| 8791 |
+
gr.update(value=files.get('Dockerfile', '')),
|
| 8792 |
+
gr.update(value=files.get('package.json', '')),
|
| 8793 |
+
gr.update(value=files.get('next.config.js', '')),
|
| 8794 |
+
gr.update(value=files.get('postcss.config.js', '')),
|
| 8795 |
+
gr.update(value=files.get('tailwind.config.js', '')),
|
| 8796 |
+
gr.update(value=files.get('pages/_app.js', '')),
|
| 8797 |
+
gr.update(value=files.get('pages/index.js', '')),
|
| 8798 |
+
gr.update(value=files.get('components/ChatApp.jsx', '')),
|
| 8799 |
+
gr.update(value=files.get('styles/globals.css', '')),
|
| 8800 |
+
]
|
| 8801 |
+
else:
|
| 8802 |
+
return [
|
| 8803 |
+
gr.update(visible=True), # code_output shown
|
| 8804 |
+
gr.update(visible=False), # tjs_group hidden
|
| 8805 |
+
gr.update(),
|
| 8806 |
+
gr.update(),
|
| 8807 |
+
gr.update(),
|
| 8808 |
+
# React group hidden
|
| 8809 |
+
gr.update(visible=False),
|
| 8810 |
+
gr.update(),
|
| 8811 |
+
gr.update(),
|
| 8812 |
+
gr.update(),
|
| 8813 |
+
gr.update(),
|
| 8814 |
+
gr.update(),
|
| 8815 |
+
gr.update(),
|
| 8816 |
+
gr.update(),
|
| 8817 |
+
gr.update(),
|
| 8818 |
+
gr.update(),
|
| 8819 |
+
]
|
| 8820 |
else:
|
| 8821 |
return [
|
| 8822 |
gr.update(visible=True), # code_output shown
|
|
|
|
| 8824 |
gr.update(),
|
| 8825 |
gr.update(),
|
| 8826 |
gr.update(),
|
| 8827 |
+
# React group hidden
|
| 8828 |
+
gr.update(visible=False),
|
| 8829 |
+
gr.update(),
|
| 8830 |
+
gr.update(),
|
| 8831 |
+
gr.update(),
|
| 8832 |
+
gr.update(),
|
| 8833 |
+
gr.update(),
|
| 8834 |
+
gr.update(),
|
| 8835 |
+
gr.update(),
|
| 8836 |
+
gr.update(),
|
| 8837 |
+
gr.update(),
|
| 8838 |
]
|
| 8839 |
|
| 8840 |
language_dropdown.change(
|
| 8841 |
toggle_editors,
|
| 8842 |
inputs=[language_dropdown, code_output],
|
| 8843 |
+
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],
|
| 8844 |
)
|
| 8845 |
|
| 8846 |
# Toggle Python multi-file editors for Gradio/Streamlit
|
|
|
|
| 9459 |
language_to_sdk_map = {
|
| 9460 |
"gradio": "gradio",
|
| 9461 |
"streamlit": "docker", # Use 'docker' for Streamlit Spaces
|
| 9462 |
+
"react": "docker", # Use 'docker' for React/Next.js Spaces
|
| 9463 |
"html": "static",
|
| 9464 |
"transformers.js": "static", # Transformers.js uses static SDK
|
| 9465 |
"svelte": "static", # Svelte uses static SDK
|
|
|
|
| 9480 |
)
|
| 9481 |
except Exception as e:
|
| 9482 |
return gr.update(value=f"Error creating Space: {e}", visible=True)
|
| 9483 |
+
# Streamlit/React/docker logic
|
| 9484 |
+
if sdk == "docker" and language in ["streamlit", "react"]:
|
| 9485 |
try:
|
| 9486 |
# For new spaces, duplicate the template first
|
| 9487 |
if not is_update:
|
| 9488 |
+
# Use duplicate_space to create a Streamlit or React template space
|
| 9489 |
from huggingface_hub import duplicate_space
|
| 9490 |
|
| 9491 |
+
if language == "react":
|
| 9492 |
+
# Duplicate the React template space
|
| 9493 |
+
duplicated_repo = duplicate_space(
|
| 9494 |
+
from_id="akhaliq/next-js-template",
|
| 9495 |
+
to_id=space_name.strip(),
|
| 9496 |
+
token=token.token,
|
| 9497 |
+
exist_ok=True
|
| 9498 |
+
)
|
| 9499 |
+
else:
|
| 9500 |
+
# Duplicate the streamlit template space
|
| 9501 |
+
duplicated_repo = duplicate_space(
|
| 9502 |
+
from_id="streamlit/streamlit-template-space",
|
| 9503 |
+
to_id=space_name.strip(),
|
| 9504 |
+
token=token.token,
|
| 9505 |
+
exist_ok=True
|
| 9506 |
+
)
|
| 9507 |
+
|
| 9508 |
+
# Handle React or Streamlit deployment
|
| 9509 |
+
if language == "react":
|
| 9510 |
+
# Parse React/Next.js files
|
| 9511 |
+
files = parse_react_output(code)
|
| 9512 |
+
if not files:
|
| 9513 |
+
return gr.update(value="Error: Could not parse React output. Please regenerate the code.", visible=True)
|
| 9514 |
+
|
| 9515 |
+
# Upload React files
|
| 9516 |
+
import tempfile
|
| 9517 |
+
import time
|
| 9518 |
+
|
| 9519 |
+
for file_name, file_content in files.items():
|
| 9520 |
+
if not file_content:
|
| 9521 |
+
continue
|
| 9522 |
+
|
| 9523 |
+
success = False
|
| 9524 |
+
last_error = None
|
| 9525 |
+
max_attempts = 3
|
| 9526 |
+
|
| 9527 |
+
for attempt in range(max_attempts):
|
| 9528 |
+
try:
|
| 9529 |
+
with tempfile.NamedTemporaryFile("w", suffix=f".{file_name.split('.')[-1]}", delete=False) as f:
|
| 9530 |
+
f.write(file_content)
|
| 9531 |
+
temp_path = f.name
|
| 9532 |
+
|
| 9533 |
+
api.upload_file(
|
| 9534 |
+
path_or_fileobj=temp_path,
|
| 9535 |
+
path_in_repo=file_name,
|
| 9536 |
+
repo_id=repo_id,
|
| 9537 |
+
repo_type="space"
|
| 9538 |
+
)
|
| 9539 |
+
success = True
|
| 9540 |
+
break
|
| 9541 |
+
|
| 9542 |
+
except Exception as e:
|
| 9543 |
+
last_error = e
|
| 9544 |
+
error_msg = str(e)
|
| 9545 |
+
if "403 Forbidden" in error_msg and "write token" in error_msg:
|
| 9546 |
+
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)
|
| 9547 |
+
|
| 9548 |
+
if attempt < max_attempts - 1:
|
| 9549 |
+
time.sleep(2)
|
| 9550 |
+
finally:
|
| 9551 |
+
import os
|
| 9552 |
+
if 'temp_path' in locals():
|
| 9553 |
+
os.unlink(temp_path)
|
| 9554 |
+
|
| 9555 |
+
if not success:
|
| 9556 |
+
return gr.update(value=f"Error uploading {file_name}: {last_error}", visible=True)
|
| 9557 |
+
|
| 9558 |
+
# Add anycoder tag to existing README
|
| 9559 |
+
add_anycoder_tag_to_readme(api, repo_id)
|
| 9560 |
+
|
| 9561 |
+
space_url = f"https://huggingface.co/spaces/{repo_id}"
|
| 9562 |
+
action_text = "Updated" if is_update else "Deployed"
|
| 9563 |
+
return gr.update(value=f"✅ {action_text}! [Open your React Space here]({space_url})", visible=True)
|
| 9564 |
|
| 9565 |
+
# Streamlit logic
|
| 9566 |
# Generate requirements.txt for Streamlit apps and upload only if needed
|
| 9567 |
import_statements = extract_import_statements(code)
|
| 9568 |
requirements_content = generate_requirements_txt_with_llm(import_statements)
|