Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>DevOps AI Assistant</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link href="https://cdn.jsdelivr.net/npm/[email protected]/fonts/remixicon.css" rel="stylesheet"/> | |
| <style> | |
| .model-card:hover { | |
| transform: translateY(-5px); | |
| box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1); | |
| } | |
| .terminal { | |
| background-color: #1e1e1e; | |
| font-family: 'Courier New', monospace; | |
| border-radius: 0.375rem; | |
| color: #e0e0e0; | |
| } | |
| .prompt { | |
| color: #4ade80; | |
| font-weight: bold; | |
| } | |
| .user { | |
| color: #60a5fa; | |
| } | |
| .ai { | |
| color: #f59e0b; | |
| } | |
| .cursor { | |
| animation: blink 1s infinite; | |
| } | |
| @keyframes blink { | |
| 0%, 100% { opacity: 1; } | |
| 50% { opacity: 0; } | |
| } | |
| .sidebar { | |
| transition: all 0.3s ease; | |
| } | |
| .sidebar.collapsed { | |
| width: 70px; | |
| } | |
| .sidebar.collapsed .sidebar-text { | |
| display: none; | |
| } | |
| .sidebar.collapsed .sidebar-icon { | |
| margin-right: 0; | |
| } | |
| .progress-bar { | |
| transition: width 0.3s ease; | |
| } | |
| @keyframes spin { | |
| 0% { transform: rotate(0deg); } | |
| 100% { transform: rotate(360deg); } | |
| } | |
| .animate-spin { | |
| animation: spin 1s linear infinite; | |
| } | |
| #model-upload::-webkit-file-upload-button { | |
| visibility: hidden; | |
| } | |
| #model-upload::before { | |
| content: 'Select GGUF File'; | |
| display: inline-block; | |
| background: linear-gradient(to bottom, #f9f9f9, #e3e3e3); | |
| border: 1px solid #999; | |
| border-radius: 3px; | |
| padding: 5px 8px; | |
| outline: none; | |
| white-space: nowrap; | |
| cursor: pointer; | |
| text-shadow: 1px 1px #fff; | |
| font-weight: 700; | |
| font-size: 10pt; | |
| } | |
| #model-upload:hover::before { | |
| border-color: black; | |
| } | |
| #model-upload:active::before { | |
| background: linear-gradient(to bottom, #e3e3e3, #f9f9f9); | |
| } | |
| .dark-mode { | |
| background-color: #1a202c; | |
| color: #e2e8f0; | |
| } | |
| .dark-mode .sidebar { | |
| background-color: #2d3748; | |
| border-color: #4a5568; | |
| } | |
| .dark-mode .terminal { | |
| background-color: #111827; | |
| } | |
| .dark-mode .bg-white { | |
| background-color: #2d3748 ; | |
| color: #e2e8f0; | |
| } | |
| .dark-mode .text-gray-800 { | |
| color: #e2e8f0 ; | |
| } | |
| .dark-mode .text-gray-700 { | |
| color: #cbd5e0 ; | |
| } | |
| .dark-mode .text-gray-500 { | |
| color: #a0aec0 ; | |
| } | |
| .dark-mode .border-gray-200 { | |
| border-color: #4a5568 ; | |
| } | |
| .dark-mode .bg-gray-50 { | |
| background-color: #4a5568 ; | |
| } | |
| .active-section { | |
| background-color: #eff6ff ; | |
| } | |
| .dark-mode .active-section { | |
| background-color: #3b4d71 ; | |
| color: white ; | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gray-50 text-gray-800"> | |
| <div class="flex h-screen overflow-hidden"> | |
| <!-- Sidebar --> | |
| <div id="sidebar" class="sidebar bg-white w-64 border-r border-gray-200 flex flex-col"> | |
| <div class="p-4 border-b border-gray-200 flex items-center justify-between"> | |
| <div class="flex items-center"> | |
| <i class="ri-cpu-line text-2xl text-blue-600"></i> | |
| <span class="sidebar-text ml-2 font-bold text-xl">DevAI</span> | |
| </div> | |
| <button id="collapse-btn" class="text-gray-500 hover:text-gray-700"> | |
| <i class="ri-arrow-left-s-line"></i> | |
| </button> | |
| </div> | |
| <nav class="flex-1 overflow-y-auto p-2"> | |
| <div class="space-y-1"> | |
| <a href="#" class="active-section flex items-center px-3 py-2 text-sm font-medium rounded-md" data-section="dashboard"> | |
| <i class="ri-dashboard-line sidebar-icon mr-3"></i> | |
| <span class="sidebar-text">Dashboard</span> | |
| </a> | |
| <a href="#" class="flex items-center px-3 py-2 text-sm font-medium rounded-md text-gray-700 hover:bg-gray-100" data-section="github"> | |
| <i class="ri-github-fill sidebar-icon mr-3"></i> | |
| <span class="sidebar-text">GitHub Actions</span> | |
| </a> | |
| <a href="#" class="flex items-center px-3 py-2 text-sm font-medium rounded-md text-gray-700 hover:bg-gray-100" data-section="ai"> | |
| <i class="ri-robot-line sidebar-icon mr-3"></i> | |
| <span class="sidebar-text">AI Assistant</span> | |
| </a> | |
| <a href="#" class="flex items-center px-3 py-2 text-sm font-medium rounded-md text-gray-700 hover:bg-gray-100" data-section="model"> | |
| <i class="ri-brain-line sidebar-icon mr-3"></i> | |
| <span class="sidebar-text">Model Runner</span> | |
| </a> | |
| <a href="#" class="flex items-center px-3 py-2 text-sm font-medium rounded-md text-gray-700 hover:bg-gray-100" data-section="settings"> | |
| <i class="ri-settings-3-line sidebar-icon mr-3"></i> | |
| <span class="sidebar-text">Settings</span> | |
| </a> | |
| </div> | |
| </nav> | |
| <div class="p-4 border-t border-gray-200"> | |
| <div class="flex items-center"> | |
| <div class="h-10 w-10 rounded-full bg-blue-100 flex items-center justify-center"> | |
| <i class="ri-user-line text-blue-600"></i> | |
| </div> | |
| <div class="ml-3 sidebar-text"> | |
| <p class="text-sm font-medium">DevOps User</p> | |
| <p class="text-xs text-gray-500">admin</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Main Content --> | |
| <div class="flex-1 overflow-auto"> | |
| <div class="p-6"> | |
| <!-- Dashboard --> | |
| <div id="dashboard"> | |
| <div class="flex justify-between items-center mb-6"> | |
| <h1 class="text-2xl font-bold">DevOps Dashboard</h1> | |
| <div class="flex space-x-2"> | |
| <button class="px-4 py-2 bg-blue-600 text-white rounded-md flex items-center"> | |
| <i class="ri-add-line mr-2"></i> | |
| <span>New Project</span> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-6"> | |
| <div class="bg-white p-6 rounded-lg shadow"> | |
| <div class="flex items-center justify-between"> | |
| <h3 class="text-lg font-medium">GitHub Projects</h3> | |
| <i class="ri-github-fill text-2xl text-gray-700"></i> | |
| </div> | |
| <p class="text-3xl font-bold mt-2" id="github-project-count">42</p> | |
| <div class="mt-4 flex items-center text-sm text-green-600"> | |
| <i class="ri-arrow-up-line mr-1"></i> | |
| <span id="github-project-change">5 new this week</span> | |
| </div> | |
| </div> | |
| <div class="bg-white p-6 rounded-lg shadow"> | |
| <div class="flex items-center justify-between"> | |
| <h3 class="text-lg font-medium">Active Pipelines</h3> | |
| <i class="ri-flow-chart text-2xl text-blue-500"></i> | |
| </div> | |
| <p class="text-3xl font-bold mt-2" id="pipeline-count">18</p> | |
| <div class="mt-4 flex items-center text-sm text-yellow-600"> | |
| <i class="ri-alert-line mr-1"></i> | |
| <span id="pipeline-status">2 warnings</span> | |
| </div> | |
| </div> | |
| <div class="bg-white p-6 rounded-lg shadow"> | |
| <div class="flex items-center justify-between"> | |
| <h3 class="text-lg font-medium">AI Usage</h3> | |
| <i class="ri-robot-line text-2xl text-purple-500"></i> | |
| </div> | |
| <p class="text-3xl font-bold mt-2" id="ai-usage-count">237</p> | |
| <div class="mt-4 flex items-center text-sm text-blue-600"> | |
| <i class="ri-timer-line mr-1"></i> | |
| <span id="ai-usage-time">14.7h total</span> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-white p-6 rounded-lg shadow mb-6"> | |
| <h3 class="text-lg font-medium mb-4">Activity Feed</h3> | |
| <div id="activity-feed" class="space-y-4"> | |
| <div class="flex items-center p-3 border border-gray-200 rounded-lg"> | |
| <div class="bg-green-100 p-2 rounded-full"> | |
| <i class="ri-git-branch-line text-green-600"></i> | |
| </div> | |
| <div class="ml-3"> | |
| <p class="text-sm font-medium">New branch created</p> | |
| <p class="text-xs text-gray-500">feature/api-integration created by user on 10 min ago</p> | |
| </div> | |
| </div> | |
| <div class="flex items-center p-3 border border-gray-200 rounded-lg"> | |
| <div class="bg-blue-100 p-2 rounded-full"> | |
| <i class="ri-play-line text-blue-600"></i> | |
| </div> | |
| <div class="ml-3"> | |
| <p class="text-sm font-medium">Pipeline started</p> | |
| <p class="text-xs text-gray-500">CI/CD for project "analytics-service" started 25 min ago</p> | |
| </div> | |
| </div> | |
| <div class="flex items-center p-3 border border-gray-200 rounded-lg"> | |
| <div class="bg-purple-100 p-2 rounded-full"> | |
| <i class="ri-robot-line text-purple-600"></i> | |
| </div> | |
| <div class="ml-3"> | |
| <p class="text-sm font-medium">AI suggestion used</p> | |
| <p class="text-xs text-gray-500">Optimized deployment config for frontend at 1h ago</p> | |
| </div> | |
| </div> | |
| <div class="flex items-center p-3 border border-gray-200 rounded-lg"> | |
| <div class="bg-yellow-100 p-2 rounded-full"> | |
| <i class="ri-checkbox-circle-line text-yellow-600"></i> | |
| </div> | |
| <div class="ml-3"> | |
| <p class="text-sm font-medium">Test suite passed</p> | |
| <p class="text-xs text-gray-500">All 247 tests passed for pull request #42</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- GitHub Section --> | |
| <div id="github" class="hidden"> | |
| <div class="flex justify-between items-center mb-6"> | |
| <h1 class="text-2xl font-bold">GitHub Integration</h1> | |
| <div class="flex space-x-2"> | |
| <button id="sync-github-btn" class="px-4 py-2 bg-green-600 text-white rounded-md flex items-center"> | |
| <i class="ri-refresh-line mr-2"></i> | |
| <span>Sync Repos</span> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="bg-white p-6 rounded-lg shadow mb-6"> | |
| <h3 class="text-lg font-medium mb-4">Connected Repositories</h3> | |
| <div class="overflow-x-auto"> | |
| <table class="min-w-full divide-y divide-gray-200"> | |
| <thead> | |
| <tr> | |
| <th class="px-6 py-3 bg-gray-50 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Repository</th> | |
| <th class="px-6 py-3 bg-gray-50 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Last Commit</th> | |
| <th class="px-6 py-3 bg-gray-50 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th> | |
| <th class="px-6 py-3 bg-gray-50 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th> | |
| </tr> | |
| </thead> | |
| <tbody id="github-repos" class="bg-white divide-y divide-gray-200"> | |
| <tr> | |
| <td class="px-6 py-4 whitespace-nowrap"> | |
| <div class="flex items-center"> | |
| <i class="ri-book-2-line text-gray-500 mr-2"></i> | |
| <div> | |
| <div class="text-sm font-medium">analytics-service</div> | |
| <div class="text-xs text-gray-500">main branch</div> | |
| </div> | |
| </div> | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap"> | |
| <div class="text-sm">Update database schema</div> | |
| <div class="text-xs text-gray-500">2 hours ago</div> | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap"> | |
| <span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">Active</span> | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> | |
| <button class="text-blue-600 hover:text-blue-900 mr-3">View</button> | |
| <button class="text-indigo-600 hover:text-indigo-900 mr-3">Run CI</button> | |
| <button class="text-gray-600 hover:text-gray-900">Settings</button> | |
| </td> | |
| </tr> | |
| <tr> | |
| <td class="px-6 py-4 whitespace-nowrap"> | |
| <div class="flex items-center"> | |
| <i class="ri-book-2-line text-gray-500 mr-2"></i> | |
| <div> | |
| <div class="text-sm font-medium">user-api</div> | |
| <div class="text-xs text-gray-500">feature/auth branch</div> | |
| </div> | |
| </div> | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap"> | |
| <div class="text-sm">Add JWT support</div> | |
| <div class="text-xs text-gray-500">5 hours ago</div> | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap"> | |
| <span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-yellow-100 text-yellow-800">Pending</span> | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> | |
| <button class="text-blue-600 hover:text-blue-900 mr-3">View</button> | |
| <button class="text-indigo-600 hover:text-indigo-900 mr-3">Run CI</button> | |
| <button class="text-gray-600 hover:text-gray-900">Settings</button> | |
| </td> | |
| </tr> | |
| <tr> | |
| <td class="px-6 py-4 whitespace-nowrap"> | |
| <div class="flex items-center"> | |
| <i class="ri-book-2-line text-gray-500 mr-2"></i> | |
| <div> | |
| <div class="text-sm font-medium">frontend</div> | |
| <div class="text-xs text-gray-500">main branch</div> | |
| </div> | |
| </div> | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap"> | |
| <div class="text-sm">Fix login page styling</div> | |
| <div class="text-xs text-gray-500">1 day ago</div> | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap"> | |
| <span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">Active</span> | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> | |
| <button class="text-blue-600 hover:text-blue-900 mr-3">View</button> | |
| <button class="text-indigo-600 hover:text-indigo-900 mr-3">Run CI</button> | |
| <button class="text-gray-600 hover:text-gray-900">Settings</button> | |
| </td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-6"> | |
| <div class="bg-white p-6 rounded-lg shadow"> | |
| <h3 class="text-lg font-medium mb-4">Workflow Actions</h3> | |
| <div class="space-y-3"> | |
| <button id="create-workflow-btn" class="w-full flex items-center justify-between px-4 py-2 border border-gray-200 rounded-md hover:bg-gray-50"> | |
| <span>Create New Workflow</span> | |
| <i class="ri-arrow-right-line"></i> | |
| </button> | |
| <button id="manage-secrets-btn" class="w-full flex items-center justify-between px-4 py-2 border border-gray-200 rounded-md hover:bg-gray-50"> | |
| <span>Manage Secrets</span> | |
| <i class="ri-arrow-right-line"></i> | |
| </button> | |
| <button id="review-prs-btn" class="w-full flex items-center justify-between px-4 py-2 border border-gray-200 rounded-md hover:bg-gray-50"> | |
| <span>Review Pull Requests</span> | |
| <i class="ri-arrow-right-line"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="bg-white p-6 rounded-lg shadow"> | |
| <h3 class="text-lg font-medium mb-4">Workflow Status</h3> | |
| <div class="space-y-4" id="workflow-stats"> | |
| <div> | |
| <div class="flex justify-between text-sm mb-1"> | |
| <span>CI Pipeline</span> | |
| <span id="ci-pipeline-time">Avg: 4.2 min</span> | |
| </div> | |
| <div class="w-full bg-gray-200 rounded-full h-2.5"> | |
| <div id="ci-pipeline-bar" class="h-2.5 rounded-full bg-blue-600" style="width: 75%"></div> | |
| </div> | |
| </div> | |
| <div> | |
| <div class="flex justify-between text-sm mb-1"> | |
| <span>CD Deployment</span> | |
| <span id="cd-deployment-time">Avg: 1.5 min</span> | |
| </div> | |
| <div class="w-full bg-gray-200 rounded-full h-2.5"> | |
| <div id="cd-deployment-bar" class="h-2.5 rounded-full bg-green-600" style="width: 90%"></div> | |
| </div> | |
| </div> | |
| <div> | |
| <div class="flex justify-between text-sm mb-1"> | |
| <span>Test Coverage</span> | |
| <span id="test-coverage">78%</span> | |
| </div> | |
| <div class="w-full bg-gray-200 rounded-full h-2.5"> | |
| <div id="test-coverage-bar" class="h-2.5 rounded-full bg-purple-600" style="width: 78%"></div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- AI Assistant Section --> | |
| <div id="ai" class="hidden"> | |
| <div class="flex justify-between items-center mb-6"> | |
| <h1 class="text-2xl font-bold" id="ai-model-name">AI Assistant</h1> | |
| <div class="flex space-x-2"> | |
| <button id="test-ai-btn" class="px-4 py-2 bg-purple-600 text-white rounded-md flex items-center"> | |
| <i class="ri-flask-line mr-2"></i> | |
| <span>Test Connection</span> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-6"> | |
| <div class="md:col-span-2 bg-white p-6 rounded-lg shadow"> | |
| <div class="flex justify-between items-center mb-4"> | |
| <h3 class="text-lg font-medium">DevOps Query</h3> | |
| <div class="flex space-x-2"> | |
| <button id="clear-chat-btn" class="p-2 rounded-full bg-gray-100 hover:bg-gray-200"> | |
| <i class="ri-history-line text-gray-600"></i> | |
| </button> | |
| <button id="ai-settings-btn" class="p-2 rounded-full bg-gray-100 hover:bg-gray-200"> | |
| <i class="ri-settings-3-line text-gray-600"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <div id="ai-chat" class="terminal p-4 rounded-lg h-64 overflow-y-auto mb-4"> | |
| <div class="mb-2"> | |
| <span class="prompt">system:</span> | |
| <span class="text-gray-300">AI Assistant is ready. Ask any DevOps-related question.</span> | |
| </div> | |
| <div class="mb-2 hidden" id="ai-thinking"> | |
| <span class="prompt">system:</span> | |
| <span class="text-gray-300"><i class="ri-loader-4-line animate-spin"></i> Thinking...</span> | |
| </div> | |
| </div> | |
| <div class="flex"> | |
| <input id="ai-input" type="text" placeholder="Ask me anything about DevOps..." class="flex-1 px-4 py-2 border border-gray-300 rounded-l-md focus:outline-none focus:ring-2 focus:ring-blue-500"> | |
| <button id="send-ai-query" class="px-4 py-2 bg-blue-600 text-white rounded-r-md hover:bg-blue-700"> | |
| <i class="ri-send-plane-2-line"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="bg-white p-6 rounded-lg shadow"> | |
| <h3 class="text-lg font-medium mb-4">AI Capabilities</h3> | |
| <div class="space-y-3"> | |
| <div class="flex items-start"> | |
| <div class="flex-shrink-0 h-10 w-10 rounded-full bg-blue-100 flex items-center justify-center mt-1 mr-3"> | |
| <i class="ri-code-box-line text-blue-600"></i> | |
| </div> | |
| <div> | |
| <h4 class="font-medium">Code Generation</h4> | |
| <p class="text-sm text-gray-500">Generate pipelines, scripts, and configurations</p> | |
| </div> | |
| </div> | |
| <div class="flex items-start"> | |
| <div class="flex-shrink-0 h-10 w-10 rounded-full bg-green-100 flex items-center justify-center mt-1 mr-3"> | |
| <i class="ri-bug-line text-green-600"></i> | |
| </div> | |
| <div> | |
| <h4 class="font-medium">Troubleshooting</h4> | |
| <p class="text-sm text-gray-500">Diagnose and suggest fixes for common issues</p> | |
| </div> | |
| </div> | |
| <div class="flex items-start"> | |
| <div class="flex-shrink-0 h-10 w-10 rounded-full bg-purple-100 flex items-center justify-center mt-1 mr-3"> | |
| <i class="ri-lightbulb-flash-line text-purple-600"></i> | |
| </div> | |
| <div> | |
| <h4 class="font-medium">Best Practices</h4> | |
| <p class="text-sm text-gray-500">Recommend industry-standard approaches</p> | |
| </div> | |
| </div> | |
| <div class="flex items-start"> | |
| <div class="flex-shrink-0 h-10 w-10 rounded-full bg-yellow-100 flex items-center justify-center mt-1 mr-3"> | |
| <i class="ri-shield-keyhole-line text-yellow-600"></i> | |
| </div> | |
| <div> | |
| <h4 class="font-medium">Security Analysis</h4> | |
| <p class="text-sm text-gray-500">Identify potential vulnerabilities in your setup</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-white p-6 rounded-lg shadow"> | |
| <h3 class="text-lg font-medium mb-4">Recent AI Sessions</h3> | |
| <div class="overflow-x-auto"> | |
| <table class="min-w-full divide-y divide-gray-200"> | |
| <thead> | |
| <tr> | |
| <th class="px-6 py-3 bg-gray-50 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Query</th> | |
| <th class="px-6 py-3 bg-gray-50 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Response Summary</th> | |
| <th class="px-6 py-3 bg-gray-50 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Time</th> | |
| </tr> | |
| </thead> | |
| <tbody id="ai-history" class="bg-white divide-y divide-gray-200"> | |
| <tr> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm"> | |
| How to optimize Dockerfile? | |
| </td> | |
| <td class="px-6 py-4 text-sm"> | |
| <div class="text-xs inline-flex items-center font-bold leading-sm px-3 py-1 bg-green-100 text-green-700 rounded-full"> | |
| <i class="ri-check-line mr-1"></i> Completed | |
| </div> | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500"> | |
| 25 minutes ago | |
| </td> | |
| </tr> | |
| <tr> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm"> | |
| Best practices for Kubernetes security | |
| </td> | |
| <td class="px-6 py-4 text-sm"> | |
| <div class="text-xs inline-flex items-center font-bold leading-sm px-3 py-1 bg-green-100 text-green-700 rounded-full"> | |
| <i class="ri-check-line mr-1"></i> Completed | |
| </div> | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500"> | |
| 3 hours ago | |
| </td> | |
| </tr> | |
| <tr> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm"> | |
| CI/CD pipeline for Python project | |
| </td> | |
| <td class="px-6 py-4 text-sm"> | |
| <div class="text-xs inline-flex items-center font-bold leading-sm px-3 py-1 bg-green-100 text-green-700 rounded-full"> | |
| <i class="ri-check-line mr-1"></i> Completed | |
| </div> | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500"> | |
| Yesterday | |
| </td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Model Runner Section --> | |
| <div id="model" class="hidden"> | |
| <div class="flex justify-between items-center mb-6"> | |
| <h1 class="text-2xl font-bold">Model Runner (GGUF)</h1> | |
| <div class="flex space-x-2"> | |
| <label for="model-upload" class="px-4 py-2 bg-green-600 text-white rounded-md flex items-center cursor-pointer"> | |
| <i class="ri-upload-line mr-2"></i> | |
| <span>Upload Model</span> | |
| </label> | |
| <input type="file" id="model-upload" accept=".gguf" class="hidden"> | |
| <button id="refresh-models-btn" class="px-4 py-2 bg-blue-600 text-white rounded-md flex items-center"> | |
| <i class="ri-refresh-line mr-2"></i> | |
| <span>Refresh</span> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="grid grid-cols-1 md:grid-cols-4 gap-6 mb-6" id="model-cards"> | |
| <div class="model-card bg-white p-4 rounded-lg shadow border border-blue-100"> | |
| <div class="flex items-center mb-2"> | |
| <i class="ri-brain-line text-2xl text-blue-500 mr-2"></i> | |
| <h3 class="text-lg font-medium">Phi-2 2.7B</h3> | |
| </div> | |
| <p class="text-xs text-gray-500 mb-3">Microsoft's lightweight model good for code.</p> | |
| <div class="flex justify-between text-xs text-gray-500 mb-3"> | |
| <span>Size: 1.7GB</span> | |
| <span>Q4_0</span> | |
| </div> | |
| <button class="w-full py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 flex items-center justify-center load-model-btn" data-model="phi-2"> | |
| <i class="ri-play-line mr-1"></i> | |
| <span>Load</span> | |
| </button> | |
| </div> | |
| <div class="model-card bg-white p-4 rounded-lg shadow border border-gray-200"> | |
| <div class="flex items-center mb-2"> | |
| <i class="ri-brain-line text-2xl text-green-500 mr-2"></i> | |
| <h3 class="text-lg font-medium">Mistral 7B</h3> | |
| </div> | |
| <p class="text-xs text-gray-500 mb-3">Excellent balance of size and performance.</p> | |
| <div class="flex justify-between text-xs text-gray-500 mb-3"> | |
| <span>Size: 4.1GB</span> | |
| <span>Q4_K_M</span> | |
| </div> | |
| <button class="w-full py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 flex items-center justify-center load-model-btn" data-model="mistral-7b"> | |
| <i class="ri-play-line mr-1"></i> | |
| <span>Load</span> | |
| </button> | |
| </div> | |
| <div class="model-card bg-white p-4 rounded-lg shadow border border-gray-200"> | |
| <div class="flex items-center mb-2"> | |
| <i class="ri-brain-line text-2xl text-purple-500 mr-2"></i> | |
| <h3 class="text-lg font-medium">Llama 2 13B</h3> | |
| </div> | |
| <p class="text-xs text-gray-500 mb-3">Larger model for more complex tasks.</p> | |
| <div class="flex justify-between text-xs text-gray-500 mb-3"> | |
| <span>Size: 7.3GB</span> | |
| <span>Q4_K_S</span> | |
| </div> | |
| <button class="w-full py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 flex items-center justify-center load-model-btn" data-model="llama2-13b"> | |
| <i class="ri-play-line mr-1"></i> | |
| <span>Load</span> | |
| </button> | |
| </div> | |
| <div class="model-card bg-white p-4 rounded-lg shadow border border-gray-200"> | |
| <div class="flex items-center mb-2"> | |
| <i class="ri-brain-line text-2xl text-red-500 mr-2"></i> | |
| <h3 class="text-lg font-medium">Custom Model</h3> | |
| </div> | |
| <p class="text-xs text-gray-500 mb-3">Upload your own GGUF model file.</p> | |
| <div class="flex justify-between text-xs text-gray-500 mb-3"> | |
| <span>-</span> | |
| <span>-</span> | |
| </div> | |
| <label for="model-upload" class="w-full py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 flex items-center justify-center cursor-pointer"> | |
| <i class="ri-upload-line mr-1"></i> | |
| <span>Upload</span> | |
| </label> | |
| </div> | |
| </div> | |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-6"> | |
| <div class="md:col-span-2 bg-white p-6 rounded-lg shadow"> | |
| <h3 class="text-lg font-medium mb-4">Model Playground</h3> | |
| <div class="terminal p-4 rounded-lg h-96 overflow-y-auto mb-4" id="model-output"> | |
| <div class="mb-2"> | |
| <span class="prompt">system:</span> | |
| <span class="text-gray-300">No model loaded. Select a model from above or upload your own GGUF file.</span> | |
| </div> | |
| <div class="mb-2 hidden" id="model-thinking"> | |
| <span class="prompt">system:</span> | |
| <span class="text-gray-300"><i class="ri-loader-4-line animate-spin"></i> Generating response...</span> | |
| </div> | |
| </div> | |
| <div class="flex"> | |
| <input type="text" id="model-input" placeholder="Type your message..." class="flex-1 px-4 py-2 border border-gray-300 rounded-l-md focus:outline-none focus:ring-2 focus:ring-blue-500"> | |
| <button id="send-model-query" class="px-4 py-2 bg-blue-600 text-white rounded-r-md hover:bg-blue-700" disabled> | |
| <i class="ri-send-plane-2-line"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="bg-white p-6 rounded-lg shadow"> | |
| <h3 class="text-lg font-medium mb-4">Model Parameters</h3> | |
| <div class="space-y-4"> | |
| <div> | |
| <label class="block text-sm font-medium text-gray-700 mb-1">Temperature</label> | |
| <div class="flex items-center"> | |
| <input type="range" id="temperature-slider" min="0" max="2" step="0.1" value="0.7" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer"> | |
| <span id="temperature-value" class="ml-3 text-sm text-gray-500">0.7</span> | |
| </div> | |
| </div> | |
| <div> | |
| <label class="block text-sm font-medium text-gray-700 mb-1">Top P</label> | |
| <div class="flex items-center"> | |
| <input type="range" id="top-p-slider" min="0" max="1" step="0.05" value="0.9" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer"> | |
| <span id="top-p-value" class="ml-3 text-sm text-gray-500">0.9</span> | |
| </div> | |
| </div> | |
| <div> | |
| <label class="block text-sm font-medium text-gray-700 mb-1">Max Tokens</label> | |
| <input type="number" id="max-tokens-input" min="1" max="4096" value="512" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"> | |
| </div> | |
| <div class="pt-2"> | |
| <button id="generate-btn" class="w-full px-4 py-2 bg-green-600 text-white rounded-md hover:bg-green-700 flex items-center justify-center" disabled> | |
| <i class="ri-play-line mr-2"></i> | |
| <span>Generate</span> | |
| </button> | |
| </div> | |
| </div> | |
| <div id="model-info" class="mt-6 pt-4 border-t border-gray-200"> | |
| <h3 class="text-lg font-medium mb-2">Current Model</h3> | |
| <p class="text-sm text-gray-700 mb-1">Name: <span id="current-model-name" class="font-medium">None loaded</span></p> | |
| <p class="text-sm text-gray-700 mb-1">Size: <span id="current-model-size" class="font-medium">-</span></p> | |
| <p class="text-sm text-gray-700 mb-1">Loaded: <span id="current-model-loaded" class="font-medium">-</span></p> | |
| <div class="mt-2"> | |
| <button id="unload-model-btn" class="w-full px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-700 flex items-center justify-center"> | |
| <i class="ri-close-line mr-2"></i> | |
| <span>Unload Model</span> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Settings Section --> | |
| <div id="settings" class="hidden"> | |
| <div class="flex justify-between items-center mb-6"> | |
| <h1 class="text-2xl font-bold">Settings</h1> | |
| </div> | |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-6"> | |
| <div class="md:col-span-2 bg-white p-6 rounded-lg shadow"> | |
| <h3 class="text-lg font-medium mb-4">AI Provider Configuration</h3> | |
| <form id="settings-form"> | |
| <div class="mb-4"> | |
| <label class="block text-sm font-medium text-gray-700 mb-1">AI Provider</label> | |
| <select id="ai-provider" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"> | |
| <option value="gemini">Gemini (Google AI Studio)</option> | |
| <option value="openai">OpenAI</option> | |
| <option value="anthropic">Anthropic</option> | |
| <option value="custom">Custom</option> | |
| </select> | |
| </div> | |
| <div class="mb-4"> | |
| <label class="block text-sm font-medium text-gray-700 mb-1">API Key</label> | |
| <div class="flex"> | |
| <input id="api-key-input" type="password" placeholder="Enter your API key" class="flex-1 px-3 py-2 border border-gray-300 rounded-l-md focus:outline-none focus:ring-2 focus:ring-blue-500"> | |
| <button type="button" id="toggle-key-visibility" class="px-3 py-2 bg-gray-100 border border-l-0 border-gray-300 rounded-r-md"> | |
| <i class="ri-eye-line"></i> | |
| </button> | |
| </div> | |
| <p class="mt-1 text-xs text-gray-500" id="api-key-help">Get your API key from <a href="https://ai.google.dev/" target="_blank" class="text-blue-600 hover:underline">Google AI Studio</a></p> | |
| </div> | |
| <div class="mb-4"> | |
| <label class="block text-sm font-medium text-gray-700 mb-1">Base URL</label> | |
| <input id="api-base-url" type="text" placeholder="Leave empty for default" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"> | |
| </div> | |
| <div class="mb-4"> | |
| <div class="flex items-center"> | |
| <input id="save-api-key" type="checkbox" class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"> | |
| <label for="save-api-key" class="ml-2 block text-sm text-gray-700">Save API key in browser storage</label> | |
| </div> | |
| </div> | |
| <div class="flex justify-end"> | |
| <button type="button" id="test-api-btn" class="mr-2 px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50"> | |
| Test Connection | |
| </button> | |
| <button type="button" id="save-settings-btn" class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700"> | |
| Save Settings | |
| </button> | |
| </div> | |
| </form> | |
| </div> | |
| <div class="bg-white p-6 rounded-lg shadow"> | |
| <h3 class="text-lg font-medium mb-4">Connection Status</h3> | |
| <div class="space-y-4"> | |
| <div class="flex items-center"> | |
| <div id="ai-status-indicator" class="h-3 w-3 rounded-full bg-gray-300 mr-2"></div> | |
| <span>AI Provider</span> | |
| <button id="refresh-ai-status" class="ml-auto p-1 text-gray-500 hover:text-gray-700"> | |
| <i class="ri-refresh-line"></i> | |
| </button> | |
| </div> | |
| <div class="flex items-center"> | |
| <div id="github-status-indicator" class="h-3 w-3 rounded-full bg-gray-300 mr-2"></div> | |
| <span>GitHub Integration</span> | |
| <button id="refresh-github-status" class="ml-auto p-1 text-gray-500 hover:text-gray-700"> | |
| <i class="ri-refresh-line"></i> | |
| </button> | |
| </div> | |
| <div class="flex items-center"> | |
| <div id="model-status-indicator" class="h-3 w-3 rounded-full bg-gray-300 mr-2"></div> | |
| <span>Model Runner</span> | |
| <button id="refresh-model-status" class="ml-auto p-1 text-gray-500 hover:text-gray-700"> | |
| <i class="ri-refresh-line"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="mt-6 pt-4 border-t border-gray-200"> | |
| <h3 class="text-lg font-medium mb-4">Application Settings</h3> | |
| <div class="space-y-3"> | |
| <div class="flex items-center justify-between"> | |
| <label class="block text-sm text-gray-700">Dark Mode</label> | |
| <label class="relative inline-flex items-center cursor-pointer"> | |
| <input type="checkbox" id="dark-mode-toggle" class="sr-only peer"> | |
| <div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div> | |
| </label> | |
| </div> | |
| <div class="flex items-center justify-between"> | |
| <label class="block text-sm text-gray-700">Notifications</label> | |
| <label class="relative inline-flex items-center cursor-pointer"> | |
| <input type="checkbox" id="notifications-toggle" checked class="sr-only peer"> | |
| <div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div> | |
| </label> | |
| </div> | |
| <div class="flex items-center justify-between"> | |
| <label class="block text-sm text-gray-700">Auto-update</label> | |
| <label class="relative inline-flex items-center cursor-pointer"> | |
| <input type="checkbox" id="auto-update-toggle" class="sr-only peer"> | |
| <div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div> | |
| </label> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="mt-6 pt-4 border-t border-gray-200"> | |
| <button id="clear-storage-btn" class="w-full px-4 py-2 bg-red-50 text-red-600 rounded-md hover:bg-red-100"> | |
| Clear Local Storage | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // Sidebar toggle | |
| const sidebar = document.getElementById('sidebar'); | |
| const collapseBtn = document.getElementById('collapse-btn'); | |
| collapseBtn.addEventListener('click', () => { | |
| sidebar.classList.toggle('collapsed'); | |
| collapseBtn.querySelector('i').classList.toggle('ri-arrow-left-s-line'); | |
| collapseBtn.querySelector('i').classList.toggle('ri-arrow-right-s-line'); | |
| }); | |
| // Navigation between sections | |
| const navLinks = document.querySelectorAll('[data-section]'); | |
| const sections = { | |
| dashboard: document.getElementById('dashboard'), | |
| github: document.getElementById('github'), | |
| ai: document.getElementById('ai'), | |
| model: document.getElementById('model'), | |
| settings: document.getElementById('settings') | |
| }; | |
| navLinks.forEach(link => { | |
| link.addEventListener('click', (e) => { | |
| e.preventDefault(); | |
| const sectionName = link.getAttribute('data-section'); | |
| // Hide all sections | |
| Object.values(sections).forEach(section => { | |
| section.classList.add('hidden'); | |
| }); | |
| // Show selected section | |
| if (sections[sectionName]) { | |
| sections[sectionName].classList.remove('hidden'); | |
| } | |
| // Update active nav link | |
| navLinks.forEach(navLink => { | |
| navLink.classList.remove('active-section'); | |
| }); | |
| link.classList.add('active-section'); | |
| }); | |
| }); | |
| // Model parameters sliders | |
| const temperatureSlider = document.getElementById('temperature-slider'); | |
| const temperatureValue = document.getElementById('temperature-value'); | |
| const topPSlider = document.getElementById('top-p-slider'); | |
| const topPValue = document.getElementById('top-p-value'); | |
| temperatureSlider.addEventListener('input', () => { | |
| temperatureValue.textContent = temperatureSlider.value; | |
| }); | |
| topPSlider.addEventListener('input', () => { | |
| topPValue.textContent = topPSlider.value; | |
| }); | |
| // Dark mode toggle | |
| const darkModeToggle = document.getElementById('dark-mode-toggle'); | |
| darkModeToggle.addEventListener('change', () => { | |
| document.body.classList.toggle('dark-mode'); | |
| localStorage.setItem('darkMode', darkModeToggle.checked ? 'enabled' : 'disabled'); | |
| }); | |
| // Load dark mode preference | |
| if (localStorage.getItem('darkMode') === 'enabled') { | |
| darkModeToggle.checked = true; | |
| document.body.classList.add('dark-mode'); | |
| } | |
| // API key visibility toggle | |
| const apiKeyInput = document.getElementById('api-key-input'); | |
| const toggleKeyVisibility = document.getElementById('toggle-key-visibility'); | |
| toggleKeyVisibility.addEventListener('click', () => { | |
| if (apiKeyInput.type === 'password') { | |
| apiKeyInput.type = 'text'; | |
| toggleKeyVisibility.innerHTML = '<i class="ri-eye-off-line"></i>'; | |
| } else { | |
| apiKeyInput.type = 'password'; | |
| toggleKeyVisibility.innerHTML = '<i class="ri-eye-line"></i>'; | |
| } | |
| }); | |
| // Save settings | |
| const saveSettingsBtn = document.getElementById('save-settings-btn'); | |
| saveSettingsBtn.addEventListener('click', () => { | |
| const saveKey = document.getElementById('save-api-key').checked; | |
| const settings = { | |
| provider: document.getElementById('ai-provider').value, | |
| apiKey: document.getElementById('api-key-input').value, | |
| baseUrl: document.getElementById('api-base-url').value, | |
| saveKey | |
| }; | |
| localStorage.setItem('aiSettings', JSON.stringify(settings)); | |
| if (saveKey) { | |
| localStorage.setItem('apiKey', settings.apiKey); | |
| } else { | |
| localStorage.removeItem('apiKey'); | |
| } | |
| alert('Settings saved successfully!'); | |
| }); | |
| // Load settings | |
| const loadSettings = () => { | |
| const savedSettings = localStorage.getItem('aiSettings'); | |
| if (savedSettings) { | |
| const settings = JSON.parse(savedSettings); | |
| document.getElementById('ai-provider').value = settings.provider; | |
| document.getElementById('api-key-input').value = settings.apiKey; | |
| document.getElementById('api-base-url').value = settings.baseUrl; | |
| document.getElementById('save-api-key').checked = settings.saveKey; | |
| } else if (localStorage.getItem('apiKey')) { | |
| document.getElementById('api-key-input').value = localStorage.getItem('apiKey'); | |
| document.getElementById('save-api-key').checked = true; | |
| } | |
| // Update provider info | |
| updateProviderInfo(); | |
| }; | |
| // Update provider info based on selection | |
| const updateProviderInfo = () => { | |
| const provider = document.getElementById('ai-provider').value; | |
| let helpText = ''; | |
| switch(provider) { | |
| case 'gemini': | |
| helpText = 'Get your API key from <a href="https://ai.google.dev/" target="_blank" class="text-blue-600 hover:underline">Google AI Studio</a>'; | |
| break; | |
| case 'openai': | |
| helpText = 'Get your API key from <a href="https://platform.openai.com/api-keys" target="_blank" class="text-blue-600 hover:underline">OpenAI</a>'; | |
| break; | |
| case 'anthropic': | |
| helpText = 'Get your API key from <a href="https://console.anthropic.com/settings/keys" target="_blank" class="text-blue-600 hover:underline">Anthropic</a>'; | |
| break; | |
| case 'custom': | |
| helpText = 'Enter your custom API key and endpoint URL'; | |
| break; | |
| } | |
| document.getElementById('api-key-help').innerHTML = helpText; | |
| }; | |
| document.getElementById('ai-provider').addEventListener('change', updateProviderInfo); | |
| // Test API connection | |
| document.getElementById('test-api-btn').addEventListener('click', () => { | |
| const provider = document.getElementById('ai-provider').value; | |
| const apiKey = document.getElementById('api-key-input').value; | |
| if (!apiKey) { | |
| alert('Please enter an API key'); | |
| return; | |
| } | |
| // Simulate API test (in a real app, you'd make an actual API call) | |
| const statusIndicator = document.getElementById('ai-status-indicator'); | |
| statusIndicator.classList.remove('bg-green-500', 'bg-red-500', 'bg-gray-300'); | |
| statusIndicator.classList.add('bg-yellow-500'); | |
| setTimeout(() => { | |
| statusIndicator.classList.remove('bg-yellow-500'); | |
| statusIndicator.classList.add('bg-green-500'); | |
| const aiModelName = document.getElementById('ai-model-name'); | |
| switch(provider) { | |
| case 'gemini': | |
| aiModelName.textContent = 'Gemini AI Assistant'; | |
| break; | |
| case 'openai': | |
| aiModelName.textContent = 'OpenAI Assistant'; | |
| break; | |
| case 'anthropic': | |
| aiModelName.textContent = 'Claude AI Assistant'; | |
| break; | |
| case 'custom': | |
| aiModelName.textContent = 'Custom AI Assistant'; | |
| break; | |
| } | |
| }, 1000); | |
| }); | |
| // Model loading functionality | |
| const loadModelButtons = document.querySelectorAll('.load-model-btn'); | |
| const sendModelQueryBtn = document.getElementById('send-model-query'); | |
| const generateBtn = document.getElementById('generate-btn'); | |
| const modelOutput = document.getElementById('model-output'); | |
| const modelInput = document.getElementById('model-input'); | |
| let currentModel = null; | |
| loadModelButtons.forEach(button => { | |
| button.addEventListener('click', () => { | |
| const model = button.getAttribute('data-model'); | |
| currentModel = model; | |
| // Update model info | |
| document.getElementById('current-model-name').textContent = model.replace('-', ' ').toUpperCase(); | |
| document.getElementById('current-model-size').textContent = model === 'phi-2' ? '1.7GB' : | |
| model === 'mistral-7b' ? '4.1GB' : | |
| model === 'llama2-13b' ? '7.3GB' : '1.7GB'; | |
| document.getElementById('current-model-loaded').textContent = new Date().toLocaleTimeString(); | |
| // Enable query and generate buttons | |
| sendModelQueryBtn.disabled = false; | |
| generateBtn.disabled = false; | |
| // Update model info display | |
| document.getElementById('model-info').classList.remove('hidden'); | |
| // Update model status indicator | |
| const statusIndicator = document.getElementById('model-status-indicator'); | |
| statusIndicator.classList.remove('bg-gray-300', 'bg-red-500'); | |
| statusIndicator.classList.add('bg-green-500'); | |
| // Add to model output | |
| addToModelOutput('system', `Model ${model.replace('-', ' ').toUpperCase()} loaded successfully`); | |
| }); | |
| }); | |
| // Unload model | |
| document.getElementById('unload-model-btn').addEventListener('click', () => { | |
| if (!currentModel) return; | |
| addToModelOutput('system', `Unloading model ${currentModel.replace('-', ' ').toUpperCase()}...`); | |
| // Reset model info | |
| document.getElementById('current-model-name').textContent = 'None loaded'; | |
| document.getElementById('current-model-size').textContent = '-'; | |
| document.getElementById('current-model-loaded').textContent = '-'; | |
| // Disable query and generate buttons | |
| sendModelQueryBtn.disabled = true; | |
| generateBtn.disabled = true; | |
| // Update model status indicator | |
| const statusIndicator = document.getElementById('model-status-indicator'); | |
| statusIndicator.classList.remove('bg-green-500'); | |
| statusIndicator.classList.add('bg-gray-300'); | |
| currentModel = null; | |
| setTimeout(() => { | |
| addToModelOutput('system', 'Model unloaded. Select a model from above to continue.'); | |
| }, 500); | |
| }); | |
| // Add message to model output | |
| function addToModelOutput(sender, message) { | |
| const thinkingDiv = document.getElementById('model-thinking'); | |
| if (thinkingDiv) thinkingDiv.classList.add('hidden'); | |
| const div = document.createElement('div'); | |
| div.className = 'mb-2'; | |
| const senderSpan = document.createElement('span'); | |
| senderSpan.className = 'prompt'; | |
| senderSpan.textContent = sender + ':'; | |
| const messageSpan = document.createElement('span'); | |
| messageSpan.className = 'text-gray-300 ml-1'; | |
| messageSpan.textContent = message; | |
| div.appendChild(senderSpan); | |
| div.appendChild(messageSpan); | |
| modelOutput.appendChild(div); | |
| modelOutput.scrollTop = modelOutput.scrollHeight; | |
| } | |
| // Send model query | |
| sendModelQueryBtn.addEventListener('click', () => { | |
| const query = modelInput.value.trim(); | |
| if (!query || !currentModel) return; | |
| addToModelOutput('user', query); | |
| modelInput.value = ''; | |
| // Show thinking indicator | |
| const thinkingDiv = document.getElementById('model-thinking'); | |
| if (thinkingDiv) thinkingDiv.classList.remove('hidden'); | |
| // Simulate response after a delay | |
| setTimeout(() => { | |
| const responses = { | |
| 'phi-2': `For your query about "${query}", the Phi-2 model suggests reviewing the official Microsoft documentation. As a lightweight model, Phi-2 is particularly good for code-related queries. Would you like me to generate example code?`, | |
| 'mistral-7b': `Regarding "${query}", Mistral 7B recommends checking system logs first. This model excels at troubleshooting and offers balanced performance for most DevOps tasks. I can help analyze specific error messages if you provide them.`, | |
| 'llama2-13b': `For your inquiry about "${query}", the larger Llama 2 13B model suggests a comprehensive approach with multiple verification steps. Due to its size, it can provide more detailed responses but requires more resources. Here's a step-by-step solution...` | |
| }; | |
| addToModelOutput('ai', responses[currentModel] || `I've processed your query about "${query}". As a general AI model, my suggestion would be to consult the official documentation and check system logs for any error messages.`); | |
| }, 1000); | |
| }); | |
| // AI Chat functionality | |
| const aiChat = document.getElementById('ai-chat'); | |
| const aiInput = document.getElementById('ai-input'); | |
| const sendAiQueryBtn = document.getElementById('send-ai-query'); | |
| function addToAiChat(sender, message) { | |
| const thinkingDiv = document.getElementById('ai-thinking'); | |
| if (thinkingDiv) thinkingDiv.classList.add('hidden'); | |
| const div = document.createElement('div'); | |
| div.className = 'mb-2'; | |
| const senderSpan = document.createElement('span'); | |
| senderSpan.className = sender === 'user' ? 'user' : 'ai'; | |
| senderSpan.style.fontWeight = 'bold'; | |
| senderSpan.textContent = sender + ':'; | |
| const messageSpan = document.createElement('span'); | |
| messageSpan.className = 'text-gray-300 ml-1'; | |
| messageSpan.textContent = message; | |
| div.appendChild(senderSpan); | |
| div.appendChild(messageSpan); | |
| aiChat.appendChild(div); | |
| aiChat.scrollTop = aiChat.scrollHeight; | |
| } | |
| sendAiQueryBtn.addEventListener('click', () => { | |
| const query = aiInput.value.trim(); | |
| if (!query) return; | |
| addToAiChat('user', query); | |
| aiInput.value = ''; | |
| // Show thinking indicator | |
| document.getElementById('ai-thinking').classList.remove('hidden'); | |
| // Simulate AI response | |
| setTimeout(() => { | |
| const responses = [ | |
| `For your DevOps query "${query}", I recommend following industry best practices. First, check your system logs for any errors. Then verify all configurations are correct. Would you like me to provide specific commands for your environment?`, | |
| `Regarding "${query}", this appears to be a common issue in DevOps workflows. The standard approach involves 3 steps: 1) Verification, 2) Isolation, 3) Resolution. I can guide you through each step if helpful.`, | |
| `Your question about "${query}" touches on several important aspects. Based on similar cases, I suggest reviewing these key areas: deployment pipelines, environment variables, and resource allocation.`, | |
| `For "${query}", the solution depends on your specific stack. Please provide details about your technology (Docker, Kubernetes, CI/CD platform etc.) for more tailored advice.`, | |
| `The answer to "${query}" typically involves these considerations: security requirements, performance impact, maintainability, and team familiarity with the solution.` | |
| ]; | |
| addToAiChat('ai', responses[Math.floor(Math.random() * responses.length)]); | |
| }, 1500); | |
| }); | |
| // Allow Enter key to send messages | |
| aiInput.addEventListener('keypress', (e) => { | |
| if (e.key === 'Enter') { | |
| sendAiQueryBtn.click(); | |
| } | |
| }); | |
| modelInput.addEventListener('keypress', (e) => { | |
| if (e.key === 'Enter') { | |
| sendModelQueryBtn.click(); | |
| } | |
| }); | |
| // Clear chat history | |
| document.getElementById('clear-chat-btn').addEventListener('click', () => { | |
| aiChat.innerHTML = '<div class="mb-2"><span class="prompt">system:</span><span class="text-gray-300">Chat history cleared. Ask me anything about DevOps.</span></div>'; | |
| }); | |
| // GGUF model upload functionality | |
| const modelUpload = document.getElementById('model-upload'); | |
| modelUpload.addEventListener('change', (e) => { | |
| const file = e.target.files[0]; | |
| if (!file) return; | |
| if (!file.name.endsWith('.gguf')) { | |
| alert('Please select a GGUF model file (.gguf extension)'); | |
| return; | |
| } | |
| // Simulate file processing and model loading | |
| const fileName = file.name.replace('.gguf', ''); | |
| currentModel = fileName.toLowerCase().replace(/ /g, '-'); | |
| // Update model info | |
| document.getElementById('current-model-name').textContent = fileName; | |
| document.getElementById('current-model-size').textContent = `${(file.size / (1024 * 1024)).toFixed(1)}MB`; | |
| document.getElementById('current-model-loaded').textContent = new Date().toLocaleTimeString(); | |
| // Enable query and generate buttons | |
| sendModelQueryBtn.disabled = false; | |
| generateBtn.disabled = false; | |
| // Update model info display | |
| document.getElementById('model-info').classList.remove('hidden'); | |
| // Update model status indicator | |
| const statusIndicator = document.getElementById('model-status-indicator'); | |
| statusIndicator.classList.remove('bg-gray-300', 'bg-red-500'); | |
| statusIndicator.classList.add('bg-green-500'); | |
| // Add to model output | |
| addToModelOutput('system', `Custom model ${fileName} loaded successfully`); | |
| // Reset file input | |
| e.target.value = ''; | |
| }); | |
| // Clear local storage | |
| document.getElementById('clear-storage-btn').addEventListener('click', () => { | |
| if (confirm('Are you sure you want to clear all locally stored data (settings, API keys, etc.)?')) { | |
| localStorage.clear(); | |
| alert('Local storage cleared. Page will now reload.'); | |
| location.reload(); | |
| } | |
| }); | |
| // Initial setup | |
| loadSettings(); | |
| // Initialize connection status indicators | |
| document.getElementById('ai-status-indicator').classList.add('bg-gray-300'); | |
| document.getElementById('github-status-indicator').classList.add('bg-yellow-500'); | |
| document.getElementById('model-status-indicator').classList.add('bg-gray-300'); | |
| // Refresh status buttons | |
| document.getElementById('refresh-ai-status').addEventListener('click', () => { | |
| const indicator = document.getElementById('ai-status-indicator'); | |
| indicator.classList.remove('bg-green-500', 'bg-red-500', 'bg-gray-300'); | |
| indicator.classList.add('bg-yellow-500'); | |
| setTimeout(() => { | |
| indicator.classList.remove('bg-yellow-500'); | |
| indicator.classList.add('bg-red-500'); | |
| }, 1000); | |
| }); | |
| document.getElementById('refresh-github-status').addEventListener('click', () => { | |
| const indicator = document.getElementById('github-status-indicator'); | |
| indicator.classList.remove('bg-green-500', 'bg-red-500', 'bg-yellow-500'); | |
| indicator.classList.add('bg-gray-300'); | |
| setTimeout(() => { | |
| indicator.classList.remove('bg-gray-300'); | |
| indicator.classList.add('bg-green-500'); | |
| }, 1000); | |
| }); | |
| document.getElementById('refresh-model-status').addEventListener('click', () => { | |
| const indicator = document.getElementById('model-status-indicator'); | |
| if (!currentModel) { | |
| indicator.classList.remove('bg-green-500', 'bg-yellow-500'); | |
| indicator.classList.add('bg-gray-300'); | |
| } else { | |
| indicator.classList.remove('bg-green-500', 'bg-gray-300'); | |
| indicator.classList.add('bg-yellow-500'); | |
| setTimeout(() => { | |
| indicator.classList.remove('bg-yellow-500'); | |
| indicator.classList.add('bg-green-500'); | |
| }, 1000); | |
| } | |
| }); | |
| // Generate button - combines slider settings | |
| document.getElementById('generate-btn').addEventListener('click', () => { | |
| if (!currentModel) return; | |
| const temperature = temperatureSlider.value; | |
| const topP = topPSlider.value; | |
| const maxTokens = document.getElementById('max-tokens-input').value; | |
| addToModelOutput('system', `Generating with params: temp=${temperature}, top_p=${topP}, max_tokens=${maxTokens}`); | |
| // Show thinking indicator | |
| const thinkingDiv = document.getElementById('model-thinking'); | |
| if (thinkingDiv) thinkingDiv.classList.remove('hidden'); | |
| // Simulate generation | |
| setTimeout(() => { | |
| const examples = [ | |
| `Here's an optimized Kubernetes deployment configuration for your requirements:\n\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: optimized-deployment\nspec:\n replicas: 3\n selector:\n matchLabels:\n app: my-app\n template:\n metadata:\n labels:\n app: my-app\n spec:\n containers:\n - name: my-container\n image: my-image:latest\n ports:\n - containerPort: 8080\n resources:\n limits:\n cpu: "1"\n memory: "512Mi"`, | |
| `For your CI/CD pipeline, consider this GitHub Actions workflow:\n\nname: CI/CD Pipeline\n\non:\n push:\n branches: [ main ]\n pull_request:\n branches: [ main ]\n\njobs:\n build:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v3\n - name: Set up Node.js\n uses: actions/setup-node@v3\n with:\n node-version: '18'\n - name: Install dependencies\n run: npm ci\n - name: Run tests\n run: npm test\n - name: Build | |
| </html> |