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() |