Spaces:
Runtime error
Runtime error
| import gradio as gr | |
| import logging | |
| import json | |
| import re | |
| import torch | |
| import tempfile | |
| import subprocess | |
| from pathlib import Path | |
| from typing import Dict, List, Tuple, Optional, Any | |
| from dataclasses import dataclass | |
| from enum import Enum | |
| from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline | |
| # Configure logging | |
| logging.basicConfig( | |
| level=logging.INFO, | |
| format='%(asctime)s - %(levelname)s - %(message)s', | |
| handlers=[ | |
| logging.StreamHandler(), | |
| logging.FileHandler('gradio_builder.log') | |
| ] | |
| ) | |
| logger = logging.getLogger(__name__) | |
| # Constants and Default Configurations | |
| COMPONENT_CATEGORIES = { | |
| "Basic": { | |
| "Textbox": { | |
| "description": "Text input component", | |
| "properties": { | |
| "label": "Text Input", | |
| "placeholder": "", | |
| "lines": 1, | |
| "type": "text" | |
| }, | |
| "code_snippet": 'gr.Textbox(label="{label}", placeholder="{placeholder}", lines={lines}, type="{type}")' | |
| }, | |
| "Number": { | |
| "description": "Numeric input component", | |
| "properties": { | |
| "label": "Number Input", | |
| "value": 0, | |
| "minimum": None, | |
| "maximum": None | |
| }, | |
| "code_snippet": 'gr.Number(label="{label}", value={value}, minimum={minimum}, maximum={maximum})' | |
| }, | |
| "Button": { | |
| "description": "Clickable button component", | |
| "properties": { | |
| "text": "Button", | |
| "variant": "primary" | |
| }, | |
| "code_snippet": 'gr.Button(value="{text}", variant="{variant}")' | |
| } | |
| }, | |
| "Media": { | |
| "Image": { | |
| "description": "Image display/upload component", | |
| "properties": { | |
| "label": "Image", | |
| "shape": None, | |
| "image_mode": "RGB", | |
| "source": "upload", | |
| "type": "numpy" | |
| }, | |
| "code_snippet": 'gr.Image(label="{label}", shape={shape}, image_mode="{image_mode}", source="{source}", type="{type}")' | |
| }, | |
| "Audio": { | |
| "description": "Audio player/recorder component", | |
| "properties": { | |
| "label": "Audio", | |
| "source": "upload", | |
| "type": "numpy" | |
| }, | |
| "code_snippet": 'gr.Audio(label="{label}", source="{source}", type="{type}")' | |
| }, | |
| "Video": { | |
| "description": "Video player component", | |
| "properties": { | |
| "label": "Video", | |
| "source": "upload" | |
| }, | |
| "code_snippet": 'gr.Video(label="{label}", source="{source}")' | |
| } | |
| }, | |
| "Selection": { | |
| "Dropdown": { | |
| "description": "Dropdown selection component", | |
| "properties": { | |
| "label": "Dropdown", | |
| "choices": [], | |
| "multiselect": False | |
| }, | |
| "code_snippet": 'gr.Dropdown(label="{label}", choices={choices}, multiselect={multiselect})' | |
| }, | |
| "Radio": { | |
| "description": "Radio button group component", | |
| "properties": { | |
| "label": "Radio Group", | |
| "choices": [], | |
| "type": "value" | |
| }, | |
| "code_snippet": 'gr.Radio(label="{label}", choices={choices}, type="{type}")' | |
| }, | |
| "Checkbox": { | |
| "description": "Checkbox component", | |
| "properties": { | |
| "label": "Checkbox", | |
| "value": False | |
| }, | |
| "code_snippet": 'gr.Checkbox(label="{label}", value={value})' | |
| } | |
| } | |
| } | |
| TEMPLATE_CATEGORIES = { | |
| "Basic": { | |
| "Empty": { | |
| "description": "Empty application template", | |
| "components": [], | |
| "layout": "vertical", | |
| "css": "", | |
| "dependencies": [] | |
| }, | |
| "Text Input/Output": { | |
| "description": "Simple text input/output template", | |
| "components": [ | |
| { | |
| "type": "Textbox", | |
| "properties": { | |
| "label": "Input", | |
| "lines": 3 | |
| } | |
| }, | |
| { | |
| "type": "Button", | |
| "properties": { | |
| "text": "Process", | |
| "variant": "primary" | |
| } | |
| }, | |
| { | |
| "type": "Textbox", | |
| "properties": { | |
| "label": "Output", | |
| "lines": 3 | |
| } | |
| } | |
| ], | |
| "layout": "vertical", | |
| "css": "", | |
| "dependencies": [] | |
| } | |
| }, | |
| "Media": { | |
| "Image Processing": { | |
| "description": "Image processing template", | |
| "components": [ | |
| { | |
| "type": "Image", | |
| "properties": { | |
| "label": "Input Image", | |
| "source": "upload" | |
| } | |
| }, | |
| { | |
| "type": "Button", | |
| "properties": { | |
| "text": "Process", | |
| "variant": "primary" | |
| } | |
| }, | |
| { | |
| "type": "Image", | |
| "properties": { | |
| "label": "Output Image", | |
| "source": "upload" | |
| } | |
| } | |
| ], | |
| "layout": "vertical", | |
| "css": "", | |
| "dependencies": ["PIL"] | |
| } | |
| } | |
| } | |
| DEFAULT_THEMES = { | |
| "Light": """ | |
| /* Light theme CSS */ | |
| .gradio-container { | |
| font-family: 'Arial', sans-serif; | |
| background-color: #ffffff; | |
| } | |
| .gradio-button { | |
| background-color: #2196F3; | |
| color: white; | |
| } | |
| """, | |
| "Dark": """ | |
| /* Dark theme CSS */ | |
| .gradio-container { | |
| font-family: 'Arial', sans-serif; | |
| background-color: #2c2c2c; | |
| color: #ffffff; | |
| } | |
| .gradio-button { | |
| background-color: #bb86fc; | |
| color: black; | |
| } | |
| """ | |
| } | |
| class ChatRole(Enum): | |
| SYSTEM = "system" | |
| USER = "user" | |
| ASSISTANT = "assistant" | |
| class ChatMessage: | |
| role: ChatRole | |
| content: str | |
| class GradioAIBuilder: | |
| def __init__(self, model_name: str = "HuggingFaceH4/starchat-beta"): | |
| """Initialize the AI Builder with HuggingFace model""" | |
| try: | |
| self.tokenizer = AutoTokenizer.from_pretrained(model_name) | |
| self.model = AutoModelForCausalLM.from_pretrained( | |
| model_name, | |
| torch_dtype=torch.float16, | |
| device_map="auto", | |
| trust_remote_code=True | |
| ) | |
| self.chat_pipeline = pipeline( | |
| "text-generation", | |
| model=self.model, | |
| tokenizer=self.tokenizer, | |
| max_length=2048, | |
| do_sample=True, | |
| temperature=0.7, | |
| top_p=0.95, | |
| pad_token_id=self.tokenizer.eos_token_id | |
| ) | |
| self.chat_history: List[ChatMessage] = [] | |
| self.current_app: Dict = {} | |
| self.error_log: List[str] = [] | |
| # Initialize system prompt | |
| self.initialize_system_prompt() | |
| except Exception as e: | |
| logger.error(f"Error initializing AI Builder: {str(e)}") | |
| raise | |
| def initialize_system_prompt(self): | |
| """Set up the system prompt for the AI""" | |
| system_prompt = """You are an expert Gradio application builder. Your role is to: | |
| 1. Understand user requirements and convert them into Gradio components | |
| 2. Generate and modify Python code for Gradio applications | |
| 3. Help users customize their applications through natural language instructions | |
| 4. Provide clear explanations of changes and suggestions for improvements | |
| When generating code: | |
| 1. Use proper Python and Gradio syntax | |
| 2. Include necessary imports | |
| 3. Structure the code clearly | |
| 4. Add comments for clarity | |
| 5. Handle errors appropriately | |
| When responding to modifications: | |
| 1. Explain what changes will be made | |
| 2. Show the modified code | |
| 3. Highlight any potential issues | |
| 4. Suggest improvements if applicable | |
| Available Components: | |
| {components} | |
| Available Templates: | |
| {templates} | |
| Response Format: | |
| 1. Brief explanation of understanding | |
| 2. Proposed solution | |
| 3. Code block: | |
| ```python | |
| # Code here | |
| ``` | |
| 4. Additional explanations or suggestions | |
| """ | |
| # Format prompt with available components and templates | |
| components_str = self._format_components_for_prompt() | |
| templates_str = self._format_templates_for_prompt() | |
| self.system_prompt = system_prompt.format( | |
| components=components_str, | |
| templates=templates_str | |
| ) | |
| self.chat_history.append(ChatMessage(ChatRole.SYSTEM, self.system_prompt)) | |
| def _format_components_for_prompt(self) -> str: | |
| """Format component information for the system prompt""" | |
| components_info = [] | |
| for category, components in COMPONENT_CATEGORIES.items(): | |
| category_info = [f"\n{category}:"] | |
| for name, info in components.items(): | |
| props = ", ".join(info["properties"].keys()) | |
| category_info.append(f" - {name}: {info['description']} (Properties: {props})") | |
| components_info.extend(category_info) | |
| return "\n".join(components_info) | |
| def _format_templates_for_prompt(self) -> str: | |
| """Format template information for the system prompt""" | |
| templates_info = [] | |
| for category, templates in TEMPLATE_CATEGORIES.items(): | |
| category_info = [f"\n{category}:"] | |
| for name, info in templates.items(): | |
| category_info.append(f" - {name}: {info['description']}") | |
| templates_info.extend(category_info) | |
| return "\n".join(templates_info) | |
| async def generate_response(self, user_input: str) -> str: | |
| """Generate AI response using HuggingFace model""" | |
| try: | |
| # Format conversation history | |
| conversation = self._format_conversation_history() | |
| conversation += f"\nuser: {user_input}\nassistant:" | |
| # Generate response | |
| response = self.chat_pipeline( | |
| conversation, | |
| max_new_tokens=1024, | |
| do_sample=True, | |
| temperature=0.7, | |
| top_p=0.95 | |
| )[0]['generated_text'] | |
| # Extract assistant's response | |
| response = response.split("assistant:")[-1].strip() | |
| # Update chat history | |
| self.chat_history.append(ChatMessage(ChatRole.USER, user_input)) | |
| self.chat_history.append(ChatMessage(ChatRole.ASSISTANT, response)) | |
| return response | |
| except Exception as e: | |
| error_msg = f"Error generating response: {str(e)}" | |
| logger.error(error_msg) | |
| self.error_log.append(error_msg) | |
| raise | |
| def _format_conversation_history(self) -> str: | |
| """Format the conversation history for the model""" | |
| return "\n".join([ | |
| f"{msg.role.value}: {msg.content}" | |
| for msg in self.chat_history | |
| ]) | |
| async def process_user_request(self, user_input: str) -> Dict[str, Any]: | |
| """Process user request and return appropriate response""" | |
| try: | |
| response = await self.generate_response(user_input) | |
| # Extract code if present | |
| code_blocks = re.findall(r"```python\n(.*?)```", response, re.DOTALL) | |
| result = { | |
| "response": response, | |
| "code_changes": code_blocks[0] if code_blocks else None, | |
| "status": "success", | |
| "preview_available": bool(code_blocks) | |
| } | |
| # If code changes were generated, update the current app | |
| if code_blocks: | |
| self.update_current_app(code_blocks[0]) | |
| return result | |
| except Exception as e: | |
| error_msg = f"Error processing request: {str(e)}" | |
| logger.error(error_msg) | |
| self.error_log.append(error_msg) | |
| return { | |
| "response": error_msg, | |
| "status": "error", | |
| "error": str(e) | |
| } | |
| def update_current_app(self, code: str): | |
| """Update the current app with new code""" | |
| try: | |
| # Parse the code to extract components and layout | |
| components = self.extract_components_from_code(code) | |
| if components: | |
| self.current_app["components"] = components | |
| # Update layout if present | |
| layout_match = re.search(r"with gr\.(Row|Column|Tabs)\(\):", code) | |
| if layout_match: | |
| layout_type = layout_match.group(1).lower() | |
| self.current_app["layout"] = layout_type | |
| # Extract CSS if present | |
| css_match = re.search(r'css = """(.*?)"""', code, re.DOTALL) | |
| if css_match: | |
| self.current_app["css"] = css_match.group(1) | |
| except Exception as e: | |
| error_msg = f"Error updating current app: {str(e)}" | |
| logger.error(error_msg) | |
| self.error_log.append(error_msg) | |
| raise | |
| class ComponentManager: | |
| def __init__(self): | |
| self.components: List[Dict] = [] | |
| self.error_log: List[str] = [] | |
| def add_component(self, category: str, component_type: str, properties: Dict = None) -> Optional[Dict]: | |
| """Add a new component with specified properties""" | |
| try: | |
| if category not in COMPONENT_CATEGORIES or component_type not in COMPONENT_CATEGORIES[category]: | |
| raise ValueError(f"Invalid component type: {category}/{component_type}") | |
| component_info = COMPONENT_CATEGORIES[category][component_type].copy() | |
| if properties: | |
| component_info["properties"].update(properties) | |
| component = { | |
| "id": len(self.components), | |
| "category": category, | |
| "type": component_type, | |
| "properties": component_info["properties"] | |
| } | |
| self.components.append(component) | |
| return component | |
| except Exception as e: | |
| error_msg = f"Error adding component: {str(e)}" | |
| logger.error(error_msg) | |
| self.error_log.append(error_msg) | |
| return None | |
| def update_component(self, component_id: int, properties: Dict) -> bool: | |
| """Update properties of an existing component""" | |
| try: | |
| if not 0 <= component_id < len(self.components): | |
| raise ValueError(f"Invalid component ID: {component_id}") | |
| component = self.components[component_id] | |
| component["properties"].update(properties) | |
| return True | |
| except Exception as e: | |
| error_msg = f"Error updating component: {str(e)}" | |
| logger.error(error_msg) | |
| self.error_log.append(error_msg) | |
| return False | |
| def remove_component(self, component_id: int) -> bool: | |
| """Remove a component by ID""" | |
| try: | |
| if not 0 <= component_id < len(self.components): | |
| raise ValueError(f"Invalid component ID: {component_id}") | |
| self.components.pop(component_id) | |
| # Update remaining component IDs | |
| for i, component in enumerate(self.components): | |
| component["id"] = i | |
| return True | |
| except Exception as e: | |
| error_msg = f"Error removing component: {str(e)}" | |
| logger.error(error_msg) | |
| self.error_log.append(error_msg) | |
| return False | |
| def get_component(self, component_id: int) -> Optional[Dict]: | |
| """Get component by ID""" | |
| try: | |
| if not 0 <= component_id < len(self.components): | |
| raise ValueError(f"Invalid component ID: {component_id}") | |
| return self.components[component_id] | |
| except Exception as e: | |
| error_msg = f"Error getting component: {str(e)}" | |
| logger.error(error_msg) | |
| self.error_log.append(error_msg) | |
| return None | |
| def get_components_json(self) -> str: | |
| """Get all components as JSON string""" | |
| try: | |
| return json.dumps(self.components, indent=2) | |
| except Exception as e: | |
| error_msg = f"Error converting components to JSON: {str(e)}" | |
| logger.error(error_msg) | |
| self.error_log.append(error_msg) | |
| return "[]" | |
| def load_components_from_json(self, components_json: str) -> bool: | |
| """Load components from JSON string""" | |
| try: | |
| if isinstance(components_json, str): | |
| components = json.loads(components_json) | |
| else: | |
| components = components_json | |
| self.components = components | |
| return True | |
| except Exception as e: | |
| error_msg = f"Error loading components from JSON: {str(e)}" | |
| logger.error(error_msg) | |
| self.error_log.append(error_msg) | |
| return False | |
| class TemplateManager: | |
| def __init__(self): | |
| self.templates = TEMPLATE_CATEGORIES | |
| self.error_log: List[str] = [] | |
| def get_template(self, category: str, template_name: str) -> Optional[Dict]: | |
| """Get a specific template by category and name""" | |
| try: | |
| if category not in self.templates or template_name not in self.templates[category]: | |
| raise ValueError(f"Invalid template: {category}/{template_name}") | |
| return self.templates[category][template_name] | |
| except Exception as e: | |
| error_msg = f"Error getting template: {str(e)}" | |
| logger.error(error_msg) | |
| self.error_log.append(error_msg) | |
| return None | |
| def add_custom_template(self, category: str, template_name: str, template_data: Dict) -> bool: | |
| """Add a new custom template""" | |
| try: | |
| if not all(key in template_data for key in ["description", "components", "layout", "css", "dependencies"]): | |
| raise ValueError("Invalid template data structure") | |
| if category not in self.templates: | |
| self.templates[category] = {} | |
| self.templates[category][template_name] = template_data | |
| return True | |
| except Exception as e: | |
| error_msg = f"Error adding custom template: {str(e)}" | |
| logger.error(error_msg) | |
| self.error_log.append(error_msg) | |
| return False | |
| def get_template_list(self) -> List[Dict]: | |
| """Get list of all available templates""" | |
| template_list = [] | |
| for category, templates in self.templates.items(): | |
| for name, data in templates.items(): | |
| template_list.append({ | |
| "category": category, | |
| "name": name, | |
| "description": data["description"] | |
| }) | |
| return template_list | |
| class CodeGenerator: | |
| def __init__(self, template_manager: TemplateManager): | |
| self.template_manager = template_manager | |
| self.error_log: List[str] = [] | |
| def generate_app_code(self, components: List[Dict], layout: str = "vertical", | |
| theme: str = "Light", css: str = "") -> str: | |
| """Generate complete Gradio application code""" | |
| try: | |
| code_parts = [] | |
| # Add imports | |
| code_parts.append(self._generate_imports(components)) | |
| # Add any required helper functions | |
| code_parts.append(self._generate_helper_functions(components)) | |
| # Generate the main app code | |
| code_parts.append(self._generate_main_app_code(components, layout, theme, css)) | |
| return "\n\n".join(code_parts) | |
| except Exception as e: | |
| error_msg = f"Error generating app code: {str(e)}" | |
| logger.error(error_msg) | |
| self.error_log.append(error_msg) | |
| return "" | |
| def _generate_imports(self, components: List[Dict]) -> str: | |
| """Generate necessary import statements""" | |
| imports = ["import gradio as gr"] | |
| # Add additional imports based on components | |
| additional_imports = set() | |
| for component in components: | |
| if component["type"] == "Image": | |
| additional_imports.add("from PIL import Image") | |
| elif component["type"] in ["Audio", "Video"]: | |
| additional_imports.add("import numpy as np") | |
| return "\n".join(imports + sorted(list(additional_imports))) | |
| def _generate_helper_functions(self, components: List[Dict]) -> str: | |
| """Generate helper functions needed by components""" | |
| helper_functions = [] | |
| # Add processing functions based on component types | |
| processing_functions = set() | |
| for component in components: | |
| if component["type"] == "Image": | |
| processing_functions.add(""" | |
| def process_image(image): | |
| \"\"\"Process the input image\"\"\" | |
| # Add your image processing logic here | |
| return image | |
| """) | |
| elif component["type"] == "Audio": | |
| processing_functions.add(""" | |
| def process_audio(audio): | |
| \"\"\"Process the input audio\"\"\" | |
| # Add your audio processing logic here | |
| return audio | |
| """) | |
| return "\n".join(helper_functions + sorted(list(processing_functions))) | |
| def _generate_main_app_code(self, components: List[Dict], layout: str, | |
| theme: str, css: str) -> str: | |
| """Generate the main application code""" | |
| code_lines = [ | |
| "# Create Gradio interface", | |
| "with gr.Blocks(theme=gr.themes.Default(), css=css) as demo:", | |
| " gr.Markdown(\"# Gradio Application\")\n" | |
| ] | |
| # Add CSS | |
| if css: | |
| code_lines.insert(0, f'css = """{css}"""\n') | |
| # Generate layout | |
| if layout == "horizontal": | |
| code_lines.append(" with gr.Row():") | |
| indent = " " | |
| else: | |
| code_lines.append(" with gr.Column():") | |
| indent = " " | |
| # Add components | |
| component_vars = [] | |
| for i, component in enumerate(components): | |
| var_name = f"{component['type'].lower()}_{i}" | |
| component_vars.append(var_name) | |
| props = ", ".join([f"{k}={repr(v)}" for k, v in component["properties"].items()]) | |
| code_lines.append(f"{indent}{var_name} = gr.{component['type']}({props})") | |
| # Add event handlers | |
| if len(component_vars) > 1: | |
| code_lines.extend(self._generate_event_handlers(component_vars)) | |
| # Add launch code | |
| code_lines.extend([ | |
| "\n# Launch the application", | |
| "if __name__ == \"__main__\":", | |
| " demo.launch()" | |
| ]) | |
| return "\n".join(code_lines) | |
| def _generate_event_handlers(self, component_vars: List[str]) -> List[str]: | |
| """Generate event handlers for components""" | |
| handlers = [] | |
| # Look for input/output pairs | |
| for i in range(len(component_vars) - 1): | |
| if "button" in component_vars[i]: | |
| handlers.extend([ | |
| f"\n def process_{i}({component_vars[i-1]}):", | |
| f" # Add your processing logic here", | |
| f" return {component_vars[i-1]}", | |
| f"\n {component_vars[i]}.click(", | |
| f" fn=process_{i},", | |
| f" inputs=[{component_vars[i-1]}],", | |
| f" outputs=[{component_vars[i+1]}]", | |
| f" )" | |
| ]) | |
| return handlers | |
| class AppBuilder: | |
| def __init__(self): | |
| """Initialize the AppBuilder with necessary managers""" | |
| self.component_manager = ComponentManager() | |
| self.template_manager = TemplateManager() | |
| self.code_generator = CodeGenerator(self.template_manager) | |
| self.ai_builder = None # Will be initialized later if needed | |
| self.current_app = { | |
| "components": [], | |
| "layout": "vertical", | |
| "theme": "Light", | |
| "css": DEFAULT_THEMES["Light"] | |
| } | |
| self.error_log: List[str] = [] | |
| def create_app_from_template(self, category: str, template_name: str) -> bool: | |
| """Create a new app from a template""" | |
| try: | |
| template = self.template_manager.get_template(category, template_name) | |
| if not template: | |
| raise ValueError(f"Template not found: {category}/{template_name}") | |
| self.current_app = { | |
| "components": template["components"], | |
| "layout": template["layout"], | |
| "theme": "Light", | |
| "css": template.get("css", DEFAULT_THEMES["Light"]) | |
| } | |
| self.component_manager.load_components_from_json(template["components"]) | |
| return True | |
| except Exception as e: | |
| error_msg = f"Error creating app from template: {str(e)}" | |
| logger.error(error_msg) | |
| self.error_log.append(error_msg) | |
| return False | |
| def update_app_layout(self, layout: str) -> bool: | |
| """Update the application layout""" | |
| try: | |
| if layout not in ["vertical", "horizontal", "tabs"]: | |
| raise ValueError(f"Invalid layout: {layout}") | |
| self.current_app["layout"] = layout | |
| return True | |
| except Exception as e: | |
| error_msg = f"Error updating layout: {str(e)}" | |
| logger.error(error_msg) | |
| self.error_log.append(error_msg) | |
| return False | |
| def update_app_theme(self, theme: str) -> bool: | |
| """Update the application theme""" | |
| try: | |
| if theme not in DEFAULT_THEMES: | |
| raise ValueError(f"Invalid theme: {theme}") | |
| self.current_app["theme"] = theme | |
| self.current_app["css"] = DEFAULT_THEMES[theme] | |
| return True | |
| except Exception as e: | |
| error_msg = f"Error updating theme: {str(e)}" | |
| logger.error(error_msg) | |
| self.error_log.append(error_msg) | |
| return False | |
| def generate_app_code(self) -> str: | |
| """Generate the complete application code""" | |
| try: | |
| return self.code_generator.generate_app_code( | |
| self.current_app["components"], | |
| self.current_app["layout"], | |
| self.current_app["theme"], | |
| self.current_app["css"] | |
| ) | |
| except Exception as e: | |
| error_msg = f"Error generating app code: {str(e)}" | |
| logger.error(error_msg) | |
| self.error_log.append(error_msg) | |
| return "" | |
| def preview_app(self) -> Optional[gr.Blocks]: | |
| """Generate and preview the current application""" | |
| try: | |
| code = self.generate_app_code() | |
| if not code: | |
| raise ValueError("No code generated") | |
| # Create temporary file | |
| with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f: | |
| f.write(code) | |
| temp_file = f.name | |
| # Execute the code in a separate process | |
| result = subprocess.run(['python', temp_file], capture_output=True, text=True) | |
| if result.returncode != 0: | |
| raise ValueError(f"Error executing code: {result.stderr}") | |
| return True | |
| except Exception as e: | |
| error_msg = f"Error previewing app: {str(e)}" | |
| logger.error(error_msg) | |
| self.error_log.append(error_msg) | |
| return None | |
| class GradioInterface: | |
| def __init__(self): | |
| """Initialize the Gradio interface""" | |
| self.app_builder = AppBuilder() | |
| self.current_tab = "builder" | |
| self.error_log: List[str] = [] | |
| def create_interface(self) -> gr.Blocks: | |
| """Create the main Gradio interface""" | |
| try: | |
| with gr.Blocks(theme=gr.themes.Default()) as interface: | |
| gr.Markdown("# 🚀 Advanced Gradio App Builder") | |
| with gr.Tabs() as tabs: | |
| # Component Builder Tab | |
| with gr.TabItem("🔧 Builder"): | |
| self._create_builder_tab() | |
| # Code Editor Tab | |
| with gr.TabItem("📝 Code"): | |
| self._create_code_tab() | |
| # Preview Tab | |
| with gr.TabItem("👁️ Preview"): | |
| self._create_preview_tab() | |
| # AI Assistant Tab | |
| with gr.TabItem("🤖 AI Assistant"): | |
| self._create_ai_tab() | |
| # Settings Tab | |
| with gr.TabItem("⚙️ Settings"): | |
| self._create_settings_tab() | |
| return interface | |
| except Exception as e: | |
| error_msg = f"Error creating interface: {str(e)}" | |
| logger.error(error_msg) | |
| self.error_log.append(error_msg) | |
| raise | |
| def _create_builder_tab(self): | |
| """Create the component builder tab""" | |
| with gr.Row(): | |
| # Left Column - Component Selection | |
| with gr.Column(scale=1): | |
| gr.Markdown("### 📦 Components") | |
| category = gr.Dropdown( | |
| choices=list(COMPONENT_CATEGORIES.keys()), | |
| label="Category", | |
| value="Basic" | |
| ) | |
| component_type = gr.Dropdown( | |
| choices=list(COMPONENT_CATEGORIES["Basic"].keys()), | |
| label="Component Type" | |
| ) | |
| add_component = gr.Button("Add Component", variant="primary") | |
| # Middle Column - Component Properties | |
| with gr.Column(scale=2): | |
| gr.Markdown("### ⚙️ Properties") | |
| properties_json = gr.JSON(label="Component Properties") | |
| update_properties = gr.Button("Update Properties") | |
| # Right Column - Component List | |
| with gr.Column(scale=1): | |
| gr.Markdown("### 📋 Current Components") | |
| component_list = gr.JSON(label="Components") | |
| remove_component = gr.Button("Remove Selected", variant="stop") | |
| # Template Selection | |
| with gr.Row(): | |
| gr.Markdown("### 📑 Templates") | |
| template_category = gr.Dropdown( | |
| choices=list(TEMPLATE_CATEGORIES.keys()), | |
| label="Template Category" | |
| ) | |
| template_name = gr.Dropdown( | |
| choices=list(TEMPLATE_CATEGORIES["Basic"].keys()), | |
| label="Template" | |
| ) | |
| load_template = gr.Button("Load Template", variant="primary") | |
| # Event handlers | |
| def update_component_choices(category): | |
| return gr.Dropdown(choices=list(COMPONENT_CATEGORIES[category].keys())) | |
| category.change( | |
| update_component_choices, | |
| inputs=[category], | |
| outputs=[component_type] | |
| ) | |
| def add_new_component(category, comp_type): | |
| success = self.app_builder.component_manager.add_component(category, comp_type) | |
| components = self.app_builder.component_manager.get_components_json() | |
| return components | |
| add_component.click( | |
| add_new_component, | |
| inputs=[category, component_type], | |
| outputs=[component_list] | |
| ) | |
| def update_component_properties(props_json): | |
| try: | |
| props = json.loads(props_json) | |
| success = self.app_builder.component_manager.update_component( | |
| props["id"], props["properties"] | |
| ) | |
| return self.app_builder.component_manager.get_components_json() | |
| except Exception as e: | |
| logger.error(f"Error updating properties: {str(e)}") | |
| return None | |
| update_properties.click( | |
| update_component_properties, | |
| inputs=[properties_json], | |
| outputs=[component_list] | |
| ) | |
| def _create_code_tab(self): | |
| """Create the code editor tab""" | |
| with gr.Row(): | |
| with gr.Column(): | |
| code_editor = gr.Code( | |
| label="Application Code", | |
| language="python", | |
| value="# Your Gradio app code will appear here" | |
| ) | |
| update_code = gr.Button("Update Code") | |
| with gr.Column(): | |
| code_output = gr.Markdown("Code validation output will appear here") | |
| def update_app_code(): | |
| try: | |
| code = self.app_builder.generate_app_code() | |
| return code, "✅ Code generated successfully" | |
| except Exception as e: | |
| return None, f"❌ Error generating code: {str(e)}" | |
| update_code.click( | |
| update_app_code, | |
| outputs=[code_editor, code_output] | |
| ) | |
| def _create_preview_tab(self): | |
| """Create the preview tab""" | |
| with gr.Row(): | |
| preview_button = gr.Button("Generate Preview", variant="primary") | |
| preview_status = gr.Markdown("Click button to generate preview") | |
| with gr.Row(): | |
| preview_frame = gr.HTML(label="App Preview") | |
| def generate_preview(): | |
| try: | |
| success = self.app_builder.preview_app() | |
| if success: | |
| return "✅ Preview generated successfully" | |
| return "❌ Error generating preview" | |
| except Exception as e: | |
| return f"❌ Error: {str(e)}" | |
| preview_button.click( | |
| generate_preview, | |
| outputs=[preview_status] | |
| ) | |
| def create_gradio_interface(): | |
| """Create Gradio interface for the code executor""" | |
| def process_code(code: str, autonomy_level: int) -> Dict: | |
| executor.set_autonomy_level(autonomy_level) | |
| result = executor.execute_code(code) | |
| return { | |
| "Success": result["success"], | |
| "Output": result["output"], | |
| "Error": result["error"] or "None", | |
| "Fixed Code": result["fixed_code"] or code, | |
| "Iterations": result["iterations"] | |
| } | |
| with gr.Blocks() as interface: | |
| gr.Markdown("# 🤖 Autonomous Code Executor") | |
| with gr.Tab("Code Execution"): | |
| code_input = gr.Code( | |
| label="Code Input", | |
| language="python", | |
| lines=10, | |
| placeholder="Enter your Python code here..." | |
| ) | |
| autonomy_slider = gr.Slider( | |
| minimum=0, | |
| maximum=10, | |
| step=1, | |
| value=5, | |
| label="Autonomy Level", | |
| info="0: No fixes, 5: Balanced, 10: Fully autonomous" | |
| ) | |
| execute_btn = gr.Button("Execute Code", variant="primary") | |
| output_json = gr.JSON(label="Execution Result") | |
| execute_btn.click( | |
| fn=process_code, | |
| inputs=[code_input, autonomy_slider], | |
| outputs=output_json | |
| ) | |
| with gr.Tab("Settings"): | |
| gr.Markdown(""" | |
| ### Configuration | |
| - Model: bigcode/starcoder | |
| - Embedding Model: sentence-transformers/all-mpnet-base-v2 | |
| - Temperature: 0.1 | |
| - Max Length: 2048 | |
| """) | |
| with gr.Tab("Help"): | |
| gr.Markdown(""" | |
| ### How to Use | |
| 1. Enter your Python code in the Code Input area | |
| 2. Adjust the Autonomy Level: | |
| - 0: No automatic fixes | |
| - 5: Balanced approach | |
| - 10: Fully autonomous operation | |
| 3. Click "Execute Code" to run | |
| ### Features | |
| - Automatic code analysis | |
| - Error detection and fixing | |
| - Code formatting | |
| - Syntax validation | |
| """) | |
| return interface | |
| def create_gradio_interface(): | |
| """Create Gradio interface for the code executor""" | |
| def process_code(code: str, autonomy_level: int) -> Dict: | |
| executor.set_autonomy_level(autonomy_level) | |
| result = executor.execute_code(code) | |
| return { | |
| "Success": result["success"], | |
| "Output": result["output"], | |
| "Error": result["error"] or "None", | |
| "Fixed Code": result["fixed_code"] or code, | |
| "Iterations": result["iterations"] | |
| } | |
| with gr.Blocks() as interface: | |
| gr.Markdown("# 🤖 Autonomous Code Executor") | |
| with gr.Tab("Code Execution"): | |
| # Corrected Code component initialization | |
| code_input = gr.Code( | |
| label="Code Input", | |
| language="python", | |
| lines=10, | |
| value="# Enter your Python code here..." # Using value instead of placeholder | |
| ) | |
| autonomy_slider = gr.Slider( | |
| minimum=0, | |
| maximum=10, | |
| step=1, | |
| value=5, | |
| label="Autonomy Level", | |
| info="0: No fixes, 5: Balanced, 10: Fully autonomous" | |
| ) | |
| execute_btn = gr.Button("Execute Code", variant="primary") | |
| output_json = gr.JSON(label="Execution Result") | |
| # Add example inputs | |
| gr.Examples( | |
| examples=[ | |
| ["def hello():\n print('Hello, World!')", 5], | |
| ["for i in range(5):\n print(i)", 5] | |
| ], | |
| inputs=[code_input, autonomy_slider], | |
| outputs=output_json, | |
| label="Example Code" | |
| ) | |
| execute_btn.click( | |
| fn=process_code, | |
| inputs=[code_input, autonomy_slider], | |
| outputs=output_json | |
| ) | |
| with gr.Tab("Settings"): | |
| gr.Markdown(""" | |
| ### Configuration | |
| - Model: bigcode/starcoder | |
| - Embedding Model: sentence-transformers/all-mpnet-base-v2 | |
| - Temperature: 0.1 | |
| - Max Length: 2048 | |
| """) | |
| with gr.Tab("Help"): | |
| gr.Markdown(""" | |
| ### How to Use | |
| 1. Enter your Python code in the Code Input area | |
| 2. Adjust the Autonomy Level: | |
| - 0: No automatic fixes | |
| - 5: Balanced approach | |
| - 10: Fully autonomous operation | |
| 3. Click "Execute Code" to run | |
| ### Features | |
| - Automatic code analysis | |
| - Error detection and fixing | |
| - Code formatting | |
| - Syntax validation | |
| """) | |
| return interface | |
| # Create Gradio interface | |
| interface = create_gradio_interface() | |
| if __name__ == "__main__": | |
| # Run Flask and Gradio in separate threads | |
| flask_thread = threading.Thread(target=run_flask, daemon=True) | |
| gradio_thread = threading.Thread(target=run_gradio, daemon=True) | |
| flask_thread.start() | |
| gradio_thread.start() | |
| # Keep the main thread alive | |
| try: | |
| while True: | |
| time.sleep(1) | |
| except KeyboardInterrupt: | |
| print("Shutting down...") | |
| class ChatState: | |
| def __init__(self): | |
| self.current_step = 0 | |
| self.command = None | |
| self.context = {} | |
| def reset(self): | |
| self.current_step = 0 | |
| self.command = None | |
| self.context = {} | |
| chat_state = ChatState() | |
| def get_next_question(command, step, previous_answer=None): | |
| """Generate next question based on command and current step""" | |
| questions = { | |
| "create": [ | |
| "Do you need user input components?", | |
| "Do you need data processing functionality?", | |
| "Would you like to add styling/themes?" | |
| ], | |
| "component": [ | |
| "Is this for user input?", | |
| "Do you need media handling (image/audio/video)?", | |
| "Should the component have real-time updates?" | |
| ], | |
| "layout": [ | |
| "Do you want a multi-tab layout?", | |
| "Do you need responsive design?", | |
| "Should components be arranged horizontally?" | |
| ], | |
| "style": [ | |
| "Do you want a dark theme?", | |
| "Do you need custom CSS?", | |
| "Should components have rounded corners?" | |
| ], | |
| "data": [ | |
| "Will you be handling file uploads?", | |
| "Do you need data visualization?", | |
| "Should data be stored persistently?" | |
| ], | |
| "api": [ | |
| "Do you need authentication for API?", | |
| "Will you be handling JSON data?", | |
| "Do you need error handling?" | |
| ], | |
| "auth": [ | |
| "Do you need user registration?", | |
| "Should sessions be persistent?", | |
| "Do you need role-based access?" | |
| ], | |
| "file": [ | |
| "Will you handle multiple file types?", | |
| "Do you need file preprocessing?", | |
| "Should files be stored locally?" | |
| ], | |
| "viz": [ | |
| "Do you need interactive plots?", | |
| "Will you use real-time data?", | |
| "Do you need multiple chart types?" | |
| ], | |
| "db": [ | |
| "Do you need real-time updates?", | |
| "Will you use SQL database?", | |
| "Do you need data caching?" | |
| ] | |
| } | |
| if step < len(questions[command]): | |
| return questions[command][step] | |
| return None | |
| def generate_code(command, context): | |
| """Generate code based on collected context""" | |
| base_templates = { | |
| "create": """ | |
| ```python | |
| import gradio as gr | |
| def process_input({input_params}): | |
| {processing_logic} | |
| return result | |
| with gr.Blocks({style_params}) as demo: | |
| {components} | |
| {layout} | |
| {event_handlers} | |
| demo.launch() | |
| ```""", | |
| "component": """ | |
| ```python | |
| {import_statements} | |
| {component_definition} | |
| {event_handling} | |
| ```""", | |
| # Add other base templates for each command... | |
| } | |
| # Customize template based on context | |
| if command == "create": | |
| input_params = "user_input" | |
| processing_logic = "result = user_input" | |
| style_params = "theme=gr.themes.Default()" if not context.get("dark_theme") else "theme=gr.themes.Monochrome()" | |
| components = "input_component = gr.Textbox(label='Input')\noutput_component = gr.Textbox(label='Output')" | |
| layout = "gr.Button('Process')" | |
| event_handlers = "input_component.change(process_input, inputs=input_component, outputs=output_component)" | |
| return base_templates[command].format( | |
| input_params=input_params, | |
| processing_logic=processing_logic, | |
| style_params=style_params, | |
| components=components, | |
| layout=layout, | |
| event_handlers=event_handlers | |
| ) | |
| def process_chat(command, answer, history): | |
| """Process chat interaction""" | |
| try: | |
| if command and chat_state.command != command: | |
| # New command started | |
| chat_state.reset() | |
| chat_state.command = command | |
| question = get_next_question(command, 0) | |
| return history + [[None, question]], True, question | |
| if answer: | |
| # Store answer and get next question | |
| chat_state.context[f"step_{chat_state.current_step}"] = answer == "Yes" | |
| chat_state.current_step += 1 | |
| next_question = get_next_question(chat_state.command, chat_state.current_step) | |
| if next_question: | |
| # More questions to ask | |
| return history + [[answer, next_question]], True, next_question | |
| else: | |
| # Generate final code | |
| code = generate_code(chat_state.command, chat_state.context) | |
| return history + [[answer, f"Here's your code:\n{code}"]], False, None | |
| return history, True, None | |
| except Exception as e: | |
| error_msg = f"Error: {str(e)}" | |
| logger.error(error_msg) | |
| return history + [[None, error_msg]], False, None | |
| def reset_chat(): | |
| """Reset chat state and history""" | |
| chat_state.reset() | |
| return None, None, False, None | |
| # Set up event handlers | |
| send_btn.click( | |
| process_chat, | |
| inputs=[command_input, user_input, chat_history], | |
| outputs=[chat_history, user_input, user_input] | |
| ) | |
| restart_btn.click( | |
| reset_chat, | |
| outputs=[chat_history, command_input, user_input, user_input] | |
| ) | |
| def _create_settings_tab(self): | |
| """Create the settings tab""" | |
| with gr.Row(): | |
| with gr.Column(): | |
| gr.Markdown("### 🎨 Appearance") | |
| theme_dropdown = gr.Dropdown( | |
| choices=list(DEFAULT_THEMES.keys()), | |
| label="Theme", | |
| value="Light" | |
| ) | |
| layout_dropdown = gr.Dropdown( | |
| choices=["vertical", "horizontal", "tabs"], | |
| label="Layout", | |
| value="vertical" | |
| ) | |
| with gr.Column(): | |
| gr.Markdown("### 📝 Custom CSS") | |
| css_editor = gr.Code( | |
| label="Custom CSS", | |
| language="css", | |
| value=DEFAULT_THEMES["Light"] | |
| ) | |
| update_settings = gr.Button("Apply Settings", variant="primary") | |
| def update_app_settings(theme, layout, css): | |
| try: | |
| self.app_builder.update_app_theme(theme) | |
| self.app_builder.update_app_layout(layout) | |
| self.app_builder.current_app["css"] = css | |
| return "✅ Settings updated successfully" | |
| except Exception as e: | |
| return f"❌ Error updating settings: {str(e)}" | |
| update_settings.click( | |
| update_app_settings, | |
| inputs=[theme_dropdown, layout_dropdown, css_editor], | |
| outputs=[gr.Markdown()] | |
| ) | |
| def main(): | |
| """Main execution function""" | |
| try: | |
| interface = GradioInterface() | |
| demo = interface.create_interface() | |
| demo.launch( | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| share=True, | |
| debug=True | |
| ) | |
| except Exception as e: | |
| logger.error(f"Application failed to start: {str(e)}") | |
| raise | |
| if __name__ == "__main__": | |
| main() |