// AI Server Admin Dashboard JavaScript class AdminDashboard { constructor() { this.apiKey = this.getApiKey(); this.baseUrl = window.location.origin; this.init(); } getApiKey() { // 테스트 모드에서는 기본 API 키 사용 let apiKey = localStorage.getItem('ai_admin_api_key'); if (!apiKey) { // 테스트 모드 기본 키 apiKey = 'test-admin-key-123'; localStorage.setItem('ai_admin_api_key', apiKey); // 사용자에게 알림 setTimeout(() => { alert('테스트 모드입니다.\nAPI Key: test-admin-key-123'); }, 1000); } return apiKey; } async init() { this.updateCurrentTime(); setInterval(() => this.updateCurrentTime(), 1000); await this.loadSystemStatus(); await this.loadModels(); await this.loadApiKeys(); // Auto-refresh every 30 seconds setInterval(() => { this.loadSystemStatus(); this.loadModels(); }, 30000); } updateCurrentTime() { const now = new Date(); document.getElementById('current-time').textContent = now.toLocaleString('ko-KR', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit' }); } async apiRequest(endpoint, options = {}) { const url = `${this.baseUrl}${endpoint}`; const defaultOptions = { headers: { 'Content-Type': 'application/json', 'X-API-Key': this.apiKey } }; try { const response = await fetch(url, { ...defaultOptions, ...options }); if (!response.ok) { if (response.status === 401) { localStorage.removeItem('ai_admin_api_key'); location.reload(); return; } throw new Error(`HTTP ${response.status}: ${response.statusText}`); } return await response.json(); } catch (error) { console.error('API Request failed:', error); throw error; } } async loadSystemStatus() { try { // Check AI Server status const healthResponse = await this.apiRequest('/health'); document.getElementById('server-status').textContent = 'Online'; document.getElementById('server-status').className = 'status-value'; // Check Ollama status try { const ollamaResponse = await this.apiRequest('/admin/ollama/status'); document.getElementById('ollama-status').textContent = ollamaResponse.status === 'online' ? 'Online' : 'Offline'; document.getElementById('ollama-status').className = `status-value ${ollamaResponse.status === 'online' ? '' : 'error'}`; } catch (error) { document.getElementById('ollama-status').textContent = 'Offline'; document.getElementById('ollama-status').className = 'status-value error'; } // Load active model try { const modelResponse = await this.apiRequest('/admin/models/active'); document.getElementById('active-model').textContent = modelResponse.model || 'None'; } catch (error) { document.getElementById('active-model').textContent = 'Unknown'; } // Load API call stats (placeholder) document.getElementById('api-calls').textContent = '0'; } catch (error) { console.error('Failed to load system status:', error); document.getElementById('server-status').textContent = 'Error'; document.getElementById('server-status').className = 'status-value error'; } } async loadModels() { try { const response = await this.apiRequest('/admin/models'); const models = response.models || []; const tbody = document.getElementById('models-tbody'); if (models.length === 0) { tbody.innerHTML = 'No models found'; return; } tbody.innerHTML = models.map(model => ` ${model.name} ${model.is_active ? 'Active' : ''} ${this.formatSize(model.size)} ${model.status || 'Unknown'} ${model.last_used ? new Date(model.last_used).toLocaleString('ko-KR') : 'Never'} `).join(''); } catch (error) { console.error('Failed to load models:', error); document.getElementById('models-tbody').innerHTML = 'Error loading models'; } } async loadApiKeys() { try { const response = await this.apiRequest('/admin/api-keys'); const apiKeys = response.api_keys || []; const container = document.getElementById('api-keys-list'); if (apiKeys.length === 0) { container.innerHTML = '
No API keys found
'; return; } container.innerHTML = apiKeys.map(key => `
${key.name || 'Unnamed Key'}
${this.maskApiKey(key.key)}
Created: ${new Date(key.created_at).toLocaleString('ko-KR')} | Uses: ${key.usage_count || 0}
`).join(''); } catch (error) { console.error('Failed to load API keys:', error); document.getElementById('api-keys-list').innerHTML = '
Error loading API keys
'; } } formatSize(bytes) { if (!bytes) return 'Unknown'; const sizes = ['B', 'KB', 'MB', 'GB', 'TB']; const i = Math.floor(Math.log(bytes) / Math.log(1024)); return Math.round(bytes / Math.pow(1024, i) * 100) / 100 + ' ' + sizes[i]; } maskApiKey(key) { if (!key) return 'Unknown'; if (key.length <= 8) return key; return key.substring(0, 4) + '...' + key.substring(key.length - 4); } async refreshModels() { document.getElementById('models-tbody').innerHTML = 'Refreshing models...'; await this.loadModels(); } async testModel(modelName) { try { const response = await this.apiRequest('/admin/models/test', { method: 'POST', body: JSON.stringify({ model: modelName }) }); alert(`Model test result:\n${response.result || 'Test completed successfully'}`); } catch (error) { alert(`Model test failed: ${error.message}`); } } async generateApiKey() { const name = prompt('Enter a name for the new API key:'); if (!name) return; try { const response = await this.apiRequest('/admin/api-keys', { method: 'POST', body: JSON.stringify({ name }) }); alert(`New API key created:\n${response.api_key}\n\nPlease save this key securely. It will not be shown again.`); await this.loadApiKeys(); } catch (error) { alert(`Failed to generate API key: ${error.message}`); } } async deleteApiKey(keyId) { if (!confirm('Are you sure you want to delete this API key?')) return; try { await this.apiRequest(`/admin/api-keys/${keyId}`, { method: 'DELETE' }); await this.loadApiKeys(); } catch (error) { alert(`Failed to delete API key: ${error.message}`); } } } // Global functions for HTML onclick handlers let admin; function refreshModels() { admin.refreshModels(); } function generateApiKey() { admin.generateApiKey(); } // Initialize dashboard when page loads document.addEventListener('DOMContentLoaded', () => { admin = new AdminDashboard(); });