""" 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 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 ) # Main application with proper Gradio theming 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; } """ ) 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) with gr.Sidebar() as sidebar: login_button = gr.LoginButton() # Unified Import section 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) input = gr.Textbox( label="What would you like to build?", placeholder="🔒 Please log in with Hugging Face to use AnyCoder...", lines=3, visible=True, interactive=False ) # Language dropdown for code generation (add Streamlit and Gradio as first-class options) language_choices = [ "html", "gradio", "transformers.js", "streamlit", "comfyui", "react" ] language_dropdown = gr.Dropdown( choices=language_choices, value="html", label="Code Language", visible=True ) # Removed image generation components 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 components (visible by default) --- 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") # --- End move --- # Removed media generation and web search UI components # Removed media generation toggle event handlers 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") # Removed web search availability indicator 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] ) # --- Remove deploy/app name/sdk from bottom column --- # (delete the gr.Column() block containing space_name_input, sdk_dropdown, deploy_btn, deploy_status) 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" ) # Transformers.js multi-file editors (hidden by default) 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") # Python multi-file editors (hidden by default) for Gradio/Streamlit 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") # Static HTML multi-file editors (hidden by default). Use separate tab groups for different file counts. 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") # React Next.js multi-file editors (hidden by default) 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") # Removed Import Logs tab for cleaner UI # History tab hidden per user request # with gr.Tab("History"): # history_output = gr.Chatbot(show_label=False, height=400, type="messages") # Keep history_output as hidden component to maintain functionality history_output = gr.Chatbot(show_label=False, height=400, type="messages", visible=False) # Global generation status view (disabled placeholder) generating_status = gr.Markdown("", visible=False) # Unified import handler 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(), # keep import header as-is gr.update(), # keep import button as-is gr.update() # language dropdown - no change ] kind, meta = _parse_repo_or_model_url(url) if kind == "hf_space": status, code = load_project_from_url(url) # Extract space info for deployment 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]] # Determine the correct language/framework based on the imported content code_lang = "html" # default framework_type = "html" # for language dropdown # Check imports to determine framework for Python code 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: # This is a transformers.js app with the combined format code_lang = "html" # Use html for code display framework_type = "transformers.js" # But set dropdown to transformers.js elif ("import " in code or "def " in code) and not ("" in code or "") or code.strip().startswith("") or code.strip().startswith("