Spaces:
Running
Running
A production-ready **PWA** (installable, offline-capable) that runs on Android and desktop.
2ac1520 verified | <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Bytebot - Autonomous AI OS</title> | |
| <meta name="theme-color" content="#2563eb"> | |
| <meta name="description" content="Bytebot - Your autonomous AI operating system"> | |
| <link rel="manifest" href="/manifest.json"> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="https://unpkg.com/feather-icons"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script> | |
| <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet"> | |
| <link href="https://unpkg.com/aos@2.3.1/dist/aos.css" rel="stylesheet"> | |
| <script src="https://unpkg.com/aos@2.3.1/dist/aos.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.globe.min.js"></script> | |
| <style> | |
| :root { | |
| --primary: #2563eb; | |
| --primary-light: #3b82f6; | |
| --secondary: #10b981; | |
| --background: #f8fafc; | |
| --card: #ffffff; | |
| --text: #0f172a; | |
| --text-light: #64748b; | |
| } | |
| body { | |
| font-family: 'Inter', sans-serif; | |
| background-color: var(--background); | |
| color: var(--text); | |
| overflow-x: hidden; | |
| } | |
| .glass-card { | |
| background: rgba(255, 255, 255, 0.85); | |
| backdrop-filter: blur(12px); | |
| -webkit-backdrop-filter: blur(12px); | |
| border-radius: 12px; | |
| border: 1px solid rgba(255, 255, 255, 0.2); | |
| box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05); | |
| } | |
| .neumorphic { | |
| box-shadow: 8px 8px 16px #e2e8f0, -8px -8px 16px #ffffff; | |
| } | |
| .hover-pop { | |
| transition: transform 0.2s ease, box-shadow 0.2s ease; | |
| } | |
| .hover-pop:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1); | |
| } | |
| .progress-ring { | |
| transition: stroke-dashoffset 0.5s ease; | |
| transform: rotate(-90deg); | |
| transform-origin: 50% 50%; | |
| } | |
| @keyframes pulse { | |
| 0%, 100% { | |
| opacity: 1; | |
| } | |
| 50% { | |
| opacity: 0.5; | |
| } | |
| } | |
| .pulse-animation { | |
| animation: pulse 2s infinite; | |
| } | |
| #vanta-bg { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| z-index: -1; | |
| opacity: 0.1; | |
| } | |
| .message-enter { | |
| animation: fadeInUp 0.3s ease-out; | |
| } | |
| @keyframes fadeInUp { | |
| from { | |
| opacity: 0; | |
| transform: translateY(10px); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateY(0); | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body class="min-h-screen"> | |
| <div id="vanta-bg"></div> | |
| <!-- Main App Container --> | |
| <div class="container mx-auto px-4 py-6 max-w-7xl"> | |
| <!-- Header --> | |
| <header class="flex justify-between items-center mb-8"> | |
| <div class="flex items-center space-x-3"> | |
| <div class="w-10 h-10 rounded-full bg-gradient-to-br from-blue-500 to-green-400 flex items-center justify-center shadow-lg"> | |
| <i data-feather="cpu" class="text-white w-5 h-5"></i> | |
| </div> | |
| <h1 class="text-2xl font-bold text-gray-800">Bytebot</h1> | |
| <span class="px-3 py-1 text-xs font-medium rounded-full bg-blue-100 text-blue-800 flex items-center space-x-1"> | |
| <span class="w-2 h-2 rounded-full bg-blue-500 pulse-animation"></span> | |
| <span>Active</span> | |
| </span> | |
| </div> | |
| <div class="flex space-x-4"> | |
| <button id="mic-btn" class="p-2 rounded-full bg-white shadow-md hover-pop"> | |
| <i data-feather="mic" class="w-5 h-5 text-gray-600"></i> | |
| </button> | |
| <button id="settings-btn" class="p-2 rounded-full bg-white shadow-md hover-pop"> | |
| <i data-feather="settings" class="w-5 h-5 text-gray-600"></i> | |
| </button> | |
| </div> | |
| </header> | |
| <!-- Main Content Area --> | |
| <div class="grid grid-cols-1 lg:grid-cols-3 gap-6"> | |
| <!-- Left Sidebar - Task Progress --> | |
| <div class="lg:col-span-1 space-y-6"> | |
| <!-- System Status --> | |
| <div class="glass-card p-5 hover-pop"> | |
| <h2 class="text-lg font-semibold mb-4 flex items-center"> | |
| <i data-feather="activity" class="w-5 h-5 mr-2 text-blue-500"></i> | |
| System Status | |
| </h2> | |
| <div class="space-y-4"> | |
| <div class="flex justify-between items-center"> | |
| <span class="text-sm text-gray-600">CPU Usage</span> | |
| <div> | |
| <svg class="w-12 h-12" viewBox="0 0 36 36"> | |
| <path class="text-gray-200" d="M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831" fill="none" stroke="currentColor" stroke-width="3" stroke-dasharray="88, 100" stroke-linecap="round"/> | |
| <path class="text-blue-500 progress-ring" d="M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831" fill="none" stroke="currentColor" stroke-width="3" stroke-dasharray="30, 100" stroke-linecap="round"/> | |
| <text x="18" y="20.5" font-size="8" text-anchor="middle" fill="currentColor" class="text-blue-500 font-medium">30%</text> | |
| </svg> | |
| </div> | |
| </div> | |
| <div class="flex justify-between items-center"> | |
| <span class="text-sm text-gray-600">Memory</span> | |
| <div> | |
| <svg class="w-12 h-12" viewBox="0 0 36 36"> | |
| <path class="text-gray-200" d="M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831" fill="none" stroke="currentColor" stroke-width="3" stroke-dasharray="88, 100" stroke-linecap="round"/> | |
| <path class="text-green-500 progress-ring" d="M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831" fill="none" stroke="currentColor" stroke-width="3" stroke-dasharray="65, 100" stroke-linecap="round"/> | |
| <text x="18" y="20.5" font-size="8" text-anchor="middle" fill="currentColor" class="text-green-500 font-medium">65%</text> | |
| </svg> | |
| </div> | |
| </div> | |
| <div class="flex justify-between items-center"> | |
| <span class="text-sm text-gray-600">Network</span> | |
| <div> | |
| <svg class="w-12 h-12" viewBox="0 0 36 36"> | |
| <path class="text-gray-200" d="M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831" fill="none" stroke="currentColor" stroke-width="3" stroke-dasharray="88, 100" stroke-linecap="round"/> | |
| <path class="text-purple-500 progress-ring" d="M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831" fill="none" stroke="currentColor" stroke-width="3" stroke-dasharray="85, 100" stroke-linecap="round"/> | |
| <text x="18" y="20.5" font-size="8" text-anchor="middle" fill="currentColor" class="text-purple-500 font-medium">85%</text> | |
| </svg> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Active Tasks --> | |
| <div class="glass-card p-5 hover-pop"> | |
| <h2 class="text-lg font-semibold mb-4 flex items-center"> | |
| <i data-feather="list" class="w-5 h-5 mr-2 text-blue-500"></i> | |
| Active Tasks | |
| </h2> | |
| <div class="space-y-3"> | |
| <div class="flex items-start space-x-3"> | |
| <div class="w-2 h-2 mt-2 rounded-full bg-blue-500 animate-pulse"></div> | |
| <div class="flex-1"> | |
| <h3 class="text-sm font-medium">Processing voice command</h3> | |
| <p class="text-xs text-gray-500">"Set a timer for 10 minutes"</p> | |
| <div class="w-full bg-gray-200 rounded-full h-1.5 mt-2"> | |
| <div class="bg-blue-500 h-1.5 rounded-full" style="width: 45%"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="flex items-start space-x-3"> | |
| <div class="w-2 h-2 mt-2 rounded-full bg-green-500"></div> | |
| <div class="flex-1"> | |
| <h3 class="text-sm font-medium">Web search</h3> | |
| <p class="text-xs text-gray-500">"Latest AI research papers"</p> | |
| <div class="w-full bg-gray-200 rounded-full h-1.5 mt-2"> | |
| <div class="bg-green-500 h-1.5 rounded-full" style="width: 85%"></div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Memory Summary --> | |
| <div class="glass-card p-5 hover-pop"> | |
| <h2 class="text-lg font-semibold mb-4 flex items-center"> | |
| <i data-feather="database" class="w-5 h-5 mr-2 text-blue-500"></i> | |
| Memory | |
| </h2> | |
| <div class="flex justify-between items-center mb-2"> | |
| <span class="text-sm text-gray-600">4.2 MB used</span> | |
| <span class="text-xs text-gray-500">of 10 MB</span> | |
| </div> | |
| <div class="w-full bg-gray-200 rounded-full h-2"> | |
| <div class="bg-yellow-500 h-2 rounded-full" style="width: 42%"></div> | |
| </div> | |
| <div class="flex justify-between items-center mt-4"> | |
| <button class="text-xs text-blue-500 hover:text-blue-700 flex items-center"> | |
| <i data-feather="search" class="w-3 h-3 mr-1"></i> | |
| Search | |
| </button> | |
| <button class="text-xs text-blue-500 hover:text-blue-700 flex items-center"> | |
| <i data-feather="edit" class="w-3 h-3 mr-1"></i> | |
| Manage | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Chat Interface --> | |
| <div class="lg:col-span-2"> | |
| <div class="glass-card p-5 hover-pop h-full flex flex-col"> | |
| <div class="flex border-b pb-3 mb-4"> | |
| <button class="px-4 py-2 text-sm font-medium text-blue-500 border-b-2 border-blue-500"> | |
| Chat | |
| </button> | |
| <button class="px-4 py-2 text-sm font-medium text-gray-500 hover:text-blue-500"> | |
| Dashboard | |
| </button> | |
| <button class="px-4 py-2 text-sm font-medium text-gray-500 hover:text-blue-500"> | |
| Logs | |
| </button> | |
| <button class="px-4 py-2 text-sm font-medium text-gray-500 hover:text-blue-500"> | |
| Skills | |
| </button> | |
| </div> | |
| <!-- Chat Messages --> | |
| <div id="chat-messages" class="flex-1 overflow-y-auto mb-4 space-y-4 max-h-[400px]"> | |
| <div class="message-enter flex items-start space-x-3"> | |
| <div class="flex-shrink-0 w-8 h-8 rounded-full bg-blue-100 flex items-center justify-center"> | |
| <i data-feather="user" class="w-4 h-4 text-blue-500"></i> | |
| </div> | |
| <div class="bg-white p-3 rounded-lg shadow-sm max-w-[85%]"> | |
| <p class="text-sm">Hey Bytebot, can you help me summarize this article?</p> | |
| </div> | |
| </div> | |
| <div class="message-enter flex items-start space-x-3"> | |
| <div class="flex-shrink-0 w-8 h-8 rounded-full bg-green-100 flex items-center justify-center"> | |
| <i data-feather="cpu" class="w-4 h-4 text-green-500"></i> | |
| </div> | |
| <div class="bg-green-50 p-3 rounded-lg shadow-sm max-w-[85%]"> | |
| <p class="text-sm">Of course! I'll analyze the article and extract the key points. Please share the article URL or text with me.</p> | |
| <div class="mt-2 border-t pt-2 flex items-center justify-between"> | |
| <span class="text-xs text-gray-500">Task ID: BOT-487</span> | |
| <span class="text-xs px-2 py-1 rounded-full bg-green-100 text-green-800">Parsing</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Task Plan Visualization --> | |
| <div class="bg-blue-50 p-4 rounded-lg mb-4" data-aos="fade-up"> | |
| <h3 class="text-sm font-medium text-blue-800 mb-2 flex items-center"> | |
| <i data-feather="layers" class="w-4 h-4 mr-2"></i> | |
| Task Plan | |
| </h3> | |
| <div class="flex items-center space-x-4 text-xs"> | |
| <div class="flex flex-col items-center"> | |
| <div class="w-8 h-8 rounded-full bg-blue-500 flex items-center justify-center text-white font-medium">1</div> | |
| <span class="mt-1">Plan</span> | |
| </div> | |
| <div class="flex-1 h-1 bg-blue-300 rounded-full"></div> | |
| <div class="flex flex-col items-center"> | |
| <div class="w-8 h-8 rounded-full bg-blue-500 flex items-center justify-center text-white font-medium">2</div> | |
| <span class="mt-1">Execute</span> | |
| </div> | |
| <div class="flex-1 h-1 bg-blue-200 rounded-full"></div> | |
| <div class="flex flex-col items-center"> | |
| <div class="w-8 h-8 rounded-full bg-blue-200 flex items-center justify-center text-white font-medium">3</div> | |
| <span class="mt-1">Confirm</span> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Input Area --> | |
| <div class="mt-auto"> | |
| <div class="flex items-center bg-white rounded-lg shadow-sm border overflow-hidden"> | |
| <input type="text" id="chat-input" placeholder="Type or say 'Hey Bytebot'..." class="flex-1 px-4 py-3 focus:outline-none" autocomplete="off"> | |
| <button id="send-btn" class="px-4 py-3 bg-blue-500 text-white"> | |
| <i data-feather="send" class="w-5 h-5"></i> | |
| </button> | |
| </div> | |
| <div id="voice-feedback" class="hidden mt-2 p-2 bg-blue-50 rounded-lg flex items-center space-x-2"> | |
| <span class="w-2 h-2 rounded-full bg-blue-500 animate-pulse"></span> | |
| <span class="text-sm text-blue-800">Listening...</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Floating Status Widget --> | |
| <div class="fixed bottom-6 right-6"> | |
| <div class="glass-card p-3 rounded-full shadow-xl hover-pop group"> | |
| <div class="w-12 h-12 rounded-full bg-gradient-to-br from-blue-500 to-green-400 flex items-center justify-center relative"> | |
| <i data-feather="cpu" class="text-white w-5 h-5"></i> | |
| <span class="absolute -top-1 -right-1 w-4 h-4 rounded-full bg-green-400 border-2 border-white"></span> | |
| </div> | |
| <div class="absolute bottom-full right-0 mb-2 w-64 p-3 bg-white rounded-lg shadow-lg hidden group-hover:block"> | |
| <div class="text-sm font-medium text-gray-900">System Status</div> | |
| <div class="mt-1 text-xs text-gray-500">3 tasks running, 68% memory free</div> | |
| <div class="mt-2 flex justify-between text-xs"> | |
| <span class="text-gray-500">Network:</span> | |
| <span class="text-green-500">Connected</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Settings Modal (hidden by default) --> | |
| <div id="settings-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden"> | |
| <div class="glass-card w-full max-w-2xl p-6 rounded-lg"> | |
| <div class="flex justify-between items-center mb-4"> | |
| <h3 class="text-xl font-semibold">Settings</h3> | |
| <button id="close-settings" class="text-gray-500 hover:text-gray-700"> | |
| <i data-feather="x" class="w-6 h-6"></i> | |
| </button> | |
| </div> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-6"> | |
| <div> | |
| <h4 class="text-sm font-medium mb-3 text-gray-700">Voice Settings</h4> | |
| <div class="space-y-3"> | |
| <div> | |
| <label class="flex items-center cursor-pointer"> | |
| <div class="relative"> | |
| <input type="checkbox" class="sr-only" checked> | |
| <div class="block bg-gray-300 w-10 h-6 rounded-full"></div> | |
| <div class="dot absolute left-1 top-1 bg-white w-4 h-4 rounded-full transition"></div> | |
| </div> | |
| <div class="ml-3 text-sm text-gray-700">Wake word "Hey Bytebot"</div> | |
| </label> | |
| </div> | |
| <div> | |
| <label class="text-xs text-gray-700">Voice Speed</label> | |
| <input type="range" min="0.5" max="1.5" step="0.1" value="1.0" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer"> | |
| </div> | |
| </div> | |
| </div> | |
| <div> | |
| <h4 class="text-sm font-medium mb-3 text-gray-700">Memory Settings</h4> | |
| <div class="space-y-3"> | |
| <button class="w-full text-left py-2 px-3 bg-red-50 text-red-600 rounded text-sm flex items-center justify-between"> | |
| Clear all memory | |
| <i data-feather="trash-2" class="w-4 h-4"></i> | |
| </button> | |
| <label class="flex items-center cursor-pointer"> | |
| <div class="relative"> | |
| <input type="checkbox" class="sr-only"> | |
| <div class="block bg-gray-300 w-10 h-6 rounded-full"></div> | |
| <div class="dot absolute left-1 top-1 bg-white w-4 h-4 rounded-full transition"></div> | |
| </div> | |
| <div class="ml-3 text-sm text-gray-700">Enable PIN protection</div> | |
| </label> | |
| </div> | |
| </div> | |
| <div> | |
| <h4 class="text-sm font-medium mb-3 text-gray-700">Appearance</h4> | |
| <div class="grid grid-cols-3 gap-2"> | |
| <button class="py-2 px-3 rounded border border-gray-300 text-sm"> | |
| Light | |
| </button> | |
| <button class="py-2 px-3 rounded border border-gray-300 bg-gray-800 text-white text-sm"> | |
| Dark | |
| </button> | |
| <button class="py-2 px-3 rounded border border-blue-500 bg-blue-50 text-blue-700 text-sm"> | |
| System | |
| </button> | |
| </div> | |
| </div> | |
| <div> | |
| <h4 class="text-sm font-medium mb-3 text-gray-700">Developer Mode</h4> | |
| <div class="space-y-3"> | |
| <label class="flex items-center cursor-pointer"> | |
| <div class="relative"> | |
| <input type="checkbox" class="sr-only"> | |
| <div class="block bg-gray-300 w-10 h-6 rounded-full"></div> | |
| <div class="dot absolute left-1 top-1 bg-white w-4 h-4 rounded-full transition"></div> | |
| </div> | |
| <div class="ml-3 text-sm text-gray-700">Show raw LLM I/O</div> | |
| </label> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Load new JS modules --> | |
| <script type="module"> | |
| import { sendToAI, getAIConfig } from '/src/ai/aiClient.js'; | |
| // Initialize Vanta.js background | |
| VANTA.GLOBE({ | |
| el: "#vanta-bg", | |
| mouseControls: true, | |
| touchControls: true, | |
| gyroControls: false, | |
| minHeight: 200.00, | |
| minWidth: 200.00, | |
| scale: 1.00, | |
| scaleMobile: 1.00, | |
| color: 0x3b82f6, | |
| size: 0.8 | |
| }); | |
| // Initialize AOS animations | |
| AOS.init({ | |
| duration: 600, | |
| easing: 'ease-in-out', | |
| once: true | |
| }); | |
| // Initialize Feather Icons | |
| document.addEventListener('DOMContentLoaded', function() { | |
| feather.replace(); | |
| // Simulate the app as a PWA | |
| if ('serviceWorker' in navigator) { | |
| window.addEventListener('load', () => { | |
| navigator.serviceWorker.register('/sw.js').then(registration => { | |
| console.log('ServiceWorker registration successful'); | |
| }, err => { | |
| console.log('ServiceWorker registration failed: ', err); | |
| }); | |
| }); | |
| } | |
| // Modal toggle functionality | |
| const settingsBtn = document.getElementById('settings-btn'); | |
| const closeSettings = document.getElementById('close-settings'); | |
| const settingsModal = document.getElementById('settings-modal'); | |
| settingsBtn.addEventListener('click', () => { | |
| settingsModal.classList.remove('hidden'); | |
| }); | |
| closeSettings.addEventListener('click', () => { | |
| settingsModal.classList.add('hidden'); | |
| }); | |
| // Voice recognition simulation | |
| const micBtn = document.getElementById('mic-btn'); | |
| const voiceFeedback = document.getElementById('voice-feedback'); | |
| let isListening = false; | |
| micBtn.addEventListener('click', () => { | |
| isListening = !isListening; | |
| if (isListening) { | |
| micBtn.classList.add('bg-blue-500', 'text-white'); | |
| micBtn.classList.remove('bg-white', 'text-gray-600'); | |
| voiceFeedback.classList.remove('hidden'); | |
| // In a real app, we would initialize the Web Speech API here | |
| } else { | |
| micBtn.classList.remove('bg-blue-500', 'text-white'); | |
| micBtn.classList.add('bg-white', 'text-gray-600'); | |
| voiceFeedback.classList.add('hidden'); | |
| } | |
| }); | |
| // Chat input functionality | |
| const chatInput = document.getElementById('chat-input'); | |
| const sendBtn = document.getElementById('send-btn'); | |
| const chatMessages = document.getElementById('chat-messages'); | |
| function addUserMessage(text) { | |
| const messageDiv = document.createElement('div'); | |
| messageDiv.className = 'message-enter flex items-start space-x-3'; | |
| messageDiv.innerHTML = ` | |
| <div class="flex-shrink-0 w-8 h-8 rounded-full bg-blue-100 flex items-center justify-center"> | |
| <i data-feather="user" class="w-4 h-4 text-blue-500"></i> | |
| </div> | |
| <div class="bg-white p-3 rounded-lg shadow-sm max-w-[85%]"> | |
| <p class="text-sm">${text}</p> | |
| </div> | |
| `; | |
| chatMessages.appendChild(messageDiv); | |
| chatMessages.scrollTop = chatMessages.scrollHeight; | |
| } | |
| function addBotMessage(text, status = 'Completed') { | |
| const messageDiv = document.createElement('div'); | |
| messageDiv.className = 'message-enter flex items-start space-x-3'; | |
| messageDiv.innerHTML = ` | |
| <div class="flex-shrink-0 w-8 h-8 rounded-full bg-green-100 flex items-center justify-center"> | |
| <i data-feather="cpu" class="w-4 h-4 text-green-500"></i> | |
| </div> | |
| <div class="bg-green-50 p-3 rounded-lg shadow-sm max-w-[85%]"> | |
| <p class="text-sm">${text}</p> | |
| <div class="mt-2 border-t pt-2 flex items-center justify-between"> | |
| <span class="text-xs text-gray-500">Task ID: BOT-${Math.floor(100 + Math.random() * 900)}</span> | |
| <span class="text-xs px-2 py-1 rounded-full bg-green-100 text-green-800">${status}</span> | |
| </div> | |
| </div> | |
| `; | |
| chatMessages.appendChild(messageDiv); | |
| chatMessages.scrollTop = chatMessages.scrollHeight; | |
| feather.replace(); | |
| } | |
| async function handleSendMessage() { | |
| const text = chatInput.value.trim(); | |
| if (text) { | |
| addUserMessage(text); | |
| chatInput.value = ''; | |
| // Add "thinking" indicator | |
| const thinkingMsg = addBotMessage("Processing...", "Thinking"); | |
| try { | |
| // Get current AI config and send message | |
| const config = getAIConfig(); | |
| const messages = [{ | |
| role: "user", | |
| content: text | |
| }]; | |
| const response = await sendToAI(messages, config); | |
| // Replace thinking message with actual response | |
| thinkingMsg.querySelector('p').textContent = response; | |
| updateMessageStatus(thinkingMsg, "Completed"); | |
| } catch (error) { | |
| thinkingMsg.querySelector('p').textContent = `Error: ${error.message}`; | |
| updateMessageStatus(thinkingMsg, "Failed"); | |
| } | |
| } | |
| } | |
| function updateMessageStatus(messageElement, status) { | |
| const statusElement = messageElement.querySelector('.flex.items-center.justify-between span:last-child'); | |
| if (statusElement) { | |
| statusElement.textContent = status; | |
| statusElement.className = `text-xs px-2 py-1 rounded-full ${ | |
| status === "Completed" ? "bg-green-100 text-green-800" : | |
| status === "Failed" ? "bg-red-100 text-red-800" : | |
| "bg-blue-100 text-blue-800" | |
| }`; | |
| } | |
| } | |
| sendBtn.addEventListener('click', handleSendMessage); | |
| chatInput.addEventListener('keypress', function(e) { | |
| if (e.key === 'Enter') { | |
| handleSendMessage(); | |
| } | |
| }); | |
| // Simulate initial message | |
| setTimeout(() => { | |
| addBotMessage("Hello! I'm Bytebot, your autonomous AI assistant. How can I help you today?"); | |
| }, 1000); | |
| }); | |
| </script> | |
| <!-- Add AI Settings section --> | |
| <template id="ai-settings-template"> | |
| <div class="p-4"> | |
| <h3 class="text-lg font-medium mb-4">AI Configuration</h3> | |
| <div class="space-y-4"> | |
| <div> | |
| <label class="block text-sm font-medium mb-1">Backend</label> | |
| <select id="ai-backend" class="w-full border rounded px-3 py-2"> | |
| <option value="provider">Cloud Provider (OpenAI)</option> | |
| <option value="local">Local LLM</option> | |
| <option value="bytebot-lambda">Bytebot Lambda</option> | |
| </select> | |
| </div> | |
| <div id="provider-token-group"> | |
| <label class="block text-sm font-medium mb-1">API Key</label> | |
| <input id="ai-token" type="password" class="w-full border rounded px-3 py-2" placeholder="sk-..."> | |
| </div> | |
| <div id="local-endpoint-group" class="hidden"> | |
| <label class="block text-sm font-medium mb-1">Local Endpoint</label> | |
| <input id="local-endpoint" type="url" class="w-full border rounded px-3 py-2" placeholder="http://localhost:11434"> | |
| </div> | |
| <button id="save-ai-config" class="w-full bg-blue-500 text-white py-2 rounded">Save Configuration</button> | |
| </div> | |
| </div> | |
| </template> | |
| </body> | |
| </html> | |