feat: AI 서버 관리 페이지 Phase 2 고급 기능 구현

🤖 모델 관리 고도화:
- 모델 다운로드: 인기 모델들 원클릭 설치 (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 구현
This commit is contained in:
Hyungi Ahn
2025-08-18 13:45:04 +09:00
parent e102ce6db9
commit b752e56b94
5 changed files with 814 additions and 0 deletions

View File

@@ -330,6 +330,255 @@ body {
color: #f39c12;
}
/* Phase 2: System Monitoring Styles */
.monitoring-container {
background: white;
border-radius: 12px;
padding: 1.5rem;
box-shadow: 0 4px 6px rgba(0,0,0,0.07);
border: 1px solid #e1e8ed;
}
.monitoring-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1.5rem;
}
.monitor-card {
background: #f8f9fa;
border-radius: 8px;
padding: 1.5rem;
text-align: center;
border: 1px solid #e9ecef;
}
.monitor-card .card-header {
margin-bottom: 1rem;
}
.progress-circle {
position: relative;
width: 80px;
height: 80px;
margin: 0 auto 1rem;
border-radius: 50%;
background: conic-gradient(#667eea 0deg, #e9ecef 0deg);
display: flex;
align-items: center;
justify-content: center;
}
.progress-circle::before {
content: '';
position: absolute;
width: 60px;
height: 60px;
border-radius: 50%;
background: white;
}
.progress-text {
position: relative;
z-index: 1;
font-size: 0.9rem;
font-weight: 600;
color: #2c3e50;
}
.monitor-details {
font-size: 0.8rem;
color: #7f8c8d;
}
/* Progress circle colors */
.progress-circle.low {
background: conic-gradient(#27ae60 var(--progress, 0deg), #e9ecef var(--progress, 0deg));
}
.progress-circle.medium {
background: conic-gradient(#f39c12 var(--progress, 0deg), #e9ecef var(--progress, 0deg));
}
.progress-circle.high {
background: conic-gradient(#e74c3c var(--progress, 0deg), #e9ecef var(--progress, 0deg));
}
/* Modal Styles */
.modal {
display: none;
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.5);
backdrop-filter: blur(4px);
}
.modal-content {
background-color: white;
margin: 5% auto;
padding: 0;
border-radius: 12px;
width: 90%;
max-width: 600px;
box-shadow: 0 10px 30px rgba(0,0,0,0.3);
animation: modalSlideIn 0.3s ease;
}
@keyframes modalSlideIn {
from {
opacity: 0;
transform: translateY(-50px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1.5rem;
border-bottom: 1px solid #e1e8ed;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border-radius: 12px 12px 0 0;
}
.modal-header h3 {
margin: 0;
display: flex;
align-items: center;
gap: 0.5rem;
}
.close-btn {
background: none;
border: none;
font-size: 1.5rem;
color: white;
cursor: pointer;
padding: 0;
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
transition: background-color 0.2s ease;
}
.close-btn:hover {
background-color: rgba(255,255,255,0.2);
}
.modal-body {
padding: 1.5rem;
}
.modal-actions {
display: flex;
gap: 1rem;
justify-content: flex-end;
margin-top: 1.5rem;
padding-top: 1rem;
border-top: 1px solid #e1e8ed;
}
/* Available Models List */
.available-model-item {
background: #f8f9fa;
border: 1px solid #e1e8ed;
border-radius: 8px;
padding: 1rem;
margin-bottom: 1rem;
display: flex;
justify-content: space-between;
align-items: center;
transition: border-color 0.2s ease;
}
.available-model-item:hover {
border-color: #667eea;
}
.model-info {
flex: 1;
}
.model-name {
font-weight: 600;
color: #2c3e50;
margin-bottom: 0.3rem;
}
.model-description {
font-size: 0.9rem;
color: #7f8c8d;
margin-bottom: 0.5rem;
}
.model-tags {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
}
.model-tag {
background: #667eea;
color: white;
padding: 0.2rem 0.5rem;
border-radius: 12px;
font-size: 0.7rem;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.model-tag.code {
background: #e74c3c;
}
.model-tag.lightweight {
background: #27ae60;
}
.model-tag.recommended {
background: #f39c12;
}
.model-size {
font-size: 0.9rem;
color: #95a5a6;
margin-top: 0.5rem;
}
.model-delete-info {
background: #fadbd8;
border: 1px solid #f1948a;
border-radius: 8px;
padding: 1rem;
margin: 1rem 0;
}
.model-delete-info strong {
color: #e74c3c;
}
/* Enhanced Models Table */
.models-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1.5rem;
flex-wrap: wrap;
gap: 1rem;
}
/* Responsive */
@media (max-width: 768px) {
.admin-main {
@@ -341,6 +590,11 @@ body {
gap: 1rem;
}
.monitoring-grid {
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 1rem;
}
.header-content {
flex-direction: column;
gap: 1rem;
@@ -351,6 +605,11 @@ body {
overflow-x: auto;
}
.models-header {
flex-direction: column;
align-items: stretch;
}
.api-key-item {
flex-direction: column;
align-items: flex-start;
@@ -361,4 +620,19 @@ body {
width: 100%;
justify-content: flex-end;
}
.available-model-item {
flex-direction: column;
align-items: flex-start;
gap: 1rem;
}
.modal-content {
width: 95%;
margin: 2% auto;
}
.modal-actions {
flex-direction: column;
}
}