🤖 모델 관리 고도화: - 모델 다운로드: 인기 모델들 원클릭 설치 (llama, qwen, gemma, codellama, mistral) - 모델 삭제: 확인 모달과 함께 안전한 삭제 기능 - 사용 가능한 모델 목록: 태그별 분류 (chat, code, lightweight 등) - 모델 상세 정보: 설명, 크기, 용도별 태그 표시 �� 실시간 시스템 모니터링: - CPU/메모리/디스크/GPU 사용률 원형 프로그레스바 - 색상 코딩: 사용률에 따른 시각적 구분 (녹색/주황/빨강) - 실시간 업데이트: 30초마다 자동 새로고침 - 시스템 리소스 상세 정보 (코어 수, 용량, 온도 등) 🎨 고급 UI/UX: - 모달 창: 부드러운 애니메이션과 블러 효과 - 원형 프로그레스바: CSS 기반 실시간 업데이트 - 반응형 디자인: 모바일 최적화 - 태그 시스템: 모델 분류 및 시각화 🔧 새 API 엔드포인트: - POST /admin/models/download - 모델 다운로드 - DELETE /admin/models/{model_name} - 모델 삭제 - GET /admin/models/available - 다운로드 가능한 모델 목록 - GET /admin/system/stats - 시스템 리소스 사용률 수정된 파일: - server/main.py: Phase 2 API 엔드포인트 추가 - test_admin.py: 테스트 모드 Phase 2 기능 추가 - templates/admin.html: 시스템 모니터링 섹션, 모달 창 추가 - static/admin.css: 모니터링 차트, 모달 스타일 추가 - static/admin.js: Phase 2 기능 JavaScript 구현
239 lines
10 KiB
HTML
239 lines
10 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="ko">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>AI Server Admin Dashboard</title>
|
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
|
|
<link href="/static/admin.css" rel="stylesheet">
|
|
</head>
|
|
<body>
|
|
<div class="admin-layout">
|
|
<!-- Header -->
|
|
<header class="admin-header">
|
|
<div class="header-content">
|
|
<h1><i class="fas fa-robot"></i> AI Server Admin</h1>
|
|
<div class="header-info">
|
|
<span class="server-status online">
|
|
<i class="fas fa-circle"></i> Online
|
|
</span>
|
|
<span class="current-time" id="current-time"></span>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<!-- Main Content -->
|
|
<main class="admin-main">
|
|
<!-- System Status Dashboard -->
|
|
<section class="dashboard-section">
|
|
<h2><i class="fas fa-tachometer-alt"></i> System Status</h2>
|
|
<div class="status-grid">
|
|
<div class="status-card">
|
|
<div class="card-header">
|
|
<i class="fas fa-server"></i>
|
|
<h3>AI Server</h3>
|
|
</div>
|
|
<div class="card-content">
|
|
<div class="status-value" id="server-status">Loading...</div>
|
|
<div class="status-detail">Port: {{ server_port }}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="status-card">
|
|
<div class="card-header">
|
|
<i class="fas fa-brain"></i>
|
|
<h3>Ollama</h3>
|
|
</div>
|
|
<div class="card-content">
|
|
<div class="status-value" id="ollama-status">Loading...</div>
|
|
<div class="status-detail" id="ollama-host">{{ ollama_host }}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="status-card">
|
|
<div class="card-header">
|
|
<i class="fas fa-microchip"></i>
|
|
<h3>Active Model</h3>
|
|
</div>
|
|
<div class="card-content">
|
|
<div class="status-value" id="active-model">Loading...</div>
|
|
<div class="status-detail">Base Model</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="status-card">
|
|
<div class="card-header">
|
|
<i class="fas fa-chart-line"></i>
|
|
<h3>API Calls</h3>
|
|
</div>
|
|
<div class="card-content">
|
|
<div class="status-value" id="api-calls">Loading...</div>
|
|
<div class="status-detail">Today</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Model Management -->
|
|
<section class="dashboard-section">
|
|
<h2><i class="fas fa-cogs"></i> Model Management</h2>
|
|
<div class="models-container">
|
|
<div class="models-header">
|
|
<button class="btn btn-primary" onclick="refreshModels()">
|
|
<i class="fas fa-sync"></i> Refresh
|
|
</button>
|
|
<button class="btn btn-success" onclick="openModelDownload()">
|
|
<i class="fas fa-download"></i> Download Model
|
|
</button>
|
|
</div>
|
|
<div class="models-table">
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Model Name</th>
|
|
<th>Size</th>
|
|
<th>Status</th>
|
|
<th>Last Used</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="models-tbody">
|
|
<tr>
|
|
<td colspan="5" class="loading">Loading models...</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- System Monitoring (Phase 2) -->
|
|
<section class="dashboard-section">
|
|
<h2><i class="fas fa-chart-line"></i> System Monitoring</h2>
|
|
<div class="monitoring-container">
|
|
<div class="monitoring-grid">
|
|
<div class="monitor-card">
|
|
<div class="card-header">
|
|
<i class="fas fa-microchip"></i>
|
|
<h3>CPU Usage</h3>
|
|
</div>
|
|
<div class="card-content">
|
|
<div class="progress-circle" id="cpu-progress">
|
|
<span class="progress-text" id="cpu-text">--</span>
|
|
</div>
|
|
<div class="monitor-details">
|
|
<span id="cpu-cores">-- cores</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="monitor-card">
|
|
<div class="card-header">
|
|
<i class="fas fa-memory"></i>
|
|
<h3>Memory Usage</h3>
|
|
</div>
|
|
<div class="card-content">
|
|
<div class="progress-circle" id="memory-progress">
|
|
<span class="progress-text" id="memory-text">--</span>
|
|
</div>
|
|
<div class="monitor-details">
|
|
<span id="memory-details">-- / -- GB</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="monitor-card">
|
|
<div class="card-header">
|
|
<i class="fas fa-hdd"></i>
|
|
<h3>Disk Usage</h3>
|
|
</div>
|
|
<div class="card-content">
|
|
<div class="progress-circle" id="disk-progress">
|
|
<span class="progress-text" id="disk-text">--</span>
|
|
</div>
|
|
<div class="monitor-details">
|
|
<span id="disk-details">-- / -- GB</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="monitor-card">
|
|
<div class="card-header">
|
|
<i class="fas fa-thermometer-half"></i>
|
|
<h3>GPU Status</h3>
|
|
</div>
|
|
<div class="card-content">
|
|
<div class="progress-circle" id="gpu-progress">
|
|
<span class="progress-text" id="gpu-text">--</span>
|
|
</div>
|
|
<div class="monitor-details">
|
|
<span id="gpu-details">No GPU detected</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- API Key Management -->
|
|
<section class="dashboard-section">
|
|
<h2><i class="fas fa-key"></i> API Key Management</h2>
|
|
<div class="api-keys-container">
|
|
<div class="api-keys-header">
|
|
<button class="btn btn-success" onclick="generateApiKey()">
|
|
<i class="fas fa-plus"></i> Generate New Key
|
|
</button>
|
|
</div>
|
|
<div class="api-keys-list" id="api-keys-list">
|
|
<div class="loading">Loading API keys...</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</main>
|
|
</div>
|
|
|
|
<!-- Model Download Modal -->
|
|
<div id="model-download-modal" class="modal">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h3><i class="fas fa-download"></i> Download Model</h3>
|
|
<button class="close-btn" onclick="closeModal('model-download-modal')">×</button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div id="available-models-list">
|
|
<div class="loading">Loading available models...</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Model Delete Confirmation Modal -->
|
|
<div id="model-delete-modal" class="modal">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h3><i class="fas fa-trash"></i> Delete Model</h3>
|
|
<button class="close-btn" onclick="closeModal('model-delete-modal')">×</button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<p>Are you sure you want to delete this model?</p>
|
|
<div class="model-delete-info">
|
|
<strong id="delete-model-name">Model Name</strong>
|
|
<p>This action cannot be undone.</p>
|
|
</div>
|
|
<div class="modal-actions">
|
|
<button class="btn btn-danger" id="confirm-delete-btn">
|
|
<i class="fas fa-trash"></i> Delete
|
|
</button>
|
|
<button class="btn btn-secondary" onclick="closeModal('model-delete-modal')">
|
|
Cancel
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Scripts -->
|
|
<script src="/static/admin.js"></script>
|
|
</body>
|
|
</html>
|