cmd / index.html
kamioll999's picture
Add 2 files
7be8de0 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Autonomous Agent Deployer</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://kit.fontawesome.com/a076d05399.js" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
/* Custom scrollbar */
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: #f1f1f1;
}
::-webkit-scrollbar-thumb {
background: #3b82f6;
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: #2563eb;
}
/* Smooth transitions */
.transition-all {
transition: all 0.3s ease;
}
/* Custom tooltip */
[data-tooltip] {
position: relative;
}
[data-tooltip]:hover:after {
content: attr(data-tooltip);
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
background: #1e293b;
color: white;
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
white-space: nowrap;
z-index: 10;
}
/* Gradient background */
.gradient-bg {
background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 50%, #ec4899 100%);
}
/* Active tab indicator */
.tab-indicator {
position: relative;
}
.tab-indicator:after {
content: '';
position: absolute;
bottom: -1px;
left: 0;
right: 0;
height: 3px;
background: #3b82f6;
border-radius: 3px 3px 0 0;
}
/* Fade in animation */
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.fade-in {
animation: fadeIn 0.3s ease-in;
}
/* Pulse animation */
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.pulse {
animation: pulse 2s infinite;
}
</style>
</head>
<body class="bg-gray-100 font-sans text-gray-800">
<div class="min-h-screen flex flex-col">
<!-- Header -->
<header class="gradient-bg text-white shadow-lg">
<div class="container mx-auto px-4 py-4">
<div class="flex justify-between items-center">
<div class="flex items-center space-x-2">
<i class="fas fa-robot text-2xl"></i>
<h1 class="text-2xl font-bold">Agent Deployer</h1>
</div>
<div class="flex items-center space-x-4">
<button id="saveConfigBtn" class="px-3 py-1 bg-white bg-opacity-20 rounded hover:bg-opacity-30 flex items-center space-x-1">
<i class="fas fa-save"></i>
<span>Save Config</span>
</button>
<div class="relative">
<button id="loadConfigBtn" class="px-3 py-1 bg-white bg-opacity-20 rounded hover:bg-opacity-30 flex items-center space-x-1">
<i class="fas fa-folder-open"></i>
<span>Load Config</span>
</button>
<input type="file" id="configFileInput" class="hidden" accept=".json">
</div>
<div id="statusIndicator" class="flex items-center space-x-1">
<div class="w-2 h-2 rounded-full bg-green-400"></div>
<span>Connected</span>
</div>
</div>
</div>
</div>
</header>
<!-- Main Content -->
<main class="flex-1 container mx-auto px-4 py-6 flex flex-col lg:flex-row gap-6">
<!-- Left Panel (Configuration) -->
<div class="w-full lg:w-1/3 bg-white rounded-lg shadow-md overflow-hidden">
<div class="border-b border-gray-200">
<ul class="flex divide-x divide-gray-200">
<li class="flex-1">
<button id="agentTabBtn" class="w-full py-3 px-4 text-center font-medium tab-indicator">
Agent Settings
</button>
</li>
<li class="flex-1">
<button id="browserTabBtn" class="w-full py-3 px-4 text-center font-medium text-gray-500 hover:text-gray-700">
Browser Settings
</button>
</li>
<li class="flex-1">
<button id="researchTabBtn" class="w-full py-3 px-4 text-center font-medium text-gray-500 hover:text-gray-700">
Research Agent
</button>
</li>
</ul>
</div>
<!-- Agent Settings Tab -->
<div id="agentTab" class="p-4 fade-in">
<div class="space-y-4">
<!-- Agent Type -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Agent Type</label>
<div class="flex space-x-4">
<label class="inline-flex items-center">
<input type="radio" name="agent_type" value="custom" checked class="form-radio text-blue-600">
<span class="ml-2">Custom</span>
</label>
<label class="inline-flex items-center">
<input type="radio" name="agent_type" value="org" class="form-radio text-blue-600">
<span class="ml-2">Organization</span>
</label>
</div>
</div>
<!-- Task Configuration -->
<div>
<label for="task" class="block text-sm font-medium text-gray-700 mb-1">Task Description</label>
<textarea id="task" rows="3" class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500" placeholder="Describe the task for the agent...">go to google.com and type 'OpenAI' click search and give me the first url</textarea>
</div>
<div>
<label for="add_infos" class="block text-sm font-medium text-gray-700 mb-1">Additional Information</label>
<textarea id="add_infos" rows="2" class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500" placeholder="Any additional context or instructions..."></textarea>
</div>
<!-- LLM Configuration -->
<div class="space-y-4 p-4 bg-gray-50 rounded-md">
<h3 class="text-lg font-medium text-gray-900 flex items-center space-x-2">
<i class="fas fa-brain text-blue-500"></i>
<span>LLM Configuration</span>
</h3>
<div>
<label for="llm_provider" class="block text-sm font-medium text-gray-700 mb-1">LLM Provider</label>
<select id="llm_provider" class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500">
<option value="openai" selected>OpenAI</option>
<option value="anthropic">Anthropic</option>
<option value="ollama">Ollama</option>
<option value="google">Google</option>
</select>
</div>
<div>
<label for="llm_model_name" class="block text-sm font-medium text-gray-700 mb-1">Model Name</label>
<select id="llm_model_name" class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500">
<option value="gpt-4" selected>gpt-4</option>
<option value="gpt-4-turbo">gpt-4-turbo</option>
<option value="gpt-4o">gpt-4o</option>
<option value="gpt-3.5-turbo">gpt-3.5-turbo</option>
</select>
</div>
<div id="llm_num_ctx_container">
<label for="llm_num_ctx" class="block text-sm font-medium text-gray-700 mb-1">Context Length</label>
<input type="range" id="llm_num_ctx" min="512" max="128000" step="512" value="16000" class="w-full">
<div class="flex justify-between text-xs text-gray-500">
<span>512</span>
<span id="llm_num_ctx_value">16,000</span>
<span>128,000</span>
</div>
</div>
<div>
<label for="llm_temperature" class="block text-sm font-medium text-gray-700 mb-1">Temperature</label>
<input type="range" id="llm_temperature" min="0" max="2" step="0.1" value="0.6" class="w-full">
<div class="flex justify-between text-xs text-gray-500">
<span>Precise (0)</span>
<span id="llm_temperature_value">0.6</span>
<span>Creative (2)</span>
</div>
</div>
<div>
<label for="llm_api_key" class="block text-sm font-medium text-gray-700 mb-1">API Key</label>
<div class="relative">
<input type="password" id="llm_api_key" class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500" placeholder="Enter API key...">
<button id="toggleKeyVisibility" class="absolute right-2 top-2 text-gray-400 hover:text-gray-600">
<i class="fas fa-eye"></i>
</button>
</div>
</div>
<div>
<label for="llm_base_url" class="block text-sm font-medium text-gray-700 mb-1">Base URL (optional)</label>
<input type="text" id="llm_base_url" class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500" placeholder="Custom API endpoint...">
</div>
</div>
<!-- Agent Performance -->
<div class="space-y-4 p-4 bg-gray-50 rounded-md">
<h3 class="text-lg font-medium text-gray-900 flex items-center space-x-2">
<i class="fas fa-tachometer-alt text-blue-500"></i>
<span>Performance Settings</span>
</h3>
<div>
<label for="max_steps" class="block text-sm font-medium text-gray-700 mb-1">Max Run Steps</label>
<input type="range" id="max_steps" min="1" max="500" step="1" value="100" class="w-full">
<div class="flex justify-between text-xs text-gray-500">
<span>1</span>
<span id="max_steps_value">100</span>
<span>500</span>
</div>
</div>
<div>
<label for="max_actions_per_step" class="block text-sm font-medium text-gray-700 mb-1">Max Actions per Step</label>
<input type="range" id="max_actions_per_step" min="1" max="20" step="1" value="10" class="w-full">
<div class="flex justify-between text-xs text-gray-500">
<span>1</span>
<span id="max_actions_per_step_value">10</span>
<span>20</span>
</div>
</div>
<div>
<label for="max_input_tokens" class="block text-sm font-medium text-gray-700 mb-1">Max Input Tokens</label>
<input type="number" id="max_input_tokens" min="512" max="512000" step="512" value="128000" class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500">
</div>
<div>
<label for="tool_calling_method" class="block text-sm font-medium text-gray-700 mb-1">Tool Calling Method</label>
<select id="tool_calling_method" class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500">
<option value="auto" selected>Auto</option>
<option value="parallel">Parallel</option>
<option value="sequential">Sequential</option>
</select>
</div>
</div>
<!-- Vision Settings -->
<div class="p-4 bg-gray-50 rounded-md">
<div class="flex items-center justify-between">
<label for="use_vision" class="flex items-center space-x-2 cursor-pointer">
<input type="checkbox" id="use_vision" checked class="form-checkbox h-4 w-4 text-blue-600">
<span class="text-sm font-medium text-gray-700">Use Vision</span>
</label>
</div>
</div>
</div>
</div>
<!-- Browser Settings Tab -->
<div id="browserTab" class="p-4 hidden fade-in">
<div class="space-y-4">
<!-- Browser Options -->
<div class="space-y-4 p-4 bg-gray-50 rounded-md">
<h3 class="text-lg font-medium text-gray-900 flex items-center space-x-2">
<i class="fas fa-window-restore text-blue-500"></i>
<span>Browser Options</span>
</h3>
<div>
<label for="use_own_browser" class="flex items-center space-x-2 cursor-pointer">
<input type="checkbox" id="use_own_browser" class="form-checkbox h-4 w-4 text-blue-600">
<span class="text-sm font-medium text-gray-700">Use Own Browser</span>
</label>
<p class="text-xs text-gray-500 mt-1">Connect to an existing browser instance</p>
</div>
<div>
<label for="keep_browser_open" class="flex items-center space-x-2 cursor-pointer">
<input type="checkbox" id="keep_browser_open" class="form-checkbox h-4 w-4 text-blue-600">
<span class="text-sm font-medium text-gray-700">Keep Browser Open</span>
</label>
</div>
<div>
<label for="headless" class="flex items-center space-x-2 cursor-pointer">
<input type="checkbox" id="headless" class="form-checkbox h-4 w-4 text-blue-600">
<span class="text-sm font-medium text-gray-700">Headless Mode</span>
</label>
</div>
<div>
<label for="disable_security" class="flex items-center space-x-2 cursor-pointer">
<input type="checkbox" id="disable_security" checked class="form-checkbox h-4 w-4 text-blue-600">
<span class="text-sm font-medium text-gray-700">Disable Security</span>
</label>
<p class="text-xs text-gray-500 mt-1">Disable same-origin policy and web security</p>
</div>
</div>
<!-- Window Settings -->
<div class="space-y-4 p-4 bg-gray-50 rounded-md">
<h3 class="text-lg font-medium text-gray-900 flex items-center space-x-2">
<i class="fas fa-ruler-combined text-blue-500"></i>
<span>Window Settings</span>
</h3>
<div class="grid grid-cols-2 gap-4">
<div>
<label for="window_w" class="block text-sm font-medium text-gray-700 mb-1">Width</label>
<input type="number" id="window_w" min="800" max="3840" step="1" value="1280" class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500">
</div>
<div>
<label for="window_h" class="block text-sm font-medium text-gray-700 mb-1">Height</label>
<input type="number" id="window_h" min="600" max="2160" step="1" value="1100" class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500">
</div>
</div>
<div>
<label for="chrome_cdp" class="block text-sm font-medium text-gray-700 mb-1">CDP URL (optional)</label>
<input type="text" id="chrome_cdp" class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500" placeholder="ws://127.0.0.1:9222/devtools/browser/...">
</div>
</div>
<!-- Recording Settings -->
<div class="space-y-4 p-4 bg-gray-50 rounded-md">
<h3 class="text-lg font-medium text-gray-900 flex items-center space-x-2">
<i class="fas fa-video text-blue-500"></i>
<span>Recording Settings</span>
</h3>
<div>
<label for="enable_recording" class="flex items-center space-x-2 cursor-pointer">
<input type="checkbox" id="enable_recording" checked class="form-checkbox h-4 w-4 text-blue-600">
<span class="text-sm font-medium text-gray-700">Enable Recording</span>
</label>
</div>
<div>
<label for="save_recording_path" class="block text-sm font-medium text-gray-700 mb-1">Recording Path</label>
<input type="text" id="save_recording_path" value="./tmp/record_videos" class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500">
</div>
<div>
<label for="save_agent_history_path" class="block text-sm font-medium text-gray-700 mb-1">Agent History Path</label>
<input type="text" id="save_agent_history_path" value="./tmp/agent_history" class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500">
</div>
<div>
<label for="save_trace_path" class="block text-sm font-medium text-gray-700 mb-1">Trace Path</label>
<input type="text" id="save_trace_path" value="./tmp/traces" class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500">
</div>
</div>
</div>
</div>
<!-- Research Agent Tab -->
<div id="researchTab" class="p-4 hidden fade-in">
<div class="space-y-4">
<!-- Research Task -->
<div>
<label for="research_task" class="block text-sm font-medium text-gray-700 mb-1">Research Task</label>
<textarea id="research_task" rows="4" class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500" placeholder="Describe the research task...">Compose a report on the use of Reinforcement Learning for training Large Language Models, encompassing its origins, current advancements, and future prospects, substantiated with examples of relevant models and techniques. The report should reflect original insights and analysis, moving beyond mere summarization of existing literature.</textarea>
</div>
<!-- Search Parameters -->
<div class="space-y-4 p-4 bg-gray-50 rounded-md">
<h3 class="text-lg font-medium text-gray-900 flex items-center space-x-2">
<i class="fas fa-search text-blue-500"></i>
<span>Search Parameters</span>
</h3>
<div>
<label for="max_search_iteration_input" class="block text-sm font-medium text-gray-700 mb-1">Max Search Iterations</label>
<input type="number" id="max_search_iteration_input" min="1" max="20" value="3" class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500">
</div>
<div>
<label for="max_query_per_iter_input" class="block text-sm font-medium text-gray-700 mb-1">Max Queries per Iteration</label>
<input type="number" id="max_query_per_iter_input" min="1" max="10" value="1" class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500">
</div>
</div>
<!-- Research Action Buttons -->
<div class="flex space-x-3 justify-center">
<button id="runResearchBtn" class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 flex items-center space-x-2">
<i class="fas fa-play"></i>
<span>Run Research</span>
</button>
<button id="stopResearchBtn" class="px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-700 flex items-center space-x-2">
<i class="fas fa-stop"></i>
<span>Stop Research</span>
</button>
</div>
</div>
</div>
<!-- Action Buttons -->
<div class="p-4 border-t border-gray-200 bg-gray-50 flex space-x-3">
<button id="runAgentBtn" class="flex-1 px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 flex items-center justify-center space-x-2">
<i class="fas fa-play"></i>
<span>Run Agent</span>
</button>
<button id="stopAgentBtn" class="px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-700">
<i class="fas fa-stop"></i>
</button>
</div>
</div>
<!-- Right Panel (Output) -->
<div class="w-full lg:w-2/3 bg-white rounded-lg shadow-md overflow-hidden flex flex-col">
<div class="border-b border-gray-200">
<ul class="flex divide-x divide-gray-200">
<li class="flex-1">
<button id="outputTabBtn" class="w-full py-3 px-4 text-center font-medium tab-indicator">
Execution Output
</button>
</li>
<li class="flex-1">
<button id="recordingsTabBtn" class="w-full py-3 px-4 text-center font-medium text-gray-500 hover:text-gray-700">
Recordings
</button>
</li>
<li class="flex-1">
<button id="researchOutputTabBtn" class="w-full py-3 px-4 text-center font-medium text-gray-500 hover:text-gray-700">
Research Output
</button>
</li>
</ul>
</div>
<!-- Output Tab -->
<div id="outputTab" class="p-4 flex flex-col flex-1 fade-in">
<!-- Browser View -->
<div class="mb-4">
<div class="flex justify-between items-center mb-2">
<h3 class="text-lg font-medium text-gray-900">Live Browser View</h3>
<button id="refreshBrowserBtn" class="text-blue-600 hover:text-blue-800">
<i class="fas fa-sync-alt"></i>
</button>
</div>
<div id="browserView" class="w-full h-64 bg-gray-100 border border-gray-300 rounded-md flex items-center justify-center">
<p class="text-gray-500">Browser view will appear here when agent is running</p>
</div>
</div>
<!-- Agent Output Sections -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 flex-1">
<!-- Final Result -->
<div class="bg-gray-50 rounded-md p-4 h-64 overflow-y-auto">
<h3 class="text-lg font-medium text-gray-900 mb-2">Final Result</h3>
<div id="finalResult" class="w-full h-48 bg-white border border-gray-300 rounded p-2 text-sm overflow-y-auto"></div>
</div>
<!-- Errors -->
<div class="bg-gray-50 rounded-md p-4 h-64 overflow-y-auto">
<h3 class="text-lg font-medium text-gray-900 mb-2">Errors</h3>
<div id="errors" class="w-full h-48 bg-white border border-gray-300 rounded p-2 text-sm overflow-y-auto"></div>
</div>
<!-- Model Actions -->
<div class="bg-gray-50 rounded-md p-4 h-64 overflow-y-auto">
<h3 class="text-lg font-medium text-gray-900 mb-2">Model Actions</h3>
<div id="modelActions" class="w-full h-48 bg-white border border-gray-300 rounded p-2 text-sm overflow-y-auto"></div>
</div>
<!-- Model Thoughts -->
<div class="bg-gray-50 rounded-md p-4 h-64 overflow-y-auto">
<h3 class="text-lg font-medium text-gray-900 mb-2">Model Thoughts</h3>
<div id="modelThoughts" class="w-full h-48 bg-white border border-gray-300 rounded p-2 text-sm overflow-y-auto"></div>
</div>
</div>
<!-- Result GIF and Files -->
<div class="mt-4 grid grid-cols-1 md:grid-cols-3 gap-4">
<div class="bg-gray-50 rounded-md p-4">
<h3 class="text-lg font-medium text-gray-900 mb-2">Result GIF</h3>
<div id="resultGif" class="w-full h-32 bg-white border border-gray-300 rounded flex items-center justify-center">
<p class="text-gray-500 text-sm">Recording GIF will appear here</p>
</div>
</div>
<div class="bg-gray-50 rounded-md p-4">
<h3 class="text-lg font-medium text-gray-900 mb-2">Trace File</h3>
<div id="traceFile" class="w-full h-32 bg-white border border-gray-300 rounded flex items-center justify-center">
<p class="text-gray-500 text-sm">Trace file will appear here</p>
</div>
</div>
<div class="bg-gray-50 rounded-md p-4">
<h3 class="text-lg font-medium text-gray-900 mb-2">Agent History</h3>
<div id="agentHistory" class="w-full h-32 bg-white border border-gray-300 rounded flex items-center justify-center">
<p class="text-gray-500 text-sm">Agent history will appear here</p>
</div>
</div>
</div>
</div>
<!-- Recordings Tab -->
<div id="recordingsTab" class="p-4 hidden flex flex-col flex-1 fade-in">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-medium text-gray-900">Session Recordings</h3>
<div class="flex space-x-2">
<button id="refreshRecordingsBtn" class="px-3 py-1 bg-gray-200 rounded hover:bg-gray-300">
<i class="fas fa-sync-alt"></i>
</button>
<button id="openRecordingsFolderBtn" class="px-3 py-1 bg-gray-200 rounded hover:bg-gray-300">
<i class="fas fa-folder-open"></i>
</button>
</div>
</div>
<div id="recordingsList" class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 flex-1 overflow-y-auto">
<!-- Recordings will be loaded here -->
<div class="border rounded-md p-3">
<div class="bg-gray-100 h-32 rounded flex items-center justify-center">
<i class="fas fa-video text-gray-400 text-2xl"></i>
</div>
<div class="mt-2">
<p class="text-sm font-medium">2023-11-15_14-30-22</p>
<p class="text-xs text-gray-500">2.4 MB • 45s</p>
</div>
<div class="mt-2 flex space-x-2">
<button class="text-xs px-2 py-1 bg-blue-100 text-blue-800 rounded hover:bg-blue-200">
<i class="fas fa-play"></i>
</button>
<button class="text-xs px-2 py-1 bg-gray-100 text-gray-800 rounded hover:bg-gray-200">
<i class="fas fa-download"></i>
</button>
<button class="text-xs px-2 py-1 bg-gray-100 text-gray-800 rounded hover:bg-gray-200">
<i class="fas fa-trash"></i>
</button>
</div>
</div>
<div class="border rounded-md p-3">
<div class="bg-gray-100 h-32 rounded flex items-center justify-center">
<i class="fas fa-video text-gray-400 text-2xl"></i>
</div>
<div class="mt-2">
<p class="text-sm font-medium">2023-11-15_11-45-10</p>
<p class="text-xs text-gray-500">1.8 MB • 32s</p>
</div>
<div class="mt-2 flex space-x-2">
<button class="text-xs px-2 py-1 bg-blue-100 text-blue-800 rounded hover:bg-blue-200">
<i class="fas fa-play"></i>
</button>
<button class="text-xs px-2 py-1 bg-gray-100 text-gray-800 rounded hover:bg-gray-200">
<i class="fas fa-download"></i>
</button>
<button class="text-xs px-2 py-1 bg-gray-100 text-gray-800 rounded hover:bg-gray-200">
<i class="fas fa-trash"></i>
</button>
</div>
</div>
<div class="border rounded-md p-3">
<div class="bg-gray-100 h-32 rounded flex items-center justify-center">
<i class="fas fa-video text-gray-400 text-2xl"></i>
</div>
<div class="mt-2">
<p class="text-sm font-medium">2023-11-14_09-15-47</p>
<p class="text-xs text-gray-500">3.2 MB • 58s</p>
</div>
<div class="mt-2 flex space-x-2">
<button class="text-xs px-2 py-1 bg-blue-100 text-blue-800 rounded hover:bg-blue-200">
<i class="fas fa-play"></i>
</button>
<button class="text-xs px-2 py-1 bg-gray-100 text-gray-800 rounded hover:bg-gray-200">
<i class="fas fa-download"></i>
</button>
<button class="text-xs px-2 py-1 bg-gray-100 text-gray-800 rounded hover:bg-gray-200">
<i class="fas fa-trash"></i>
</button>
</div>
</div>
</div>
</div>
<!-- Research Output Tab -->
<div id="researchOutputTab" class="p-4 hidden flex flex-col flex-1 fade-in">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-medium text-gray-900">Research Report Output</h3>
<button id="downloadReportBtn" class="px-3 py-1 bg-blue-100 text-blue-800 rounded hover:bg-blue-200">
<i class="fas fa-download"></i> Download Report
</button>
</div>
<div id="researchReport" class="flex-1 bg-gray-50 rounded-md p-4 overflow-y-auto">
<div class="prose max-w-none">
<h1>Research Report</h1>
<p>Research report output will appear here once the research agent completes its task.</p>
</div>
</div>
</div>
</div>
</main>
<!-- Status Bar -->
<footer class="bg-gray-800 text-white text-sm px-4 py-2">
<div class="flex justify-between items-center">
<div id="statusText" class="flex items-center space-x-2">
<span class="font-medium">Status:</span>
<span>Ready</span>
</div>
<div class="flex items-center space-x-4">
<span id="timeDisplay" class="font-mono">--:--:--</span>
</div>
</div>
</footer>
</div>
<script>
// Initialize variables
let agentRunning = false;
let researchRunning = false;
let client = null;
let gradientInterval = null;
// DOM Elements
const saveConfigBtn = document.getElementById('saveConfigBtn');
const loadConfigBtn = document.getElementById('loadConfigBtn');
const configFileInput = document.getElementById('configFileInput');
const runAgentBtn = document.getElementById('runAgentBtn');
const stopAgentBtn = document.getElementById('stopAgentBtn');
const runResearchBtn = document.getElementById('runResearchBtn');
const stopResearchBtn = document.getElementById('stopResearchBtn');
const refreshBrowserBtn = document.getElementById('refreshBrowserBtn');
const refreshRecordingsBtn = document.getElementById('refreshRecordingsBtn');
const openRecordingsFolderBtn = document.getElementById('openRecordingsFolderBtn');
const downloadReportBtn = document.getElementById('downloadReportBtn');
const toggleKeyVisibility = document.getElementById('toggleKeyVisibility');
const llmApiKey = document.getElementById('llm_api_key');
// Tab elements
const agentTabBtn = document.getElementById('agentTabBtn');
const browserTabBtn = document.getElementById('browserTabBtn');
const researchTabBtn = document.getElementById('researchTabBtn');
const agentTab = document.getElementById('agentTab');
const browserTab = document.getElementById('browserTab');
const researchTab = document.getElementById('researchTab');
const outputTabBtn = document.getElementById('outputTabBtn');
const recordingsTabBtn = document.getElementById('recordingsTabBtn');
const researchOutputTabBtn = document.getElementById('researchOutputTabBtn');
const outputTab = document.getElementById('outputTab');
const recordingsTab = document.getElementById('recordingsTab');
const researchOutputTab = document.getElementById('researchOutputTab');
// Status elements
const statusText = document.getElementById('statusText');
const statusIndicator = document.getElementById('statusIndicator');
const timeDisplay = document.getElementById('timeDisplay');
// Range sliders with values
const llmNumCtx = document.getElementById('llm_num_ctx');
const llmNumCtxValue = document.getElementById('llm_num_ctx_value');
const llmTemperature = document.getElementById('llm_temperature');
const llmTemperatureValue = document.getElementById('llm_temperature_value');
const maxSteps = document.getElementById('max_steps');
const maxStepsValue = document.getElementById('max_steps_value');
const maxActionsPerStep = document.getElementById('max_actions_per_step');
const maxActionsPerStepValue = document.getElementById('max_actions_per_step_value');
// Output elements
const browserView = document.getElementById('browserView');
const finalResult = document.getElementById('finalResult');
const errors = document.getElementById('errors');
const modelActions = document.getElementById('modelActions');
const modelThoughts = document.getElementById('modelThoughts');
const resultGif = document.getElementById('resultGif');
const traceFile = document.getElementById('traceFile');
const agentHistory = document.getElementById('agentHistory');
const researchReport = document.getElementById('researchReport');
// Initialize connection to Gradio API
async function initClient() {
try {
// In a real app, you would import the Gradio client like this:
// import { Client } from "@gradio/client";
// client = await Client.connect("http://127.0.0.1:7788/");
// For this demo, we'll simulate the connection
client = {
connected: true,
predict: async function(endpoint, data) {
console.log(`API call to ${endpoint}`, data);
// Simulate API response with a delay
return new Promise(resolve => {
setTimeout(() => {
resolve({
data: simulateApiResponse(endpoint, data)
});
}, 1000);
});
}
};
updateStatusIndicator(true);
showStatusMessage("Connected to API server");
console.log("Client connected successfully");
} catch (error) {
updateStatusIndicator(false);
showStatusMessage("Failed to connect to API: " + error.message, true);
console.error("Failed to connect to API:", error);
}
}
// Simulate API responses for demo purposes
function simulateApiResponse(endpoint, data) {
switch(endpoint) {
case '/run_with_stream':
return [
"<iframe src='https://google.com' width='100%' height='100%'></iframe>",
"Completed task successfully. First result URL: https://openai.com",
"",
"1. Navigated to google.com\n2. Typed 'OpenAI'\n3. Clicked search\n4. Retrieved first result URL",
"I need to search for OpenAI on Google and return the first result. I'll use the browser.",
null, // GIF placeholder
null, // Trace file
null // Agent history
];
case '/run_deep_search':
return [
"<h1>Research Report: Reinforcement Learning for LLM Training</h1><p>This is a detailed research report on how reinforcement learning is used to train large language models...</p>",
null // Download link placeholder
];
case '/stop_agent':
return ["Agent stopped successfully"];
case '/stop_research_agent':
return ["Research agent stopped successfully"];
case '/list_recordings':
return ["Recordings list goes here"];
case '/save_current_config':
return ["Configuration saved successfully"];
case '/lambda':
return ["gpt-4-turbo"];
case '/lambda_1':
return ["./tmp/record_videos"];
case '/close_global_browser':
return ["Browser closed"];
case '/close_global_browser_1':
return ["Browser closed"];
case '/update_ui_from_config':
return Array(28).fill(null); // Placeholder for all config fields
case '/update_llm_num_ctx_visibility':
return [256]; // Default context length
default:
return ["Unknown endpoint"];
}
}
// Update status indicator
function updateStatusIndicator(connected) {
const indicator = statusIndicator.querySelector('div');
if (connected) {
indicator.classList.remove('bg-red-500');
indicator.classList.add('bg-green-400');
indicator.nextElementSibling.textContent = 'Connected';
} else {
indicator.classList.remove('bg-green-400');
indicator.classList.add('bg-red-500');
indicator.nextElementSibling.textContent = 'Disconnected';
}
}
// Show status message
function showStatusMessage(message, isError = false) {
const statusEl = statusText.querySelector('span:last-child');
statusEl.textContent = message;
if (isError) {
statusEl.classList.add('text-red-400');
statusEl.classList.remove('text-green-400');
} else {
statusEl.classList.add('text-green-400');
statusEl.classList.remove('text-red-400');
}
// Auto-clear after 5 seconds if not an error
if (!isError) {
setTimeout(() => {
if (statusEl.textContent === message) {
statusEl.textContent = 'Ready';
statusEl.classList.remove('text-green-400');
}
}, 5000);
}
}
// Format numbers with commas
function formatNumber(num) {
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
// Update time display
function updateTime() {
const now = new Date();
const hours = now.getHours().toString().padStart(2, '0');
const minutes = now.getMinutes().toString().padStart(2, '0');
const seconds = now.getSeconds().toString().padStart(2, '0');
timeDisplay.textContent = `${hours}:${minutes}:${seconds}`;
}
// Toggle API key visibility
toggleKeyVisibility.addEventListener('click', () => {
if (llmApiKey.type === 'password') {
llmApiKey.type = 'text';
toggleKeyVisibility.innerHTML = '<i class="fas fa-eye-slash"></i>';
} else {
llmApiKey.type = 'password';
toggleKeyVisibility.innerHTML = '<i class="fas fa-eye"></i>';
}
});
// Update slider value displays
function updateSliderValues() {
llmNumCtxValue.textContent = formatNumber(parseInt(llmNumCtx.value));
llmTemperatureValue.textContent = parseFloat(llmTemperature.value).toFixed(1);
maxStepsValue.textContent = formatNumber(parseInt(maxSteps.value));
maxActionsPerStepValue.textContent = formatNumber(parseInt(maxActionsPerStep.value));
}
// Run agent
runAgentBtn.addEventListener('click', async () => {
if (agentRunning) {
showStatusMessage("Agent is already running", true);
return;
}
try {
agentRunning = true;
runAgentBtn.disabled = true;
stopAgentBtn.disabled = false;
showStatusMessage("Starting agent...");
// Get all form values
const params = {
agent_type: document.querySelector('input[name="agent_type"]:checked').value,
llm_provider: document.getElementById('llm_provider').value,
llm_model_name: document.getElementById('llm_model_name').value,
llm_num_ctx: parseInt(document.getElementById('llm_num_ctx').value),
llm_temperature: parseFloat(document.getElementById('llm_temperature').value),
llm_base_url: document.getElementById('llm_base_url').value,
llm_api_key: document.getElementById('llm_api_key').value,
use_own_browser: document.getElementById('use_own_browser').checked,
keep_browser_open: document.getElementById('keep_browser_open').checked,
headless: document.getElementById('headless').checked,
disable_security: document.getElementById('disable_security').checked,
window_w: parseInt(document.getElementById('window_w').value),
window_h: parseInt(document.getElementById('window_h').value),
save_recording_path: document.getElementById('save_recording_path').value,
save_agent_history_path: document.getElementById('save_agent_history_path').value,
save_trace_path: document.getElementById('save_trace_path').value,
enable_recording: document.getElementById('enable_recording').checked,
task: document.getElementById('task').value,
add_infos: document.getElementById('add_infos').value,
max_steps: parseInt(document.getElementById('max_steps').value),
use_vision: document.getElementById('use_vision').checked,
max_actions_per_step: parseInt(document.getElementById('max_actions_per_step').value),
tool_calling_method: document.getElementById('tool_calling_method').value,
chrome_cdp: document.getElementById('chrome_cdp').value,
max_input_tokens: parseInt(document.getElementById('max_input_tokens').value)
};
// Call the API
const result = await client.predict('/run_with_stream', params);
// Process the response
if (result.data && result.data.length >= 8) {
browserView.innerHTML = result.data[0];
finalResult.textContent = result.data[1];
errors.textContent = result.data[2];
modelActions.textContent = result.data[3];
modelThoughts.textContent = result.data[4];
// For demo purposes, we'll just show a placeholder
if (result.data[5] !== null) {
resultGif.innerHTML = '<img src="https://via.placeholder.com/300x150?text=Recording+GIF" class="w-full h-full object-cover">';
}
showStatusMessage("Agent completed task successfully");
} else {
showStatusMessage("Unexpected response format from API", true);
}
} catch (error) {
showStatusMessage("Error running agent: " + error.message, true);
console.error("Error running agent:", error);
} finally {
agentRunning = false;
runAgentBtn.disabled = false;
stopAgentBtn.disabled = true;
}
});
// Stop agent
stopAgentBtn.addEventListener('click', async () => {
if (!agentRunning) {
return;
}
try {
showStatusMessage("Stopping agent...");
const result = await client.predict('/stop_agent', {});
if (result.data && result.data[0]) {
showStatusMessage(result.data[0]);
}
} catch (error) {
showStatusMessage("Error stopping agent: " + error.message, true);
console.error("Error stopping agent:", error);
} finally {
agentRunning = false;
runAgentBtn.disabled = false;
stopAgentBtn.disabled = true;
}
});
// Run research agent
runResearchBtn.addEventListener('click', async () => {
if (researchRunning) {
showStatusMessage("Research agent is already running", true);
return;
}
try {
researchRunning = true;
runResearchBtn.disabled = true;
stopResearchBtn.disabled = false;
showStatusMessage("Starting research agent...");
// Get all form values
const params = {
research_task: document.getElementById('research_task').value,
max_search_iteration_input: parseInt(document.getElementById('max_search_iteration_input').value),
max_query_per_iter_input: parseInt(document.getElementById('max_query_per_iter_input').value),
llm_provider: document.getElementById('llm_provider').value,
llm_model_name: document.getElementById('llm_model_name').value,
llm_num_ctx: parseInt(document.getElementById('llm_num_ctx').value),
llm_temperature: parseFloat(document.getElementById('llm_temperature').value),
llm_base_url: document.getElementById('llm_base_url').value,
llm_api_key: document.getElementById('llm_api_key').value,
use_vision: document.getElementById('use_vision').checked,
use_own_browser: document.getElementById('use_own_browser').checked,
headless: document.getElementById('headless').checked,
chrome_cdp: document.getElementById('chrome_cdp').value
};
// Call the API
const result = await client.predict('/run_deep_search', params);
// Process the response
if (result.data && result.data.length >= 2) {
researchReport.innerHTML = result.data[0];
// Check if we have a downloadable report
if (result.data[1] !== null) {
downloadReportBtn.style.display = 'block';
}
// Switch to research output tab
researchOutputTabBtn.click();
showStatusMessage("Research completed successfully");
} else {
showStatusMessage("Unexpected response format from API", true);
}
} catch (error) {
showStatusMessage("Error running research agent: " + error.message, true);
console.error("Error running research agent:", error);
} finally {
researchRunning = false;
runResearchBtn.disabled = false;
stopResearchBtn.disabled = true;
}
});
// Stop research agent
stopResearchBtn.addEventListener('click', async () => {
if (!researchRunning) {
return;
}
try {
showStatusMessage("Stopping research agent...");
const result = await client.predict('/stop_research_agent', {});
if (result.data && result.data[0]) {
showStatusMessage(result.data[0]);
}
} catch (error) {
showStatusMessage("Error stopping research agent: " + error.message, true);
console.error("Error stopping research agent:", error);
} finally {
researchRunning = false;
runResearchBtn.disabled = false;
stopResearchBtn.disabled = true;
}
});
// Save current configuration
saveConfigBtn.addEventListener('click', async () => {
try {
showStatusMessage("Saving configuration...");
const result = await client.predict('/save_current_config', {});
if (result.data && result.data[0]) {
showStatusMessage(result.data[0]);
}
} catch (error) {
showStatusMessage("Error saving configuration: " + error.message, true);
console.error("Error saving configuration:", error);
}
});
// Load configuration from file
loadConfigBtn.addEventListener('click', () => {
configFileInput.click();
});
configFileInput.addEventListener('change', async (e) => {
if (!e.target.files.length) return;
const file = e.target.files[0];
try {
showStatusMessage("Loading configuration...");
// In a real app, you would use FileReader to read the file
// For demo, we'll simulate loading a config
const result = await client.predict('/update_ui_from_config', {
config_file: file
});
if (result.data && result.data.length >= 28) {
// Update UI with loaded config (simplified for demo)
document.querySelector(`input[name="agent_type"][value="${result.data[0] || 'custom'}"]`).checked = true;
document.getElementById('max_steps').value = result.data[1] || 100;
document.getElementById('max_actions_per_step').value = result.data[2] || 10;
document.getElementById('use_vision').checked = result.data[3] || true;
document.getElementById('max_input_tokens').value = result.data[4] || 128000;
document.getElementById('tool_calling_method').value = result.data[5] || 'auto';
document.getElementById('llm_provider').value = result.data[6] || 'openai';
document.getElementById('llm_model_name').value = result.data[7] || 'gpt-4o';
document.getElementById('llm_num_ctx').value = result.data[8] || 16000;
document.getElementById('llm_temperature').value = result.data[9] || 0.6;
document.getElementById('use_own_browser').checked = result.data[10] || false;
document.getElementById('keep_browser_open').checked = result.data[11] || false;
document.getElementById('headless').checked = result.data[12] || false;
document.getElementById('disable_security').checked = result.data[13] || true;
document.getElementById('enable_recording').checked = result.data[14] || true;
document.getElementById('window_w').value = result.data[15] || 1280;
document.getElementById('window_h').value = result.data[16] || 1100;
document.getElementById('chrome_cdp').value = result.data[17] || '';
document.getElementById('save_recording_path').value = result.data[18] || './tmp/record_videos';
document.getElementById('save_trace_path').value = result.data[19] || './tmp/traces';
document.getElementById('save_agent_history_path').value = result.data[20] || './tmp/agent_history';
document.getElementById('task').value = result.data[21] || '';
document.getElementById('add_infos').value = result.data[22] || '';
document.getElementById('research_task').value = result.data[23] || '';
document.getElementById('max_search_iteration_input').value = result.data[24] || 3;
document.getElementById('max_query_per_iter_input').value = result.data[25] || 1;
updateSliderValues();
showStatusMessage("Configuration loaded successfully");
} else {
showStatusMessage("Unexpected response format when loading config", true);
}
} catch (error) {
showStatusMessage("Error loading configuration: " + error.message, true);
console.error("Error loading configuration:", error);
} finally {
// Reset file input to allow selecting the same file again
e.target.value = '';
}
});
// Refresh browser view
refreshBrowserBtn.addEventListener('click', async () => {
if (agentRunning) {
showStatusMessage("Refreshing browser view...");
// Simulate getting fresh browser view
browserView.innerHTML = `<iframe src='https://google.com/search?q=${new Date().getTime()}' width='100%' height='100%'></iframe>`;
showStatusMessage("Browser view refreshed");
} else {
showStatusMessage("No active agent to refresh", true);
}
});
// Refresh recordings list
refreshRecordingsBtn.addEventListener('click', async () => {
try {
showStatusMessage("Refreshing recordings list...");
const result = await client.predict('/list_recordings', {
save_recording_path: document.getElementById('save_recording_path').value
});
if (result.data && result.data[0]) {
// In a real app, you would render the recordings
showStatusMessage("Recordings list refreshed");
}
} catch (error) {
showStatusMessage("Error refreshing recordings: " + error.message, true);
console.error("Error refreshing recordings:", error);
}
});
// Open recordings folder
openRecordingsFolderBtn.addEventListener('click', () => {
showStatusMessage("Opening recordings folder (simulated)");
// In a real app, this would open the system file explorer
});
// Download research report
downloadReportBtn.addEventListener('click', () => {
showStatusMessage("Downloading research report (simulated)");
// In a real app, this would initiate a file download
});
// Tab switching logic
agentTabBtn.addEventListener('click', () => {
agentTabBtn.classList.add('tab-indicator');
browserTabBtn.classList.remove('tab-indicator');
researchTabBtn.classList.remove('tab-indicator');
agentTabBtn.classList.remove('text-gray-500', 'hover:text-gray-700');
browserTabBtn.classList.add('text-gray-500', 'hover:text-gray-700');
researchTabBtn.classList.add('text-gray-500', 'hover:text-gray-700');
agentTab.classList.remove('hidden');
browserTab.classList.add('hidden');
researchTab.classList.add('hidden');
});
browserTabBtn.addEventListener('click', () => {
browserTabBtn.classList.add('tab-indicator');
agentTabBtn.classList.remove('tab-indicator');
researchTabBtn.classList.remove('tab-indicator');
browserTabBtn.classList.remove('text-gray-500', 'hover:text-gray-700');
agentTabBtn.classList.add('text-gray-500', 'hover:text-gray-700');
researchTabBtn.classList.add('text-gray-500', 'hover:text-gray-700');
browserTab.classList.remove('hidden');
agentTab.classList.add('hidden');
researchTab.classList.add('hidden');
});
researchTabBtn.addEventListener('click', () => {
researchTabBtn.classList.add('tab-indicator');
agentTabBtn.classList.remove('tab-indicator');
browserTabBtn.classList.remove('tab-indicator');
researchTabBtn.classList.remove('text-gray-500', 'hover:text-gray-700');
agentTabBtn.classList.add('text-gray-500', 'hover:text-gray-700');
browserTabBtn.classList.add('text-gray-500', 'hover:text-gray-700');
researchTab.classList.remove('hidden');
agentTab.classList.add('hidden');
browserTab.classList.add('hidden');
});
outputTabBtn.addEventListener('click', () => {
outputTabBtn.classList.add('tab-indicator');
recordingsTabBtn.classList.remove('tab-indicator');
researchOutputTabBtn.classList.remove('tab-indicator');
outputTabBtn.classList.remove('text-gray-500', 'hover:text-gray-700');
recordingsTabBtn.classList.add('text-gray-500', 'hover:text-gray-700');
researchOutputTabBtn.classList.add('text-gray-500', 'hover:text-gray-700');
outputTab.classList.remove('hidden');
recordingsTab.classList.add('hidden');
researchOutputTab.classList.add('hidden');
});
recordingsTabBtn.addEventListener('click', () => {
recordingsTabBtn.classList.add('tab-indicator');
outputTabBtn.classList.remove('tab-indicator');
researchOutputTabBtn.classList.remove('tab-indicator');
recordingsTabBtn.classList.remove('text-gray-500', 'hover:text-gray-700');
outputTabBtn.classList.add('text-gray-500', 'hover:text-gray-700');
researchOutputTabBtn.classList.add('text-gray-500', 'hover:text-gray-700');
recordingsTab.classList.remove('hidden');
outputTab.classList.add('hidden');
researchOutputTab.classList.add('hidden');
});
researchOutputTabBtn.addEventListener('click', () => {
researchOutputTabBtn.classList.add('tab-indicator');
outputTabBtn.classList.remove('tab-indicator');
recordingsTabBtn.classList.remove('tab-indicator');
researchOutputTabBtn.classList.remove('text-gray-500', 'hover:text-gray-700');
outputTabBtn.classList.add('text-gray-500', 'hover:text-gray-700');
recordingsTabBtn.classList.add('text-gray-500', 'hover:text-gray-700');
researchOutputTab.classList.remove('hidden');
outputTab.classList.add('hidden');
recordingsTab.classList.add('hidden');
});
// Initialize the application
document.addEventListener('DOMContentLoaded', () => {
// Initialize client connection
initClient();
// Update slider value displays
updateSliderValues();
// Set up event listeners for sliders to update their value displays
llmNumCtx.addEventListener('input', updateSliderValues);
llmTemperature.addEventListener('input', updateSliderValues);
maxSteps.addEventListener('input', updateSliderValues);
maxActionsPerStep.addEventListener('input', updateSliderValues);
// Set up time display
updateTime();
setInterval(updateTime, 1000);
// Disable stop buttons initially
stopAgentBtn.disabled = true;
stopResearchBtn.disabled = true;
// Initialize tooltips (data-tooltip attribute)
document.querySelectorAll('[data-tooltip]').forEach(el => {
el.addEventListener('mouseenter', () => {
// Tooltip is shown via CSS
});
});
// Initialize tabs
agentTabBtn.click();
outputTabBtn.click();
// Set up gradient animation for header
let hue = 0;
gradientInterval = setInterval(() => {
hue = (hue + 0.5) % 360;
document.querySelector('header').style.backgroundImage = `linear-gradient(135deg, hsl(${hue}, 86%, 68%) 0%, hsl(${(hue + 60) % 360}, 86%, 68%) 50%, hsl(${(hue + 120) % 360}, 86%, 68%) 100%)`;
}, 100);
});
// Clean up when page is unloaded
window.addEventListener('beforeunload', () => {
if (gradientInterval) {
clearInterval(gradientInterval);
}
// In a real app, you'd also stop any running agents
if (agentRunning || researchRunning) {
return "There are agents running. Are you sure you want to leave?";
}
});
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=kamioll999/cmd" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>