""" 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 # Monkey-patch httpx to increase timeout for OAuth # This prevents ReadTimeout errors during HuggingFace OAuth flow _original_client_init = httpx.AsyncClient.__init__ def _patched_client_init(self, *args, **kwargs): # If no timeout is specified, use longer timeouts if 'timeout' not in kwargs: kwargs['timeout'] = httpx.Timeout( connect=30.0, # 30 seconds for connection read=60.0, # 60 seconds for reading response (increased from default 5s) write=30.0, # 30 seconds for writing pool=30.0 # 30 seconds for pool operations ) 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 ) # 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; } /* 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("") # Track current trending model for code switching agent_conversation_state = gr.State({ "stage": "initial", # initial, waiting_for_answers, generating "original_query": "", "questions": "" }) with gr.Sidebar() as sidebar: login_button = gr.LoginButton() # App link (visible on all devices) mobile_link = gr.HTML( """ """, visible=True ) # 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) # Trending HuggingFace Models section trending_models_dropdown = gr.Dropdown( label="🔥 Trending HuggingFace Models", choices=[], # Will be populated on load 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 HuggingFace Spaces section trending_spaces_dropdown = gr.Dropdown( label="🚀 Trending HuggingFace Spaces", choices=[], # Will be populated on load value=None, interactive=True, visible=True ) trending_spaces_status = gr.Markdown(visible=False) # Chat history display in sidebar chat_history = gr.Chatbot( label="Conversation History", type="messages", height=300, show_copy_button=True, visible=True ) # Input textbox for new messages 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 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 ) # Agent mode checkbox 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 ) # 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 [] # chat_history ] 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("