Spaces:
Sleeping
Sleeping
| import os | |
| import json | |
| import importlib | |
| import requests | |
| import gradio as gr | |
| import subprocess | |
| class Tool: | |
| def __init__(self, name, description, ui_class, icon="🔧", version="0.1", ui_module=None): | |
| self.name = name | |
| self.description = description | |
| self.ui_class = ui_class | |
| self.icon = icon | |
| self.version = version | |
| self.ui_module = ui_module | |
| class MainUI: | |
| def __init__(self): | |
| # Load installed tools from JSON | |
| self.tools = {} | |
| self.load_installed_tools() | |
| # Marketplace server URL | |
| self.marketplace_url = "https://marketplace.vidplus.app/api/marketplace" | |
| self.version = "0.1" | |
| # Create tools directory if it doesn't exist | |
| os.makedirs('tools', exist_ok=True) | |
| def load_installed_tools(self): | |
| """Load installed tools from JSON file""" | |
| try: | |
| if os.path.exists('installed_tools.json'): | |
| with open('installed_tools.json', 'r') as f: | |
| data = json.load(f) | |
| for tool_data in data.get('tools', []): | |
| # If ui_module is specified, dynamically import it | |
| if tool_data.get('ui_module'): | |
| try: | |
| module = importlib.import_module(tool_data['ui_module']) | |
| ui_class = getattr(module, tool_data['ui_class']) | |
| self.tools[tool_data['id']] = Tool( | |
| name=tool_data['name'], | |
| description=tool_data['description'], | |
| ui_class=ui_class, | |
| icon=tool_data['icon'], | |
| version=tool_data['version'], | |
| ui_module=tool_data['ui_module'] | |
| ) | |
| except (ImportError, AttributeError) as e: | |
| print(f"Error loading tool {tool_data['name']}: {e}") | |
| except Exception as e: | |
| print(f"Error loading installed tools: {e}") | |
| # Fallback to default BeatSyncer tool | |
| # self.tools = { | |
| # "beatsyncer": Tool( | |
| # name="BeatSyncer", | |
| # description="Create amazing videos synchronized with music beats", | |
| # ui_class=BeatSyncerUI, | |
| # icon="🎵" | |
| # ) | |
| # } | |
| def save_installed_tools(self): | |
| """Save installed tools to JSON file""" | |
| data = { | |
| "tools": [ | |
| { | |
| "id": tool_id, | |
| "name": tool.name, | |
| "description": tool.description, | |
| "icon": tool.icon, | |
| "version": tool.version, | |
| "ui_class": tool.ui_class.__name__, | |
| "ui_module": tool.ui_module | |
| } | |
| for tool_id, tool in self.tools.items() | |
| ] | |
| } | |
| with open('installed_tools.json', 'w') as f: | |
| json.dump(data, f, indent=4) | |
| def fetch_marketplace_tools(self): | |
| """Fetch available tools from marketplace server""" | |
| try: | |
| response = requests.get(f"{self.marketplace_url}/tools") | |
| if response.status_code == 200: | |
| # Get the list of tools from the marketplace | |
| marketplace_tools = response.json() | |
| # Ensure we're working with the latest state of installed tools | |
| # This is important after a tool has been removed | |
| if os.path.exists('installed_tools.json'): | |
| with open('installed_tools.json', 'r') as f: | |
| data = json.load(f) | |
| installed_tool_ids = [tool['id'] for tool in data.get('tools', [])] | |
| else: | |
| installed_tool_ids = [] | |
| # Update the is_installed flag for each tool | |
| for tool in marketplace_tools: | |
| tool['is_installed'] = tool['id'] in installed_tool_ids | |
| return marketplace_tools | |
| else: | |
| return [] | |
| except Exception as e: | |
| print(f"Error fetching marketplace tools: {e}") | |
| return [] | |
| def fetch_tool_details(self, tool_id): | |
| """Fetch details for a specific tool from marketplace server""" | |
| try: | |
| response = requests.get(f"{self.marketplace_url}/tools/{tool_id}") | |
| if response.status_code == 200: | |
| return response.json() | |
| else: | |
| return None | |
| except Exception as e: | |
| print(f"Error fetching tool details: {e}") | |
| return None | |
| def install_tool(self, tool_id): | |
| """Install a tool from the marketplace""" | |
| try: | |
| # Import required modules | |
| import importlib | |
| import importlib.util | |
| import sys | |
| import subprocess | |
| import gradio as gr | |
| # Fetch tool data | |
| response = requests.get(f"{self.marketplace_url}/tools/{tool_id}/download") | |
| if response.status_code != 200: | |
| return f"Error: Failed to download tool (Status code: {response.status_code})" | |
| tool_data = response.json() | |
| tool_info = tool_data['tool'] | |
| tool_files = tool_data['files'] | |
| # Check and install dependencies if they exist | |
| dependencies = tool_info.get('dependencies', []) | |
| if dependencies: | |
| try: | |
| # Read current requirements.txt | |
| current_requirements = [] | |
| if os.path.exists('requirements.txt'): | |
| with open('requirements.txt', 'r') as f: | |
| current_requirements = [line.strip() for line in f.readlines() if line.strip()] | |
| # Check which dependencies need to be installed | |
| to_install = [] | |
| to_add_to_requirements = [] | |
| for dep in dependencies: | |
| # Extract just the package name (ignore version requirements) | |
| pkg_name = dep.split('>=')[0].split('==')[0].split('>')[0].split('<')[0].strip() | |
| # Check if dependency is already in requirements.txt | |
| is_in_requirements = False | |
| for req in current_requirements: | |
| req_name = req.split('>=')[0].split('==')[0].split('>')[0].split('<')[0].strip() | |
| if req_name == pkg_name: | |
| is_in_requirements = True | |
| break | |
| if not is_in_requirements: | |
| to_add_to_requirements.append(dep) | |
| try: | |
| # Try to import the package to check if it's installed | |
| importlib.import_module(pkg_name) | |
| except ImportError: | |
| # Package not installed, add to installation list | |
| to_install.append(dep) | |
| # Install missing dependencies | |
| if to_install: | |
| for dep in to_install: | |
| # Use subprocess to run pip install | |
| subprocess.check_call([sys.executable, "-m", "pip", "install", dep]) | |
| # Append new dependencies to requirements.txt | |
| if to_add_to_requirements: | |
| with open('requirements.txt', 'a') as f: | |
| for dep in to_add_to_requirements: | |
| f.write(f"\n{dep}") | |
| print(f"Added {len(to_add_to_requirements)} dependencies to requirements.txt") | |
| except Exception as e: | |
| return f"Error installing dependencies: {e}" | |
| # Create tool directory | |
| tool_dir = os.path.join('tools', tool_id) | |
| os.makedirs(tool_dir, exist_ok=True) | |
| # Write tool files | |
| for file_name, file_content in tool_files.items(): | |
| # Rename files to match our convention | |
| target_file_name = file_name | |
| if file_name.endswith('_tool_logic.py'): | |
| target_file_name = f"{tool_id}_tool.py" | |
| elif file_name.endswith('_tool_ui.py'): | |
| target_file_name = f"{tool_id}_ui.py" | |
| with open(os.path.join(tool_dir, target_file_name), 'w') as f: | |
| f.write(file_content) | |
| # Create __init__.py to make the directory a package | |
| with open(os.path.join(tool_dir, '__init__.py'), 'w') as f: | |
| f.write(f"# {tool_info['name']} package\n") | |
| # Add tool to installed tools | |
| ui_module = f"tools.{tool_id}.{tool_id}_ui" | |
| ui_class = f"{tool_id.title().replace('_', '')}UI" | |
| # Update installed_tools.json | |
| with open('installed_tools.json', 'r') as f: | |
| data = json.load(f) | |
| data['tools'].append({ | |
| "id": tool_id, | |
| "name": tool_info['name'], | |
| "description": tool_info['description'], | |
| "icon": tool_info['icon'], | |
| "version": tool_info['version'], | |
| "ui_class": ui_class, | |
| "ui_module": ui_module | |
| }) | |
| with open('installed_tools.json', 'w') as f: | |
| json.dump(data, f, indent=4) | |
| # Dynamically load the newly installed tool | |
| try: | |
| # Reload the module if it was already imported | |
| if ui_module in sys.modules: | |
| importlib.reload(sys.modules[ui_module]) | |
| # Import the module | |
| module = importlib.import_module(ui_module) | |
| ui_class_obj = getattr(module, ui_class) | |
| # Add the tool to self.tools | |
| self.tools[tool_id] = Tool( | |
| name=tool_info['name'], | |
| description=tool_info['description'], | |
| ui_class=ui_class_obj, | |
| icon=tool_info['icon'], | |
| version=tool_info['version'], | |
| ui_module=ui_module | |
| ) | |
| # Flag to indicate this is a newly installed tool that needs special handling | |
| self.tools[tool_id].newly_installed = True | |
| # Return success message | |
| return f"Successfully installed {tool_info['name']}. The tool is now available in the Tools page." | |
| except Exception as e: | |
| print(f"Error dynamically loading tool: {e}") | |
| import traceback | |
| traceback.print_exc() | |
| # Still return success but with a restart message | |
| return f"Successfully installed {tool_info['name']}. Please restart the application to use the new tool." | |
| except Exception as e: | |
| return f"Error installing tool: {e}" | |
| def remove_tool(self, tool_id): | |
| """Remove an installed tool""" | |
| try: | |
| if tool_id not in self.tools: | |
| return "Error: Tool is not installed" | |
| # Get tool info before removal | |
| tool_name = self.tools[tool_id].name | |
| # Remove tool directory | |
| tool_dir = os.path.join('tools', tool_id) | |
| if os.path.exists(tool_dir): | |
| import shutil | |
| shutil.rmtree(tool_dir) | |
| print(f"Removed tool directory: {tool_dir}") | |
| # Remove tool from installed_tools.json | |
| if os.path.exists('installed_tools.json'): | |
| with open('installed_tools.json', 'r') as f: | |
| data = json.load(f) | |
| # Filter out the tool to be removed | |
| data['tools'] = [tool for tool in data['tools'] if tool['id'] != tool_id] | |
| # Save updated tools list | |
| with open('installed_tools.json', 'w') as f: | |
| json.dump(data, f, indent=4) | |
| print(f"Removed tool from installed_tools.json: {tool_id}") | |
| # Remove tool from self.tools | |
| del self.tools[tool_id] | |
| return f"✅ Successfully removed {tool_name}" | |
| except Exception as e: | |
| print(f"Error removing tool: {e}") | |
| import traceback | |
| traceback.print_exc() | |
| return f"Error removing tool: {str(e)}" | |
| def create_tool_card(self, name): | |
| return f""" | |
| <div style=" | |
| background: #E6E6E6; | |
| border-radius: 16px; | |
| width: 200px; | |
| height: 200px; | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| cursor: pointer; | |
| transition: transform 0.2s; | |
| box-shadow: 0 2px 4px rgba(0,0,0,0.1); | |
| &:hover {{ | |
| transform: scale(1.02); | |
| }}"> | |
| <span style="color: #1a1a1a; font-size: 16px; font-weight: 500;">{name}</span> | |
| </div> | |
| """ | |
| def create_ui(self): | |
| css = """ | |
| :root { | |
| --sidebar-width: 200px; | |
| } | |
| body { | |
| margin: 0; | |
| padding: 0; | |
| overflow: hidden; | |
| } | |
| #sidebar { | |
| background-color: #0A192F; | |
| color: white; | |
| padding: 32px 24px; | |
| height: 100vh; | |
| width: var(--sidebar-width); | |
| position: fixed; | |
| left: 0; | |
| top: 0; | |
| display: flex; | |
| flex-direction: column; | |
| box-sizing: border-box; | |
| z-index: 1000; | |
| } | |
| #main-content { | |
| background-color: #0F172A; | |
| min-height: 100vh; | |
| margin-left: var(--sidebar-width); | |
| padding: 50px; | |
| box-sizing: border-box; | |
| overflow-y: auto; | |
| position: relative; | |
| max-height: 100vh; /* Ensure content is scrollable */ | |
| } | |
| .nav-button { | |
| background: none !important; | |
| border: none !important; | |
| box-shadow: none !important; | |
| color: #94A3B8 !important; | |
| padding: 8px 0 !important; | |
| margin: 4px 0 !important; | |
| min-width: unset !important; | |
| width: 100% !important; | |
| text-align: left !important; | |
| font-size: 16px !important; | |
| font-weight: 500 !important; | |
| height: auto !important; | |
| line-height: 1.2 !important; | |
| } | |
| .nav-button:hover { | |
| color: white !important; | |
| } | |
| .nav-button[variant="primary"] { | |
| color: white !important; | |
| } | |
| .tool-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); | |
| gap: 20px; | |
| padding: 24px 0; | |
| width: 100%; | |
| } | |
| .version-text { | |
| margin-top: auto; | |
| color: #64748B; | |
| font-size: 12px; | |
| padding-top: 16px; | |
| } | |
| .title { | |
| font-size: 32px; | |
| font-weight: 800; | |
| margin-bottom: 32px; | |
| color: white; | |
| letter-spacing: -0.5px; | |
| } | |
| .page-title { | |
| font-size: 28px; | |
| font-weight: 700; | |
| color: white; | |
| margin: 0; | |
| padding: 0; | |
| letter-spacing: -0.5px; | |
| } | |
| #content-wrapper { | |
| width: 100%; | |
| max-width: 100%; | |
| padding: 24px; | |
| } | |
| .tool-card { | |
| background: #1E293B !important; | |
| border: none !important; | |
| border-radius: 16px !important; | |
| overflow: hidden !important; | |
| transition: transform 0.2s !important; | |
| box-shadow: 0 4px 6px rgba(0,0,0,0.1) !important; | |
| height: 100% !important; | |
| display: flex !important; | |
| flex-direction: column !important; | |
| width: auto !important; | |
| min-height: 200px !important; | |
| justify-content: flex-start !important; | |
| align-items: stretch !important; | |
| padding: 0 !important; | |
| color: white !important; | |
| text-align: left !important; | |
| cursor: pointer !important; | |
| } | |
| .tool-card:hover { | |
| transform: scale(1.02) !important; | |
| } | |
| .tool-card-img { | |
| width: 100%; | |
| height: 150px; | |
| background: #2D3748; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 48px; | |
| color: #38BDF8; | |
| } | |
| .tool-card-content { | |
| padding: 16px !important; | |
| flex-grow: 1 !important; | |
| display: flex !important; | |
| flex-direction: column !important; | |
| } | |
| .tool-card-title { | |
| font-size: 18px !important; | |
| font-weight: 600 !important; | |
| color: white !important; | |
| margin: 0 0 8px 0 !important; | |
| } | |
| .tool-card-description { | |
| font-size: 14px !important; | |
| color: #94A3B8 !important; | |
| margin: 0 !important; | |
| flex-grow: 1 !important; | |
| } | |
| .installed-indicator { | |
| background-color: #10B981 !important; | |
| color: white !important; | |
| font-size: 12px !important; | |
| font-weight: 600 !important; | |
| padding: 4px 8px !important; | |
| border-radius: 4px !important; | |
| margin-top: 8px !important; | |
| display: inline-block !important; | |
| } | |
| .tool-card.installed { | |
| border: 2px solid #10B981 !important; | |
| } | |
| .add-tool-card { | |
| background: rgba(255, 255, 255, 0.05) !important; | |
| border: 2px dashed rgba(255, 255, 255, 0.2) !important; | |
| color: rgba(255, 255, 255, 0.8) !important; | |
| display: flex !important; | |
| flex-direction: column !important; | |
| justify-content: center !important; | |
| align-items: center !important; | |
| text-align: center !important; | |
| padding: 16px !important; | |
| } | |
| .add-tool-icon { | |
| font-size: 32px; | |
| margin-bottom: 16px; | |
| color: rgba(255, 255, 255, 0.5); | |
| } | |
| .tool-card-button { | |
| background: transparent !important; | |
| border: none !important; | |
| padding: 0 !important; | |
| margin: 0 !important; | |
| width: 100% !important; | |
| height: auto !important; | |
| min-height: 0 !important; | |
| box-shadow: none !important; | |
| } | |
| .tool-details { | |
| width: 100%; | |
| max-width: 100%; | |
| padding: 0; | |
| } | |
| .tool-details-container { | |
| background: #0F172A; | |
| border-radius: 0; | |
| padding: 32px; | |
| margin-bottom: 0; | |
| max-height: 100vh; | |
| overflow-y: auto; | |
| width: 100%; | |
| } | |
| .tool-details-header { | |
| display: flex; | |
| align-items: center; | |
| margin-bottom: 24px; | |
| justify-content: space-between; | |
| } | |
| .tool-details-title-section { | |
| display: flex; | |
| align-items: center; | |
| } | |
| .tool-details-icon { | |
| font-size: 28px; | |
| margin-right: 16px; | |
| } | |
| .tool-details-title { | |
| font-size: 28px; | |
| font-weight: 700; | |
| color: white; | |
| margin: 0; | |
| } | |
| .tool-details-version { | |
| font-size: 14px; | |
| color: #94A3B8; | |
| margin-left: 8px; | |
| } | |
| .tool-details-description { | |
| font-size: 16px; | |
| color: #E2E8F0; | |
| margin-bottom: 32px; | |
| max-width: 800px; | |
| } | |
| .tool-details-section-title { | |
| font-size: 18px; | |
| font-weight: 600; | |
| color: white; | |
| margin: 32px 0 16px 0; | |
| } | |
| .tool-details-features { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 12px; | |
| margin-bottom: 32px; | |
| } | |
| .tool-details-feature { | |
| display: flex; | |
| align-items: center; | |
| margin-bottom: 0; | |
| } | |
| .tool-details-feature-icon { | |
| color: #38BDF8; | |
| margin-right: 12px; | |
| font-size: 16px; | |
| } | |
| .tool-details-feature-text { | |
| color: #E2E8F0; | |
| font-size: 16px; | |
| } | |
| .tool-details-screenshots { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); | |
| gap: 16px; | |
| margin-top: 16px; | |
| } | |
| .tool-details-screenshot { | |
| width: 100%; | |
| border-radius: 8px; | |
| overflow: hidden; | |
| } | |
| .tool-details-video { | |
| width: 100%; | |
| aspect-ratio: 16/9; | |
| border-radius: 8px; | |
| overflow: hidden; | |
| margin-top: 16px; | |
| background: #1E293B; | |
| border: none; | |
| max-width: 800px; | |
| height: 450px; | |
| } | |
| .back-button { | |
| background: transparent !important; | |
| border: none !important; | |
| color: #94A3B8 !important; | |
| font-size: 14px !important; | |
| padding: 8px 16px !important; | |
| border-radius: 8px !important; | |
| cursor: pointer !important; | |
| transition: background-color 0.2s !important; | |
| text-align: left !important; | |
| width: auto !important; | |
| margin-bottom: 24px !important; | |
| } | |
| .back-button:hover { | |
| background: rgba(255, 255, 255, 0.1) !important; | |
| } | |
| .install-button { | |
| background: #38BDF8 !important; | |
| color: #0F172A !important; | |
| font-weight: 600 !important; | |
| padding: 12px 24px !important; | |
| border-radius: 8px !important; | |
| margin-top: 24px !important; | |
| width: 100% !important; | |
| } | |
| .install-button:hover { | |
| background: #0EA5E9 !important; | |
| } | |
| .remove-button { | |
| background: #EF4444 !important; | |
| color: white !important; | |
| font-weight: 600 !important; | |
| padding: 12px 24px !important; | |
| border-radius: 8px !important; | |
| margin-top: 24px !important; | |
| width: 100% !important; | |
| border: none !important; | |
| cursor: pointer !important; | |
| transition: background-color 0.2s !important; | |
| } | |
| .remove-button:hover { | |
| background: #DC2626 !important; | |
| } | |
| .tool-details-action .remove-button { | |
| margin-top: 0 !important; | |
| padding: 8px 16px !important; | |
| font-size: 14px !important; | |
| width: auto !important; | |
| } | |
| /* Confirmation dialog styling */ | |
| .confirmation-dialog { | |
| background-color: #1E293B; | |
| border-radius: 8px; | |
| padding: 24px; | |
| margin-bottom: 24px; | |
| box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); | |
| border: 1px solid #2D3748; | |
| } | |
| .confirmation-title { | |
| font-size: 18px; | |
| font-weight: 600; | |
| color: white; | |
| margin-bottom: 16px; | |
| } | |
| .confirmation-message { | |
| font-size: 14px; | |
| color: #E2E8F0; | |
| margin-bottom: 24px; | |
| } | |
| .confirmation-buttons { | |
| display: flex; | |
| justify-content: flex-end; | |
| gap: 12px; | |
| } | |
| .cancel-button { | |
| background: #4B5563 !important; | |
| color: white !important; | |
| font-weight: 600 !important; | |
| padding: 8px 16px !important; | |
| border-radius: 8px !important; | |
| border: none !important; | |
| cursor: pointer !important; | |
| transition: background-color 0.2s !important; | |
| } | |
| .cancel-button:hover { | |
| background: #374151 !important; | |
| } | |
| .confirm-button { | |
| background: #EF4444 !important; | |
| color: white !important; | |
| font-weight: 600 !important; | |
| padding: 8px 16px !important; | |
| border-radius: 8px !important; | |
| border: none !important; | |
| cursor: pointer !important; | |
| transition: background-color 0.2s !important; | |
| } | |
| .confirm-button:hover { | |
| background: #DC2626 !important; | |
| } | |
| /* Modal styling */ | |
| #installation-modal { | |
| max-width: 500px; | |
| border-radius: 8px; | |
| box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); | |
| } | |
| #installation-status { | |
| font-size: 18px; | |
| font-weight: 600; | |
| margin-bottom: 12px; | |
| padding-bottom: 8px; | |
| border-bottom: 1px solid #e5e7eb; | |
| } | |
| #installation-result { | |
| font-size: 14px; | |
| margin-bottom: 20px; | |
| white-space: pre-wrap; | |
| max-height: 300px; | |
| overflow-y: auto; | |
| } | |
| #close-modal-btn { | |
| background-color: #6B7280; | |
| color: white; | |
| border: none; | |
| padding: 8px 16px; | |
| border-radius: 4px; | |
| cursor: pointer; | |
| font-weight: 500; | |
| transition: background-color 0.2s; | |
| margin-top: 12px; | |
| } | |
| #close-modal-btn:hover { | |
| background-color: #4B5563; | |
| } | |
| /* Installation result styling */ | |
| #installation-result-container { | |
| margin-bottom: 20px; | |
| border: 1px solid #2D3748; | |
| border-radius: 8px; | |
| padding: 16px; | |
| background-color: #1E293B; | |
| max-width: 100%; | |
| position: relative; | |
| z-index: 100; | |
| box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); | |
| margin-top: 0; | |
| } | |
| #installation-status { | |
| font-size: 18px; | |
| font-weight: 600; | |
| margin-bottom: 12px; | |
| padding-bottom: 8px; | |
| border-bottom: 1px solid #2D3748; | |
| } | |
| #installation-result { | |
| font-size: 14px; | |
| margin-bottom: 20px; | |
| white-space: pre-wrap; | |
| max-height: 300px; | |
| overflow-y: auto; | |
| } | |
| #close-result-btn { | |
| background-color: #6B7280; | |
| color: white; | |
| border: none; | |
| padding: 8px 16px; | |
| border-radius: 4px; | |
| cursor: pointer; | |
| font-weight: 500; | |
| transition: background-color 0.2s; | |
| margin-top: 12px; | |
| } | |
| #close-result-btn:hover { | |
| background-color: #4B5563; | |
| } | |
| .tool-details-action { | |
| display: flex; | |
| align-items: center; | |
| } | |
| .tool-details-action .install-button { | |
| margin-top: 0 !important; | |
| padding: 8px 16px !important; | |
| font-size: 14px !important; | |
| width: auto !important; | |
| } | |
| """ | |
| with gr.Blocks(theme=gr.themes.Default(), css=css) as app: | |
| # Define state variables | |
| marketplace_tools_state = gr.State([]) | |
| current_tool_details_state = gr.State(None) | |
| # Define event handlers first, before any references to them | |
| def show_tools(): | |
| # Create updates to hide all tool containers | |
| tool_container_updates = [gr.update(visible=False) for _ in tool_containers] | |
| # Generate fresh HTML for tools grid based on current tools | |
| tools_html = '' | |
| for tool_id, tool in self.tools.items(): | |
| # Create HTML for each tool card | |
| tools_html += f''' | |
| <div class="tool-card" id="tool-card-{tool_id}" onclick="document.getElementById('tool-btn-{tool_id}').click()"> | |
| <div class="tool-card-img"> | |
| {tool.icon} | |
| </div> | |
| <div class="tool-card-content"> | |
| <h3 class="tool-card-title">{tool.name}</h3> | |
| <p class="tool-card-description">{tool.description if hasattr(tool, 'description') else ""}</p> | |
| </div> | |
| </div> | |
| ''' | |
| # Add "Add New Tool" button | |
| tools_html += ''' | |
| <div class="tool-card add-tool-card" onclick="document.getElementById('add-tool-btn').click()"> | |
| <div class="add-tool-icon">+</div> | |
| <div>Add New Tool from Marketplace</div> | |
| </div> | |
| ''' | |
| # Create HTML update for tools grid | |
| tools_html_component = gr.HTML(f'<div class="tool-grid">{tools_html}</div>') | |
| return [ | |
| gr.update(visible=True), # tools_content | |
| gr.update(visible=False), # marketplace_content | |
| gr.update(visible=False), # settings_content | |
| gr.update(visible=False), # tool_interfaces | |
| gr.update(visible=False), # tool_details_content | |
| gr.update(variant="primary"), # tools_btn | |
| gr.update(variant="secondary"), # marketplace_btn | |
| gr.update(variant="secondary"), # settings_btn, | |
| tools_html_component, # tools_html_component | |
| gr.update(value="") # tool_interfaces_html | |
| ] + tool_container_updates | |
| def show_marketplace(): | |
| # Fetch marketplace tools | |
| tools = self.fetch_marketplace_tools() | |
| # Create HTML for marketplace grid | |
| html = '<div class="tool-grid">' | |
| for i, tool in enumerate(tools): | |
| # Use a unique ID for each card based on the tool ID | |
| # Add a class to indicate if the tool is installed | |
| installed_class = "installed" if tool.get('is_installed', False) else "" | |
| # Add an indicator for installed tools | |
| installed_indicator = '<div class="installed-indicator">✓ Installed</div>' if tool.get('is_installed', False) else '' | |
| html += f''' | |
| <div class="tool-card {installed_class}" id="card-{tool['id']}" onclick="document.getElementById('marketplace-tool-btn-{i}').click()"> | |
| <div class="tool-card-img"> | |
| {tool['icon']} | |
| </div> | |
| <div class="tool-card-content"> | |
| <h3 class="tool-card-title">{tool['name']}</h3> | |
| <p class="tool-card-description">{tool['description']}</p> | |
| {installed_indicator} | |
| </div> | |
| </div> | |
| ''' | |
| html += '</div>' | |
| # Hide installation result container and confirmation dialog | |
| installation_result_container_update = gr.update(visible=False) | |
| confirmation_dialog_update = gr.update(visible=False) | |
| # Create updates for all tool containers | |
| tool_container_updates = [gr.update(visible=False) for _ in tool_containers] | |
| # Update marketplace_tools_state with the latest tools | |
| # This ensures the marketplace shows the current state of available tools | |
| return [ | |
| gr.update(visible=False), # tools_content | |
| gr.update(visible=True), # marketplace_content | |
| gr.update(visible=False), # settings_content | |
| gr.update(visible=False), # tool_interfaces | |
| gr.update(visible=False), # tool_details_content | |
| gr.update(variant="secondary"), # tools_btn | |
| gr.update(variant="primary"), # marketplace_btn | |
| gr.update(variant="secondary"), # settings_btn | |
| tools, # marketplace_tools_state - updated with latest tools | |
| html, # marketplace_html | |
| installation_result_container_update, # installation_result_container | |
| confirmation_dialog_update, # confirmation_dialog | |
| gr.update(value="") # tool_interfaces_html | |
| ] + tool_container_updates | |
| def show_settings(): | |
| # Create updates to hide all tool containers | |
| tool_container_updates = [gr.update(visible=False) for _ in tool_containers] | |
| return [ | |
| gr.update(visible=False), # tools_content | |
| gr.update(visible=False), # marketplace_content | |
| gr.update(visible=True), # settings_content | |
| gr.update(visible=False), # tool_interfaces | |
| gr.update(visible=False), # tool_details_content | |
| gr.update(variant="secondary"), # tools_btn | |
| gr.update(variant="secondary"), # marketplace_btn | |
| gr.update(variant="primary"), # settings_btn | |
| gr.update(value="") # tool_interfaces_html | |
| ] + tool_container_updates | |
| def show_tool(tool_id=None): | |
| # Import gradio at the beginning of the function | |
| import gradio as gr | |
| # Check if the tool exists | |
| if tool_id not in self.tools: | |
| print(f"Tool {tool_id} not found") | |
| return show_tools() | |
| # Get the tool | |
| tool = self.tools[tool_id] | |
| # Check if this is a newly installed tool that needs special handling | |
| if hasattr(tool, 'newly_installed') and tool.newly_installed: | |
| print(f"Dynamically creating UI for newly installed tool: {tool_id}") | |
| try: | |
| # Create a message to inform the user that we're loading the tool | |
| loading_message = f""" | |
| <div style="text-align: center; padding: 20px;"> | |
| <h2>Loading {tool.name}...</h2> | |
| <p>Please wait while we set up the tool interface.</p> | |
| </div> | |
| """ | |
| # First, return a loading message | |
| loading_updates = [ | |
| gr.update(visible=False), # tools_content | |
| gr.update(visible=False), # marketplace_content | |
| gr.update(visible=False), # settings_content | |
| gr.update(visible=True), # tool_interfaces | |
| gr.update(visible=False), # tool_details_content | |
| gr.update(variant="secondary"), # tools_btn | |
| gr.update(variant="secondary"), # marketplace_btn | |
| gr.update(variant="secondary"), # settings_btn | |
| gr.update(value=loading_message) # tool_interfaces_html | |
| ] + [gr.update(visible=False) for _ in tool_containers] | |
| # Instead of trying to create the UI dynamically, which can cause issues with Gradio components, | |
| # we'll create a simple HTML interface that provides basic functionality and instructions | |
| # Get the tool class name and module for display | |
| tool_class_name = tool.ui_class.__name__ | |
| tool_module_name = tool.ui_module | |
| # Create a friendly HTML interface | |
| tool_html = f""" | |
| <div style="text-align: center; padding: 20px;"> | |
| <h2>{tool.name} is Ready!</h2> | |
| <p>This tool has been successfully installed.</p> | |
| <p>For the best experience with this tool, please restart the application.</p> | |
| <p>After restarting, you'll be able to use all the features of this tool.</p> | |
| <!--<div style="margin-top: 20px;"> | |
| <button onclick="window.location.reload()" style="background-color: #4CAF50; color: white; padding: 10px 20px; border: none; border-radius: 4px; cursor: pointer; font-size: 16px;">Refresh Page</button> | |
| </div>--> | |
| </div> | |
| """ | |
| # Remove the newly_installed flag so we don't try to create the UI again | |
| delattr(tool, 'newly_installed') | |
| # Return the HTML interface | |
| return [ | |
| gr.update(visible=False), # tools_content | |
| gr.update(visible=False), # marketplace_content | |
| gr.update(visible=False), # settings_content | |
| gr.update(visible=True), # tool_interfaces | |
| gr.update(visible=False), # tool_details_content | |
| gr.update(variant="secondary"), # tools_btn | |
| gr.update(variant="secondary"), # marketplace_btn | |
| gr.update(variant="secondary"), # settings_btn | |
| gr.update(value=tool_html) # tool_interfaces_html | |
| ] + [gr.update(visible=False) for _ in tool_containers] | |
| except Exception as e: | |
| print(f"Error creating UI for newly installed tool: {e}") | |
| import traceback | |
| traceback.print_exc() | |
| # If there's an error, show a message asking the user to restart | |
| restart_message = f""" | |
| <div style="text-align: center; padding: 20px;"> | |
| <h2>Error Loading {tool.name}</h2> | |
| <p>There was an error setting up the tool interface:</p> | |
| <pre style="text-align: left; background: #f0f0f0; padding: 10px; border-radius: 5px; overflow: auto;">{str(e)}</pre> | |
| <p>Please restart the application to use this tool.</p> | |
| <div style="margin-top: 20px;"> | |
| <button onclick="window.location.reload()" style="background-color: #4CAF50; color: white; padding: 10px 20px; border: none; border-radius: 4px; cursor: pointer; font-size: 16px;">Refresh Page</button> | |
| </div> | |
| </div> | |
| """ | |
| return [ | |
| gr.update(visible=False), # tools_content | |
| gr.update(visible=False), # marketplace_content | |
| gr.update(visible=False), # settings_content | |
| gr.update(visible=True), # tool_interfaces | |
| gr.update(visible=False), # tool_details_content | |
| gr.update(variant="secondary"), # tools_btn | |
| gr.update(variant="secondary"), # marketplace_btn | |
| gr.update(variant="secondary"), # settings_btn | |
| gr.update(value=restart_message) # tool_interfaces_html | |
| ] + [gr.update(visible=False) for _ in tool_containers] | |
| # For existing tools with proper UI containers | |
| # Create a list of visibility updates for all tool containers | |
| updates = [] | |
| for i, container in enumerate(tool_containers): | |
| # Get the tool_id for this container | |
| container_tool_id = None | |
| for tid, t in self.tools.items(): | |
| if hasattr(t, 'ui_container') and t.ui_container == container: | |
| container_tool_id = tid | |
| break | |
| # Set visibility based on whether this is the selected tool | |
| if container_tool_id == tool_id: | |
| updates.append(gr.update(visible=True)) | |
| else: | |
| updates.append(gr.update(visible=False)) | |
| return [ | |
| gr.update(visible=False), # tools_content | |
| gr.update(visible=False), # marketplace_content | |
| gr.update(visible=False), # settings_content | |
| gr.update(visible=True), # tool_interfaces | |
| gr.update(visible=False), # tool_details_content | |
| gr.update(variant="secondary"), # tools_btn | |
| gr.update(variant="secondary"), # marketplace_btn | |
| gr.update(variant="secondary"), # settings_btn | |
| gr.update(value="") # tool_interfaces_html | |
| ] + updates | |
| def show_tool_details(tool_id): | |
| # Fetch tool details | |
| tool = self.fetch_tool_details(tool_id) | |
| # Create updates to hide all tool containers | |
| tool_container_updates = [gr.update(visible=False) for _ in tool_containers] | |
| if not tool: | |
| return [ | |
| gr.update(visible=False), # tools_content | |
| gr.update(visible=True), # marketplace_content | |
| gr.update(visible=False), # settings_content | |
| gr.update(visible=False), # tool_interfaces | |
| gr.update(visible=False), # tool_details_content | |
| gr.update(variant="secondary"), # tools_btn | |
| gr.update(variant="primary"), # marketplace_btn | |
| gr.update(variant="secondary"), # settings_btn | |
| None, # current_tool_details_state | |
| "", # tool_details_html | |
| gr.update(visible=False), # installation_result_container | |
| gr.update(visible=False), # confirmation_dialog | |
| gr.update(value="") # tool_interfaces_html | |
| ] + tool_container_updates | |
| # Create features HTML | |
| features_html = "".join([ | |
| f'<div class="tool-details-feature"><span class="tool-details-feature-icon">✓</span><span class="tool-details-feature-text">{feature}</span></div>' | |
| for feature in tool.get('features', []) | |
| ]) | |
| # Create demo video HTML | |
| demo_video_html = f'<iframe class="tool-details-video" src="{tool.get("demo_video", "https://www.youtube.com/embed/dQw4w9WgXcQ")}" frameborder="0" allowfullscreen></iframe>' if True else '' | |
| # Check if the tool is already installed | |
| # Use the is_installed flag if available, otherwise check self.tools | |
| is_installed = tool.get('is_installed', False) or tool_id in self.tools | |
| # Determine which button to show based on installation status | |
| if is_installed: | |
| action_button = f'<button id="remove-tool-btn-inline" class="remove-button" onclick="document.getElementById(\'remove-btn\').click()">Remove Tool</button>' | |
| else: | |
| action_button = f'<button id="add-tool-btn-inline" class="install-button" onclick="document.getElementById(\'install-btn\').click()">Add Tool</button>' | |
| # Create HTML for tool details | |
| html = f''' | |
| <div class="tool-details-container"> | |
| <div class="tool-details"> | |
| <div class="tool-details-header"> | |
| <div class="tool-details-title-section"> | |
| <div class="tool-details-icon">{tool['icon']}</div> | |
| <h2 class="tool-details-title">{tool['name']} <span class="tool-details-version">v{tool['version']}</span></h2> | |
| </div> | |
| <div class="tool-details-action"> | |
| {action_button} | |
| </div> | |
| </div> | |
| <p class="tool-details-description">{tool['description']}</p> | |
| <h3 class="tool-details-section-title">Features</h3> | |
| <div class="tool-details-features"> | |
| {features_html} | |
| </div> | |
| <h3 class="tool-details-section-title">Video</h3> | |
| {demo_video_html} | |
| </div> | |
| </div> | |
| ''' | |
| print(f"Setting current_tool_details_state to: {tool}") | |
| return [ | |
| gr.update(visible=False), # tools_content | |
| gr.update(visible=False), # marketplace_content | |
| gr.update(visible=False), # settings_content | |
| gr.update(visible=False), # tool_interfaces | |
| gr.update(visible=True), # tool_details_content | |
| gr.update(variant="secondary"), # tools_btn | |
| gr.update(variant="secondary"), # marketplace_btn | |
| gr.update(variant="secondary"), # settings_btn | |
| tool, # current_tool_details_state | |
| html, # tool_details_html | |
| gr.update(visible=False), # installation_result_container | |
| gr.update(visible=False), # confirmation_dialog | |
| gr.update(value="") # tool_interfaces_html | |
| ] + tool_container_updates | |
| def install_selected_tool(tool_details): | |
| print(f"Installing tool: {tool_details}") | |
| if not tool_details: | |
| print("No tool details provided") | |
| return [ | |
| gr.update(visible=True), # installation_result_container | |
| "⚠️ Installation Failed", # installation_status | |
| "No tool selected to install." # installation_result | |
| ] | |
| try: | |
| # Install the tool | |
| result = self.install_tool(tool_details['id']) | |
| if "Error" in result: | |
| return [ | |
| gr.update(visible=True), # installation_result_container | |
| "⚠️ Installation Failed", # installation_status | |
| result # installation_result | |
| ] | |
| else: | |
| # If installation was successful, we'll show a success message | |
| # The user can click "Close" to see the installation result | |
| # and then navigate to the tools page to see the new tool | |
| return [ | |
| gr.update(visible=True), # installation_result_container | |
| "✅ Installation Successful", # installation_status | |
| result # installation_result | |
| ] | |
| except Exception as e: | |
| print(f"Error installing tool: {e}") | |
| return [ | |
| gr.update(visible=True), # installation_result_container | |
| "⚠️ Installation Failed", # installation_status | |
| f"Error installing tool: {e}" # installation_result | |
| ] | |
| # Create components after defining the functions | |
| with gr.Row(): | |
| # Sidebar | |
| with gr.Column(elem_id="sidebar", scale=1): | |
| gr.Markdown("AI TOOLS", elem_classes="title") | |
| tools_btn = gr.Button("Tools", elem_classes="nav-button", variant="primary") | |
| marketplace_btn = gr.Button("Marketplace", elem_classes="nav-button", variant="secondary") | |
| settings_btn = gr.Button("Settings", elem_classes="nav-button", variant="secondary") | |
| gr.Markdown(f"version: {self.version}", elem_classes="version-text") | |
| # Main content | |
| with gr.Column(elem_id="main-content", scale=4): | |
| # Define all content containers | |
| tools_content = gr.Column(visible=True) | |
| marketplace_content = gr.Column(visible=False) | |
| settings_content = gr.Column(visible=False) | |
| tool_interfaces = gr.Column(visible=False) | |
| tool_details_content = gr.Column(visible=False) | |
| # Fill tools content | |
| with tools_content: | |
| gr.Markdown("Tools", elem_classes="page-title") | |
| tool_buttons = [] | |
| tool_ids = [] # Store tool_ids in the same order as tool_buttons | |
| # Create HTML for all tools | |
| tools_html = '' | |
| for tool_id, tool in self.tools.items(): | |
| # Create HTML for each tool card | |
| tools_html += f''' | |
| <div class="tool-card" id="tool-card-{tool_id}" onclick="document.getElementById('tool-btn-{tool_id}').click()"> | |
| <div class="tool-card-img"> | |
| {tool.icon} | |
| </div> | |
| <div class="tool-card-content"> | |
| <h3 class="tool-card-title">{tool.name}</h3> | |
| <p class="tool-card-description">{tool.description if hasattr(tool, 'description') else ""}</p> | |
| </div> | |
| </div> | |
| ''' | |
| # Create hidden buttons for tool selection | |
| btn = gr.Button(f"Select {tool.name}", visible=False, elem_id=f"tool-btn-{tool_id}") | |
| tool_buttons.append(btn) | |
| tool_ids.append(tool_id) | |
| # Add "Add New Tool" button | |
| tools_html += ''' | |
| <div class="tool-card add-tool-card" onclick="document.getElementById('add-tool-btn').click()"> | |
| <div class="add-tool-icon">+</div> | |
| <div>Add New Tool from Marketplace</div> | |
| </div> | |
| ''' | |
| # Render the HTML inside a div with the tool-grid class | |
| tools_html_component = gr.HTML(f'<div class="tool-grid">{tools_html}</div>') | |
| # Create hidden add tool button | |
| add_tool_btn = gr.Button("Add New Tool", visible=False, elem_id="add-tool-btn") | |
| # Fill marketplace content | |
| with marketplace_content: | |
| gr.Markdown("Marketplace", elem_classes="page-title") | |
| marketplace_html = gr.HTML("Loading marketplace tools...") | |
| # Create hidden buttons for marketplace tool details with unique IDs | |
| tool_buttons_container = gr.Column(visible=False) | |
| # Create hidden buttons for marketplace tools | |
| marketplace_tool_buttons = [] | |
| for i, tool in enumerate(self.fetch_marketplace_tools()): | |
| tool_btn = gr.Button(f"View {tool['name']}", visible=False, elem_id=f"marketplace-tool-btn-{i}") | |
| marketplace_tool_buttons.append((tool['id'], tool_btn)) | |
| # The click handlers for marketplace tool buttons will be set up after all components are defined | |
| # Fill tool details content | |
| with tool_details_content: | |
| # Installation result section at the top | |
| with gr.Column(elem_id="installation-result-container", elem_classes="installation-result-container", visible=False) as installation_result_container: | |
| installation_status = gr.Markdown("Ready to install", elem_id="installation-status") | |
| installation_result = gr.Markdown("Click the Install Tool button to install the selected tool.", elem_id="installation-result") | |
| close_result_btn = gr.Button("Close", elem_id="close-result-btn") | |
| # Confirmation dialog for tool removal | |
| with gr.Column(elem_id="confirmation-dialog", elem_classes="confirmation-dialog", visible=False) as confirmation_dialog: | |
| gr.Markdown("⚠️ Warning: Remove Tool", elem_id="confirmation-title", elem_classes="confirmation-title") | |
| gr.Markdown( | |
| "Are you sure you want to remove this tool? This action cannot be undone. " | |
| "All data created by this tool will be permanently deleted.", | |
| elem_id="confirmation-message", | |
| elem_classes="confirmation-message" | |
| ) | |
| with gr.Row(elem_classes="confirmation-buttons"): | |
| cancel_btn = gr.Button("Cancel", elem_classes="cancel-button") | |
| confirm_btn = gr.Button("Yes, Remove Tool", elem_classes="confirm-button") | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| back_btn = gr.Button("← Back to Marketplace", elem_classes="back-button") | |
| with gr.Column(scale=3): | |
| gr.Markdown("", elem_classes="page-title") | |
| # Tool details content | |
| tool_details_html = gr.HTML("") | |
| # Hidden install button (will be triggered by the inline button) | |
| install_btn = gr.Button("Add Tool", elem_classes="install-button", elem_id="install-btn", variant="primary", visible=False) | |
| # Hidden remove button (will be triggered by the inline button) | |
| remove_btn = gr.Button("Remove Tool", elem_classes="remove-button", elem_id="remove-btn", variant="primary", visible=False) | |
| # Add a direct event handler to the install button | |
| def debug_install_click(): | |
| print("Install button clicked directly!") | |
| return [gr.update(visible=True), gr.update(value="Install button clicked!")] | |
| # Add a direct event handler to the remove button to show confirmation dialog | |
| def show_confirmation_dialog(): | |
| print("Remove button clicked - showing confirmation dialog") | |
| return gr.update(visible=True) | |
| # Function to handle tool removal confirmation | |
| def remove_selected_tool(tool_details): | |
| print(f"Removing tool: {tool_details}") | |
| if not tool_details: | |
| print("No tool details provided") | |
| return [ | |
| gr.update(visible=False), # confirmation_dialog | |
| gr.update(visible=True), # installation_result_container | |
| "⚠️ Removal Failed", # installation_status | |
| "No tool selected to remove." # installation_result | |
| ] | |
| try: | |
| # Remove the tool | |
| result = self.remove_tool(tool_details['id']) | |
| if "Error" in result: | |
| return [ | |
| gr.update(visible=False), # confirmation_dialog | |
| gr.update(visible=True), # installation_result_container | |
| "⚠️ Removal Failed", # installation_status | |
| result # installation_result | |
| ] | |
| else: | |
| # After successful removal, show success message | |
| # The user will need to click "Back to Marketplace" manually | |
| # This avoids issues with dynamic UI updates | |
| return [ | |
| gr.update(visible=False), # confirmation_dialog | |
| gr.update(visible=True), # installation_result_container | |
| "✅ Removal Successful", # installation_status | |
| f"{result} - Click 'Back to Marketplace' to return. You may need to restart the application to see all changes." # installation_result | |
| ] | |
| except Exception as e: | |
| print(f"Error removing tool: {e}") | |
| return [ | |
| gr.update(visible=False), # confirmation_dialog | |
| gr.update(visible=True), # installation_result_container | |
| "⚠️ Removal Failed", # installation_status | |
| f"Error removing tool: {e}" # installation_result | |
| ] | |
| # Function to cancel removal | |
| def cancel_removal(): | |
| return gr.update(visible=False) | |
| debug_output = gr.Textbox(label="Debug Output", visible=False) | |
| # Set up event handlers for buttons | |
| install_btn.click( | |
| fn=install_selected_tool, | |
| inputs=[current_tool_details_state], | |
| outputs=[installation_result_container, installation_status, installation_result] | |
| ) | |
| remove_btn.click(fn=show_confirmation_dialog, outputs=confirmation_dialog) | |
| # Set up confirmation dialog buttons | |
| cancel_btn.click(fn=cancel_removal, outputs=confirmation_dialog) | |
| confirm_btn.click( | |
| fn=remove_selected_tool, | |
| inputs=[current_tool_details_state], | |
| outputs=[confirmation_dialog, installation_result_container, installation_status, installation_result] | |
| ) | |
| # Fill settings content | |
| with settings_content: | |
| gr.Markdown("Settings", elem_classes="page-title") | |
| gr.Markdown("Settings options will appear here...") | |
| # Fill tool interfaces | |
| with tool_interfaces: | |
| # Add an HTML component to display messages for newly installed tools | |
| tool_interfaces_html = gr.HTML("", elem_id="tool-interfaces-html") | |
| for tool_id, tool in self.tools.items(): | |
| with gr.Column(visible=False) as tool_container: | |
| tool_ui = tool.ui_class() | |
| tool_ui.create_ui() | |
| # Store the UI container in the tool object for later reference | |
| tool.ui_container = tool_container | |
| # Set up event handlers after all components are defined | |
| # Set up tool button events | |
| # Collect all tool containers for outputs | |
| tool_containers = [] | |
| for tool_id, tool in self.tools.items(): | |
| if hasattr(tool, 'ui_container'): | |
| tool_containers.append(tool.ui_container) | |
| # Set up click handlers for marketplace tool buttons | |
| for i, (tool_id, tool_btn) in enumerate(marketplace_tool_buttons): | |
| # We need to create a separate function for each button to avoid lambda closure issues | |
| def make_handler(tid): | |
| return lambda: show_tool_details(tid) | |
| handler = make_handler(tool_id) | |
| tool_btn.click( | |
| fn=handler, | |
| outputs=[ | |
| tools_content, marketplace_content, settings_content, tool_interfaces, | |
| tool_details_content, tools_btn, marketplace_btn, settings_btn, | |
| current_tool_details_state, tool_details_html, installation_result_container, | |
| confirmation_dialog, tool_interfaces_html | |
| ] + tool_containers | |
| ) | |
| for i, btn in enumerate(tool_buttons): | |
| if isinstance(btn, gr.Button): # Check if it's a button from the tools grid | |
| tool_id = tool_ids[i] # Get the corresponding tool_id | |
| # We need to create a separate function for each button to avoid lambda closure issues | |
| def make_handler(tid): | |
| return lambda: show_tool(tid) | |
| handler = make_handler(tool_id) | |
| btn.click( | |
| fn=handler, | |
| outputs=[tools_content, marketplace_content, settings_content, tool_interfaces, | |
| tool_details_content, tools_btn, marketplace_btn, settings_btn, | |
| tool_interfaces_html] + tool_containers | |
| ) | |
| # Set up navigation events | |
| tools_btn.click( | |
| fn=show_tools, | |
| outputs=[tools_content, marketplace_content, settings_content, tool_interfaces, | |
| tool_details_content, tools_btn, marketplace_btn, settings_btn, | |
| tools_html_component, tool_interfaces_html] + tool_containers | |
| ) | |
| marketplace_btn.click( | |
| fn=show_marketplace, | |
| outputs=[tools_content, marketplace_content, settings_content, tool_interfaces, | |
| tool_details_content, tools_btn, marketplace_btn, settings_btn, | |
| marketplace_tools_state, marketplace_html, installation_result_container, | |
| confirmation_dialog, tool_interfaces_html] + tool_containers | |
| ) | |
| settings_btn.click( | |
| fn=show_settings, | |
| outputs=[tools_content, marketplace_content, settings_content, tool_interfaces, | |
| tool_details_content, tools_btn, marketplace_btn, settings_btn, | |
| tool_interfaces_html] + tool_containers | |
| ) | |
| # Set up add tool button to navigate to marketplace | |
| add_tool_btn.click( | |
| fn=show_marketplace, | |
| outputs=[tools_content, marketplace_content, settings_content, tool_interfaces, | |
| tool_details_content, tools_btn, marketplace_btn, settings_btn, | |
| marketplace_tools_state, marketplace_html, installation_result_container, | |
| confirmation_dialog, tool_interfaces_html] + tool_containers | |
| ) | |
| # Set up event handlers for tool details | |
| back_btn.click( | |
| fn=show_marketplace, | |
| outputs=[ | |
| tools_content, marketplace_content, settings_content, tool_interfaces, | |
| tool_details_content, tools_btn, marketplace_btn, settings_btn, | |
| marketplace_tools_state, marketplace_html, installation_result_container, | |
| confirmation_dialog | |
| ] + tool_containers | |
| ) | |
| # Define a function to handle closing the installation result and navigating to tools | |
| def close_result_and_show_tools(): | |
| # First hide the installation result container | |
| installation_result_update = gr.update(visible=False) | |
| # Then get the updates from show_tools | |
| tools_updates = show_tools() | |
| # Combine the updates | |
| return [installation_result_update] + tools_updates | |
| # Set up close button for installation result | |
| close_result_btn.click( | |
| fn=close_result_and_show_tools, | |
| outputs=[installation_result_container, | |
| tools_content, marketplace_content, settings_content, tool_interfaces, | |
| tool_details_content, tools_btn, marketplace_btn, settings_btn, | |
| tools_html_component, tool_interfaces_html] + tool_containers | |
| ) | |
| return app | |
| if __name__ == "__main__": | |
| ui = MainUI() | |
| demo = ui.create_ui() | |
| demo.queue() # Add queue for better handling of multiple requests | |
| demo.title = "AI Tools Platform" # Add a title | |
| demo.launch( | |
| debug=True, | |
| share=True, | |
| server_name="0.0.0.0", | |
| server_port=7860 | |
| ) |