1032 lines
49 KiB
HTML
1032 lines
49 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>大模型微调平台 - 主页</title>
|
||
<!-- Tailwind CSS CDN -->
|
||
<script src="https://cdn.tailwindcss.com"></script>
|
||
<!-- Chart.js CDN -->
|
||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.8/dist/chart.umd.min.js"></script>
|
||
<!-- 自定义Tailwind配置(匹配浅色主题) -->
|
||
<script>
|
||
tailwind.config = {
|
||
theme: {
|
||
extend: {
|
||
colors: {
|
||
dashboard: {
|
||
bg: '#DBE0F9', // 主背景色(与login一致)
|
||
card: '#FFFFFF', // 卡片背景
|
||
primary: '#6065D9', // 主蓝色
|
||
secondary: '#764BA2', // 深蓝紫色
|
||
accent: '#17D7FA', // 浅蓝高亮
|
||
text: '#333333', // 文字色
|
||
textLight: '#666666' // 浅文字色
|
||
}
|
||
},
|
||
fontFamily: {
|
||
inter: ['Inter', 'sans-serif'],
|
||
},
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
<style type="text/tailwindcss">
|
||
@layer utilities {
|
||
.gradient-blue {
|
||
background: linear-gradient(135deg, #6065D9 0%, #17D7FA 100%);
|
||
}
|
||
.card-shadow {
|
||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
||
}
|
||
.progress-bar {
|
||
height: 8px;
|
||
border-radius: 4px;
|
||
overflow: hidden;
|
||
}
|
||
.radial-progress {
|
||
position: relative;
|
||
width: 120px;
|
||
height: 120px;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
.radial-progress::before {
|
||
content: '';
|
||
position: absolute;
|
||
width: 90%;
|
||
height: 90%;
|
||
background-color: #FFFFFF;
|
||
border-radius: 50%;
|
||
}
|
||
}
|
||
</style>
|
||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||
<!-- 登录验证脚本 -->
|
||
<script>
|
||
// 页面加载时检查登录状态
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
const isLoggedIn = sessionStorage.getItem('isLoggedIn') === 'true';
|
||
|
||
if (!isLoggedIn) {
|
||
// 如果未登录,重定向到登录页面
|
||
window.location.href = 'login.html';
|
||
}
|
||
});
|
||
</script>
|
||
</head>
|
||
<body class="bg-dashboard-bg text-dashboard-text font-inter min-h-screen">
|
||
<div class="flex">
|
||
<!-- 侧边栏 -->
|
||
<aside class="w-16 md:w-64 bg-white h-screen p-4 flex flex-col shadow-lg">
|
||
<div class="flex items-center mb-8">
|
||
<div class="w-10 h-10 rounded-lg gradient-blue flex items-center justify-center">
|
||
<span class="text-white font-bold">AI</span>
|
||
</div>
|
||
<span class="ml-2 text-lg font-semibold hidden md:block text-dashboard-primary">大模型平台</span>
|
||
</div>
|
||
<nav class="flex-1">
|
||
<ul class="space-y-4">
|
||
<li><a href="#" data-page="dashboard" class="nav-item flex items-center p-2 rounded-lg gradient-blue text-white">
|
||
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"></path></svg>
|
||
<span class="hidden md:block">仪表盘</span>
|
||
</a></li>
|
||
<li><a href="#" data-page="preprocess" class="nav-item flex items-center p-2 rounded-lg hover:bg-dashboard-primary/10 text-dashboard-textLight">
|
||
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4"></path></svg>
|
||
<span class="hidden md:block">数据预处理</span>
|
||
</a></li>
|
||
<li><a href="#" data-page="pretrain" class="nav-item flex items-center p-2 rounded-lg hover:bg-dashboard-primary/10 text-dashboard-textLight">
|
||
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path></svg>
|
||
<span class="hidden md:block">模型预训练</span>
|
||
</a></li>
|
||
<li><a href="#" data-page="finetune" class="nav-item flex items-center p-2 rounded-lg hover:bg-dashboard-primary/10 text-dashboard-textLight">
|
||
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 3v2m6-2v2M9 19v2m6-2v2M5 9H3m2 6H3m18-6h-2m2 6h-2M7 19h10a2 2 0 002-2V7a2 2 0 00-2-2H7a2 2 0 00-2 2v10a2 2 0 002 2zM9 9h6v6H9V9z"></path></svg>
|
||
<span class="hidden md:block">模型微调</span>
|
||
</a></li>
|
||
<li><a href="#" data-page="rl" class="nav-item flex items-center p-2 rounded-lg hover:bg-dashboard-primary/10 text-dashboard-textLight">
|
||
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6"></path></svg>
|
||
<span class="hidden md:block">强化训练</span>
|
||
</a></li>
|
||
<li><a href="#" data-page="validate" class="nav-item flex items-center p-2 rounded-lg hover:bg-dashboard-primary/10 text-dashboard-textLight">
|
||
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
|
||
<span class="hidden md:block">模型验证</span>
|
||
</a></li>
|
||
<li><a href="#" data-page="compare" class="nav-item flex items-center p-2 rounded-lg hover:bg-dashboard-primary/10 text-dashboard-textLight">
|
||
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path></svg>
|
||
<span class="hidden md:block">模型对比</span>
|
||
</a></li>
|
||
<li><a href="#" data-page="dataset" class="nav-item flex items-center p-2 rounded-lg hover:bg-dashboard-primary/10 text-dashboard-textLight">
|
||
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"></path></svg>
|
||
<span class="hidden md:block">数据集管理</span>
|
||
</a></li>
|
||
<li><a href="#" data-page="config" class="nav-item flex items-center p-2 rounded-lg hover:bg-dashboard-primary/10 text-dashboard-textLight">
|
||
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"></path><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path></svg>
|
||
<span class="hidden md:block">模型配置</span>
|
||
</a></li>
|
||
<li><a href="#" onclick="logout()" class="flex items-center p-2 rounded-lg hover:bg-red-100 text-dashboard-textLight hover:text-red-600">
|
||
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1"></path></svg>
|
||
<span class="hidden md:block">退出登录</span>
|
||
</a></li>
|
||
</ul>
|
||
</nav>
|
||
</aside>
|
||
|
||
<!-- 主内容区 -->
|
||
<main class="flex-1" style="height: calc(100vh - 0px);">
|
||
<!-- 仪表盘页面 -->
|
||
<div id="dashboard-page" class="page-content hidden" style="padding: 1.5rem; height: 100%; overflow-y: auto;">
|
||
<!-- 顶部数据卡片 -->
|
||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-6">
|
||
<div class="bg-white rounded-xl p-4 card-shadow">
|
||
<p class="text-dashboard-textLight text-sm">活跃模型</p>
|
||
<p class="text-2xl font-bold mt-1 text-dashboard-text">12</p>
|
||
<div class="flex items-center mt-2 text-green-500 text-sm">
|
||
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 15l7-7 7 7"></path></svg>
|
||
<span>+3个</span>
|
||
</div>
|
||
</div>
|
||
<div class="bg-white rounded-xl p-4 card-shadow">
|
||
<p class="text-dashboard-textLight text-sm">训练中项目</p>
|
||
<p class="text-2xl font-bold mt-1 text-dashboard-text">5</p>
|
||
<div class="flex items-center mt-2 text-blue-500 text-sm">
|
||
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path></svg>
|
||
<span>运行中</span>
|
||
</div>
|
||
</div>
|
||
<div class="bg-white rounded-xl p-4 card-shadow">
|
||
<p class="text-dashboard-textLight text-sm">完成任务</p>
|
||
<p class="text-2xl font-bold mt-1 text-dashboard-text">158</p>
|
||
<div class="flex items-center mt-2 text-green-500 text-sm">
|
||
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
|
||
<span>全部成功</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 中部核心卡片 - 系统监控 -->
|
||
<div class="grid grid-cols-1 gap-6 mb-6">
|
||
<!-- 系统状态监控 -->
|
||
<div class="bg-white rounded-xl p-6 card-shadow">
|
||
<div class="flex items-center justify-between mb-6">
|
||
<p class="text-lg font-semibold text-dashboard-text">系统监控</p>
|
||
<div class="flex items-center">
|
||
<div class="w-3 h-3 rounded-full bg-green-500 mr-2 animate-pulse"></div>
|
||
<p class="text-dashboard-textLight text-sm">实时监控</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 三个实时监控图表 -->
|
||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||
<!-- CPU监控 -->
|
||
<div class="bg-gray-50 rounded-lg p-4">
|
||
<div class="flex items-center justify-between mb-3">
|
||
<div class="flex items-center">
|
||
<div class="w-3 h-3 rounded-full bg-red-500 mr-2"></div>
|
||
<span class="text-sm font-medium text-dashboard-text">CPU</span>
|
||
</div>
|
||
<span id="cpuPercent" class="text-lg font-bold text-dashboard-text">45%</span>
|
||
</div>
|
||
<div class="h-24">
|
||
<canvas id="cpuChart"></canvas>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- GPU监控 -->
|
||
<div class="bg-gray-50 rounded-lg p-4">
|
||
<div class="flex items-center justify-between mb-3">
|
||
<div class="flex items-center">
|
||
<div class="w-3 h-3 rounded-full bg-green-500 mr-2"></div>
|
||
<span class="text-sm font-medium text-dashboard-text">GPU</span>
|
||
</div>
|
||
<span id="gpuPercent" class="text-lg font-bold text-dashboard-text">67%</span>
|
||
</div>
|
||
<div class="h-24">
|
||
<canvas id="gpuChart"></canvas>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 内存监控 -->
|
||
<div class="bg-gray-50 rounded-lg p-4">
|
||
<div class="flex items-center justify-between mb-3">
|
||
<div class="flex items-center">
|
||
<div class="w-3 h-3 rounded-full bg-blue-500 mr-2"></div>
|
||
<span class="text-sm font-medium text-dashboard-text">内存</span>
|
||
</div>
|
||
<span id="memoryPercent" class="text-lg font-bold text-dashboard-text">52%</span>
|
||
</div>
|
||
<div class="h-24">
|
||
<canvas id="memoryChart"></canvas>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 图表区域 -->
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
|
||
<!-- 训练进度折线图 -->
|
||
<div class="bg-white rounded-xl p-6 card-shadow">
|
||
<p class="text-lg font-semibold mb-4 text-dashboard-text">训练进度</p>
|
||
<div class="w-full h-60">
|
||
<canvas id="trainingChart"></canvas>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 模型分布柱状图 -->
|
||
<div class="bg-white rounded-xl p-6 card-shadow">
|
||
<div class="flex justify-between items-center mb-4">
|
||
<p class="text-lg font-semibold text-dashboard-text">模型类型分布</p>
|
||
<div class="flex space-x-2">
|
||
<div class="px-3 py-1 bg-dashboard-primary/10 rounded text-xs text-dashboard-primary">全部</div>
|
||
</div>
|
||
</div>
|
||
<div class="w-full h-40 mb-4">
|
||
<canvas id="modelChart"></canvas>
|
||
</div>
|
||
<div class="grid grid-cols-3 gap-2 text-center">
|
||
<div>
|
||
<p class="text-lg font-bold text-dashboard-text">GPT</p>
|
||
<p class="text-xs text-dashboard-textLight">8个</p>
|
||
</div>
|
||
<div>
|
||
<p class="text-lg font-bold text-dashboard-text">BERT</p>
|
||
<p class="text-xs text-dashboard-textLight">5个</p>
|
||
</div>
|
||
<div>
|
||
<p class="text-lg font-bold text-dashboard-text">LLaMA</p>
|
||
<p class="text-xs text-dashboard-textLight">3个</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 底部项目和订单 -->
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||
<!-- 当前任务 -->
|
||
<div class="bg-white rounded-xl p-6 card-shadow">
|
||
<p class="text-lg font-semibold mb-4 text-dashboard-text">当前训练任务</p>
|
||
<div class="space-y-4">
|
||
<div class="border-b border-dashboard-bg pb-4">
|
||
<div class="flex justify-between mb-2">
|
||
<p class="font-medium text-dashboard-text">GPT-4微调</p>
|
||
<p class="text-dashboard-textLight text-sm">进行中</p>
|
||
</div>
|
||
<div class="progress-bar bg-dashboard-bg">
|
||
<div class="w-[75%] gradient-blue"></div>
|
||
</div>
|
||
<p class="text-right text-xs text-dashboard-textLight mt-1">75%</p>
|
||
</div>
|
||
<div class="border-b border-dashboard-bg pb-4">
|
||
<div class="flex justify-between mb-2">
|
||
<p class="font-medium text-dashboard-text">BERT情感分析</p>
|
||
<p class="text-dashboard-textLight text-sm">队列中</p>
|
||
</div>
|
||
<div class="progress-bar bg-dashboard-bg">
|
||
<div class="w-[0%] gradient-blue"></div>
|
||
</div>
|
||
<p class="text-right text-xs text-dashboard-textLight mt-1">0%</p>
|
||
</div>
|
||
<div class="border-b border-dashboard-bg pb-4">
|
||
<div class="flex justify-between mb-2">
|
||
<p class="font-medium text-dashboard-text">LLaMA对话模型</p>
|
||
<p class="text-dashboard-textLight text-sm">已完成</p>
|
||
</div>
|
||
<div class="progress-bar bg-dashboard-bg">
|
||
<div class="w-[100%] gradient-blue"></div>
|
||
</div>
|
||
<p class="text-right text-xs text-dashboard-textLight mt-1">100%</p>
|
||
</div>
|
||
<div class="border-b border-dashboard-bg pb-4">
|
||
<div class="flex justify-between mb-2">
|
||
<p class="font-medium text-dashboard-text">图像分类模型</p>
|
||
<p class="text-dashboard-textLight text-sm">已完成</p>
|
||
</div>
|
||
<div class="progress-bar bg-dashboard-bg">
|
||
<div class="w-[100%] gradient-blue"></div>
|
||
</div>
|
||
<p class="text-right text-xs text-dashboard-textLight mt-1">100%</p>
|
||
</div>
|
||
<div>
|
||
<div class="flex justify-between mb-2">
|
||
<p class="font-medium text-dashboard-text">推荐系统优化</p>
|
||
<p class="text-dashboard-textLight text-sm">已完成</p>
|
||
</div>
|
||
<div class="progress-bar bg-dashboard-bg">
|
||
<div class="w-[100%] gradient-blue"></div>
|
||
</div>
|
||
<p class="text-right text-xs text-dashboard-textLight mt-1">100%</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 最近活动 -->
|
||
<div class="bg-white rounded-xl p-6 card-shadow">
|
||
<p class="text-lg font-semibold mb-4 text-dashboard-text">最近活动</p>
|
||
<div class="space-y-4">
|
||
<div class="border-b border-dashboard-bg pb-4">
|
||
<div class="flex justify-between mb-1">
|
||
<p class="font-medium text-dashboard-text">模型训练完成</p>
|
||
<p class="text-xs bg-green-100 text-green-600 px-2 py-1 rounded">成功</p>
|
||
</div>
|
||
<p class="text-dashboard-textLight text-sm">GPT-4微调任务已完成</p>
|
||
<p class="text-xs text-dashboard-textLight mt-1">2分钟前</p>
|
||
</div>
|
||
<div class="border-b border-dashboard-bg pb-4">
|
||
<div class="flex justify-between mb-1">
|
||
<p class="font-medium text-dashboard-text">新任务开始</p>
|
||
<p class="text-xs bg-blue-100 text-blue-600 px-2 py-1 rounded">进行中</p>
|
||
</div>
|
||
<p class="text-dashboard-textLight text-sm">BERT情感分析模型开始训练</p>
|
||
<p class="text-xs text-dashboard-textLight mt-1">5分钟前</p>
|
||
</div>
|
||
<div class="border-b border-dashboard-bg pb-4">
|
||
<div class="flex justify-between mb-1">
|
||
<p class="font-medium text-dashboard-text">模型部署</p>
|
||
<p class="text-xs bg-green-100 text-green-600 px-2 py-1 rounded">成功</p>
|
||
</div>
|
||
<p class="text-dashboard-textLight text-sm">LLaMA对话模型已部署到云端</p>
|
||
<p class="text-xs text-dashboard-textLight mt-1">10分钟前</p>
|
||
</div>
|
||
<div class="border-b border-dashboard-bg pb-4">
|
||
<div class="flex justify-between mb-1">
|
||
<p class="font-medium text-dashboard-text">数据集更新</p>
|
||
<p class="text-xs bg-purple-100 text-purple-600 px-2 py-1 rounded">已完成</p>
|
||
</div>
|
||
<p class="text-dashboard-textLight text-sm">训练数据集已更新</p>
|
||
<p class="text-xs text-dashboard-textLight mt-1">30分钟前</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 数据集管理页面 -->
|
||
<div id="dataset-page" class="page-content hidden" style="padding: 1.5rem; height: 100%; overflow-y: auto;">
|
||
<div class="bg-white rounded-xl p-6 card-shadow">
|
||
<div class="flex justify-between items-center mb-6">
|
||
<p class="text-lg font-semibold text-dashboard-text">数据集管理</p>
|
||
<button onclick="document.getElementById('fileInput').click()" class="px-4 py-2 gradient-blue text-white rounded-lg hover:opacity-90 transition-opacity">
|
||
上传数据集
|
||
</button>
|
||
<input type="file" id="fileInput" style="display: none" accept=".json,.jsonl" onchange="handleFileUpload(this)">
|
||
</div>
|
||
|
||
<!-- 数据集列表 -->
|
||
<div id="datasetList" class="space-y-4">
|
||
<!-- 数据集列表将通过 JavaScript 动态加载 -->
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 数据预处理页面 - Easy-Datasets -->
|
||
<div id="preprocess-page" class="page-content hidden h-full" style="padding: 0;">
|
||
<iframe id="easy-datasets-frame"
|
||
src="http://localhost:1717"
|
||
style="width: 100%; height: 100%; border: none;"
|
||
title="Easy-Datasets">
|
||
</iframe>
|
||
</div>
|
||
|
||
<div id="pretrain-page" class="page-content hidden" style="padding: 1.5rem; height: 100%; overflow-y: auto;">
|
||
<div class="bg-white rounded-xl p-6 card-shadow">
|
||
<p class="text-lg font-semibold text-dashboard-text mb-4">模型预训练</p>
|
||
<p class="text-dashboard-textLight">模型预训练功能开发中...</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="finetune-page" class="page-content hidden" style="padding: 1.5rem; height: 100%; overflow-y: auto;">
|
||
<div class="bg-white rounded-xl p-6 card-shadow">
|
||
<p class="text-lg font-semibold text-dashboard-text mb-4">模型微调</p>
|
||
<p class="text-dashboard-textLight">模型微调功能开发中...</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="rl-page" class="page-content hidden" style="padding: 1.5rem; height: 100%; overflow-y: auto;">
|
||
<div class="bg-white rounded-xl p-6 card-shadow">
|
||
<p class="text-lg font-semibold text-dashboard-text mb-4">强化训练</p>
|
||
<p class="text-dashboard-textLight">强化训练功能开发中...</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="validate-page" class="page-content hidden" style="padding: 1.5rem; height: 100%; overflow-y: auto;">
|
||
<div class="bg-white rounded-xl p-6 card-shadow">
|
||
<p class="text-lg font-semibold text-dashboard-text mb-4">模型验证</p>
|
||
<p class="text-dashboard-textLight">模型验证功能开发中...</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="compare-page" class="page-content hidden" style="padding: 1.5rem; height: 100%; overflow-y: auto;">
|
||
<div class="bg-white rounded-xl p-6 card-shadow">
|
||
<p class="text-lg font-semibold text-dashboard-text mb-4">模型对比</p>
|
||
<p class="text-dashboard-textLight">模型对比功能开发中...</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="config-page" class="page-content hidden" style="padding: 1.5rem; height: 100%; overflow-y: auto;">
|
||
<div class="bg-white rounded-xl p-6 card-shadow">
|
||
<p class="text-lg font-semibold text-dashboard-text mb-4">模型配置</p>
|
||
<p class="text-dashboard-textLight">模型配置功能开发中...</p>
|
||
</div>
|
||
</div>
|
||
</main>
|
||
</div>
|
||
|
||
<!-- 图表初始化脚本 -->
|
||
<script>
|
||
// 训练进度折线图
|
||
const trainingCtx = document.getElementById('trainingChart').getContext('2d');
|
||
new Chart(trainingCtx, {
|
||
type: 'line',
|
||
data: {
|
||
labels: ['第1天', '第2天', '第3天', '第4天', '第5天', '第6天', '第7天'],
|
||
datasets: [{
|
||
label: '准确率',
|
||
data: [65, 72, 78, 85, 88, 92, 95],
|
||
borderColor: '#6065D9',
|
||
backgroundColor: 'rgba(96, 101, 217, 0.1)',
|
||
fill: true,
|
||
tension: 0.4,
|
||
pointBackgroundColor: '#FFFFFF',
|
||
pointBorderColor: '#6065D9'
|
||
}]
|
||
},
|
||
options: {
|
||
responsive: true,
|
||
maintainAspectRatio: false,
|
||
plugins: {
|
||
legend: {
|
||
display: false
|
||
}
|
||
},
|
||
scales: {
|
||
x: {
|
||
grid: {
|
||
display: false
|
||
},
|
||
ticks: {
|
||
color: '#666666'
|
||
}
|
||
},
|
||
y: {
|
||
grid: {
|
||
color: 'rgba(0, 0, 0, 0.05)'
|
||
},
|
||
ticks: {
|
||
color: '#666666'
|
||
}
|
||
}
|
||
}
|
||
}
|
||
});
|
||
|
||
// 模型类型分布柱状图
|
||
const modelCtx = document.getElementById('modelChart').getContext('2d');
|
||
new Chart(modelCtx, {
|
||
type: 'bar',
|
||
data: {
|
||
labels: ['GPT', 'BERT', 'LLaMA', 'T5', 'Others'],
|
||
datasets: [{
|
||
label: '模型数量',
|
||
data: [8, 5, 3, 2, 4],
|
||
backgroundColor: [
|
||
'rgba(96, 101, 217, 0.8)',
|
||
'rgba(118, 75, 162, 0.8)',
|
||
'rgba(23, 215, 250, 0.8)',
|
||
'rgba(96, 101, 217, 0.6)',
|
||
'rgba(118, 75, 162, 0.6)'
|
||
],
|
||
borderRadius: 4
|
||
}]
|
||
},
|
||
options: {
|
||
responsive: true,
|
||
maintainAspectRatio: false,
|
||
plugins: {
|
||
legend: {
|
||
display: false
|
||
}
|
||
},
|
||
scales: {
|
||
x: {
|
||
grid: {
|
||
display: false
|
||
},
|
||
ticks: {
|
||
color: '#666666'
|
||
}
|
||
},
|
||
y: {
|
||
grid: {
|
||
color: 'rgba(0, 0, 0, 0.05)'
|
||
},
|
||
ticks: {
|
||
color: '#666666'
|
||
}
|
||
}
|
||
}
|
||
}
|
||
});
|
||
|
||
// 系统监控图表配置
|
||
const chartConfig = {
|
||
type: 'line',
|
||
options: {
|
||
responsive: true,
|
||
maintainAspectRatio: false,
|
||
animation: false,
|
||
plugins: {
|
||
legend: {
|
||
display: false
|
||
}
|
||
},
|
||
scales: {
|
||
x: {
|
||
display: false
|
||
},
|
||
y: {
|
||
display: false,
|
||
min: 0,
|
||
max: 100
|
||
}
|
||
},
|
||
elements: {
|
||
line: {
|
||
tension: 0.4,
|
||
borderWidth: 2
|
||
},
|
||
point: {
|
||
radius: 0
|
||
}
|
||
}
|
||
}
|
||
};
|
||
|
||
// 数据存储
|
||
let cpuHistoryData = [];
|
||
let gpuHistoryData = [];
|
||
let memoryHistoryData = [];
|
||
const maxDataPoints = 20;
|
||
|
||
// 生成模拟系统数据
|
||
function generateMockData() {
|
||
const base = 50;
|
||
const variation = 30;
|
||
return {
|
||
cpu: Math.floor(base + (Math.random() - 0.5) * variation),
|
||
gpu: Math.floor(base + (Math.random() - 0.5) * variation),
|
||
memory: Math.floor(base + (Math.random() - 0.5) * variation)
|
||
};
|
||
}
|
||
|
||
// 添加数据到历史记录
|
||
function addToHistory(type, value) {
|
||
switch(type) {
|
||
case 'cpu':
|
||
cpuHistoryData.push(value);
|
||
if (cpuHistoryData.length > maxDataPoints) cpuHistoryData.shift();
|
||
break;
|
||
case 'gpu':
|
||
gpuHistoryData.push(value);
|
||
if (gpuHistoryData.length > maxDataPoints) gpuHistoryData.shift();
|
||
break;
|
||
case 'memory':
|
||
memoryHistoryData.push(value);
|
||
if (memoryHistoryData.length > maxDataPoints) memoryHistoryData.shift();
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 创建CPU图表
|
||
const cpuCtx = document.getElementById('cpuChart').getContext('2d');
|
||
const cpuChart = new Chart(cpuCtx, {
|
||
...chartConfig,
|
||
data: {
|
||
labels: Array.from({length: maxDataPoints}, (_, i) => i),
|
||
datasets: [{
|
||
label: 'CPU',
|
||
data: new Array(maxDataPoints).fill(0),
|
||
borderColor: '#EF4444',
|
||
backgroundColor: 'rgba(239, 68, 68, 0.1)',
|
||
fill: true
|
||
}]
|
||
}
|
||
});
|
||
|
||
// 创建GPU图表
|
||
const gpuCtx = document.getElementById('gpuChart').getContext('2d');
|
||
const gpuChart = new Chart(gpuCtx, {
|
||
...chartConfig,
|
||
data: {
|
||
labels: Array.from({length: maxDataPoints}, (_, i) => i),
|
||
datasets: [{
|
||
label: 'GPU',
|
||
data: new Array(maxDataPoints).fill(0),
|
||
borderColor: '#10B981',
|
||
backgroundColor: 'rgba(16, 185, 129, 0.1)',
|
||
fill: true
|
||
}]
|
||
}
|
||
});
|
||
|
||
// 创建内存图表
|
||
const memoryCtx = document.getElementById('memoryChart').getContext('2d');
|
||
const memoryChart = new Chart(memoryCtx, {
|
||
...chartConfig,
|
||
data: {
|
||
labels: Array.from({length: maxDataPoints}, (_, i) => i),
|
||
datasets: [{
|
||
label: 'Memory',
|
||
data: new Array(maxDataPoints).fill(0),
|
||
borderColor: '#3B82F6',
|
||
backgroundColor: 'rgba(59, 130, 246, 0.1)',
|
||
fill: true
|
||
}]
|
||
}
|
||
});
|
||
|
||
// 更新图表数据
|
||
function updateCharts() {
|
||
// 确保数据长度一致
|
||
while (cpuHistoryData.length < maxDataPoints) {
|
||
cpuHistoryData.unshift(0);
|
||
gpuHistoryData.unshift(0);
|
||
memoryHistoryData.unshift(0);
|
||
}
|
||
|
||
// 更新图表数据
|
||
cpuChart.data.datasets[0].data = cpuHistoryData;
|
||
gpuChart.data.datasets[0].data = gpuHistoryData;
|
||
memoryChart.data.datasets[0].data = memoryHistoryData;
|
||
|
||
// 刷新图表
|
||
cpuChart.update('none');
|
||
gpuChart.update('none');
|
||
memoryChart.update('none');
|
||
}
|
||
|
||
// 初始化并开始模拟监控
|
||
function initSystemMonitoring() {
|
||
// 生成初始数据
|
||
for (let i = 0; i < maxDataPoints; i++) {
|
||
const data = generateMockData();
|
||
addToHistory('cpu', data.cpu);
|
||
addToHistory('gpu', data.gpu);
|
||
addToHistory('memory', data.memory);
|
||
}
|
||
|
||
// 设置定期更新
|
||
setInterval(() => {
|
||
const data = generateMockData();
|
||
|
||
// 更新百分比显示
|
||
document.getElementById('cpuPercent').textContent = data.cpu + '%';
|
||
document.getElementById('gpuPercent').textContent = data.gpu + '%';
|
||
document.getElementById('memoryPercent').textContent = data.memory + '%';
|
||
|
||
// 添加到历史数据
|
||
addToHistory('cpu', data.cpu);
|
||
addToHistory('gpu', data.gpu);
|
||
addToHistory('memory', data.memory);
|
||
|
||
// 更新图表
|
||
updateCharts();
|
||
}, 2000); // 每2秒更新一次
|
||
}
|
||
|
||
// 页面加载完成后启动监控
|
||
document.addEventListener('DOMContentLoaded', initSystemMonitoring);
|
||
</script>
|
||
|
||
<script>
|
||
// 页面导航功能
|
||
function switchPage(pageId) {
|
||
// 隐藏所有页面
|
||
const allPages = document.querySelectorAll('.page-content');
|
||
allPages.forEach(page => {
|
||
page.classList.add('hidden');
|
||
});
|
||
|
||
// 显示选中的页面
|
||
const targetPage = document.getElementById(pageId + '-page');
|
||
if (targetPage) {
|
||
targetPage.classList.remove('hidden');
|
||
}
|
||
|
||
// 更新侧边栏激活状态
|
||
const navItems = document.querySelectorAll('.nav-item');
|
||
navItems.forEach(item => {
|
||
item.classList.remove('gradient-blue', 'text-white');
|
||
item.classList.add('hover:bg-dashboard-primary/10', 'text-dashboard-textLight');
|
||
});
|
||
|
||
// 激活当前页面
|
||
const activeItem = document.querySelector(`[data-page="${pageId}"]`);
|
||
if (activeItem) {
|
||
activeItem.classList.remove('hover:bg-dashboard-primary/10', 'text-dashboard-textLight');
|
||
activeItem.classList.add('gradient-blue', 'text-white');
|
||
}
|
||
}
|
||
|
||
// 初始化导航
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
// 默认显示仪表盘
|
||
switchPage('dashboard');
|
||
|
||
// 为所有导航项添加点击事件
|
||
const navItems = document.querySelectorAll('.nav-item');
|
||
navItems.forEach(item => {
|
||
item.addEventListener('click', function(e) {
|
||
e.preventDefault();
|
||
const pageId = this.getAttribute('data-page');
|
||
switchPage(pageId);
|
||
});
|
||
});
|
||
});
|
||
|
||
// 修改 switchPage 函数以支持数据集页面加载
|
||
const originalSwitchPage = switchPage;
|
||
switchPage = function(pageId) {
|
||
originalSwitchPage(pageId);
|
||
// 如果切换到数据集页面,加载数据集列表
|
||
if (pageId === 'dataset') {
|
||
loadDatasets();
|
||
}
|
||
};
|
||
|
||
// 数据集管理相关功能
|
||
const API_BASE = 'http://localhost:3000/api';
|
||
|
||
// 加载数据集列表
|
||
async function loadDatasets() {
|
||
try {
|
||
const response = await fetch(`${API_BASE}/datasets`);
|
||
const result = await response.json();
|
||
|
||
// 适配StandardResponse格式: {status: 1, response: {...}}
|
||
if (result.status === 1 && result.response && result.response.datasets) {
|
||
renderDatasetList(result.response.datasets);
|
||
} else if (result.status === 0) {
|
||
console.error('加载数据集列表失败:', result.response?.error || '未知错误');
|
||
}
|
||
} catch (error) {
|
||
console.error('加载数据集列表失败:', error);
|
||
}
|
||
}
|
||
|
||
// 渲染数据集列表
|
||
function renderDatasetList(datasets) {
|
||
const container = document.getElementById('datasetList');
|
||
if (!container) return;
|
||
|
||
container.innerHTML = '';
|
||
|
||
datasets.forEach(dataset => {
|
||
const statusClass = getStatusClass(dataset.status);
|
||
const statusText = dataset.status;
|
||
|
||
const datasetDiv = document.createElement('div');
|
||
datasetDiv.className = 'border border-dashboard-bg rounded-lg p-4 hover:shadow-md transition-shadow';
|
||
datasetDiv.innerHTML = `
|
||
<div class="flex justify-between items-center">
|
||
<div>
|
||
<h3 class="font-medium text-dashboard-text">${dataset.name}</h3>
|
||
<p class="text-sm text-dashboard-textLight mt-1">${dataset.size_display || dataset.size_mb + ' MB' || '未知大小'} • ${dataset.description || '无描述'}</p>
|
||
</div>
|
||
<div class="flex items-center space-x-2">
|
||
<span class="px-2 py-1 ${statusClass} text-xs rounded">${statusText}</span>
|
||
<button onclick="viewDatasetDetails('${dataset.file_id}')" class="text-dashboard-primary hover:underline text-sm">查看详情</button>
|
||
<button onclick="deleteDataset('${dataset.file_id}', '${dataset.name}')" class="text-red-500 hover:text-red-700 text-sm">删除</button>
|
||
</div>
|
||
</div>
|
||
`;
|
||
container.appendChild(datasetDiv);
|
||
});
|
||
}
|
||
|
||
// 获取状态样式类
|
||
function getStatusClass(status) {
|
||
switch(status) {
|
||
case '已处理':
|
||
return 'bg-green-100 text-green-600';
|
||
case '处理中':
|
||
return 'bg-blue-100 text-blue-600';
|
||
case '待处理':
|
||
return 'bg-gray-100 text-gray-600';
|
||
default:
|
||
return 'bg-gray-100 text-gray-600';
|
||
}
|
||
}
|
||
|
||
// 查看数据集详情
|
||
// 处理文件上传
|
||
async function handleFileUpload(input) {
|
||
const file = input.files[0];
|
||
if (!file) return;
|
||
|
||
// 检查文件类型
|
||
const allowedTypes = ['.json', '.jsonl'];
|
||
const fileExtension = '.' + file.name.split('.').pop().toLowerCase();
|
||
|
||
if (!allowedTypes.includes(fileExtension)) {
|
||
alert('只支持 JSON 和 JSONL 格式的文件!');
|
||
input.value = '';
|
||
return;
|
||
}
|
||
|
||
// 检查文件大小 (100MB)
|
||
const maxSize = 100 * 1024 * 1024;
|
||
if (file.size > maxSize) {
|
||
alert('文件大小不能超过 100MB!');
|
||
input.value = '';
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const formData = new FormData();
|
||
formData.append('file', file);
|
||
formData.append('description', `用户上传的数据集文件: ${file.name}`);
|
||
|
||
const response = await fetch(`${API_BASE}/datasets/upload`, {
|
||
method: 'POST',
|
||
body: formData
|
||
});
|
||
|
||
const result = await response.json();
|
||
|
||
// 适配StandardResponse格式: {status: 1, response: {...}}
|
||
if (result.status === 1) {
|
||
alert('上传成功!');
|
||
// 重新加载数据集列表
|
||
loadDatasets();
|
||
} else {
|
||
const errorMsg = result.response?.error || result.message || '未知错误';
|
||
alert('上传失败: ' + errorMsg);
|
||
}
|
||
} catch (error) {
|
||
console.error('上传失败:', error);
|
||
alert('上传失败: 网络错误');
|
||
}
|
||
|
||
// 清空文件选择
|
||
input.value = '';
|
||
}
|
||
|
||
// 退出登录函数
|
||
function logout() {
|
||
// 清除登录状态
|
||
sessionStorage.removeItem('isLoggedIn');
|
||
// 跳转到登录页面
|
||
window.location.href = 'login.html';
|
||
}
|
||
|
||
// 查看数据集详情
|
||
async function viewDatasetDetails(fileId) {
|
||
try {
|
||
// 调用API获取文件内容
|
||
const response = await fetch(`${API_BASE}/datasets/${fileId}/content?limit=5`);
|
||
const result = await response.json();
|
||
|
||
if (result.status === 1) {
|
||
const data = result.response;
|
||
let contentHtml = '';
|
||
|
||
if (Array.isArray(data.preview)) {
|
||
// 如果是数组,显示前5条记录
|
||
contentHtml = '<div style="max-height: 400px; overflow-y: auto;"><pre>' +
|
||
JSON.stringify(data.preview, null, 2) +
|
||
'</pre></div>';
|
||
} else {
|
||
// 如果是对象,直接显示
|
||
contentHtml = '<div style="max-height: 400px; overflow-y: auto;"><pre>' +
|
||
JSON.stringify(data.preview, null, 2) +
|
||
'</pre></div>';
|
||
}
|
||
|
||
// 显示模态框
|
||
showDatasetModal(data.filename, contentHtml);
|
||
} else {
|
||
alert('获取文件内容失败: ' + (result.response?.error || '未知错误'));
|
||
}
|
||
} catch (error) {
|
||
console.error('获取文件详情失败:', error);
|
||
alert('获取文件详情失败: 网络错误');
|
||
}
|
||
}
|
||
|
||
// 显示数据集详情模态框
|
||
function showDatasetModal(title, content) {
|
||
const modal = document.createElement('div');
|
||
modal.style.cssText = `
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background: rgba(0, 0, 0, 0.5);
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
z-index: 10000;
|
||
`;
|
||
|
||
const modalContent = document.createElement('div');
|
||
modalContent.style.cssText = `
|
||
background: white;
|
||
padding: 20px;
|
||
border-radius: 8px;
|
||
max-width: 800px;
|
||
max-height: 600px;
|
||
overflow: hidden;
|
||
display: flex;
|
||
flex-direction: column;
|
||
`;
|
||
|
||
const modalHeader = document.createElement('div');
|
||
modalHeader.style.cssText = `
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 15px;
|
||
border-bottom: 1px solid #eee;
|
||
padding-bottom: 10px;
|
||
`;
|
||
|
||
const titleElement = document.createElement('h3');
|
||
titleElement.textContent = title;
|
||
titleElement.style.cssText = 'margin: 0; color: #333;';
|
||
|
||
const closeButton = document.createElement('button');
|
||
closeButton.textContent = '×';
|
||
closeButton.style.cssText = `
|
||
background: none;
|
||
border: none;
|
||
font-size: 24px;
|
||
cursor: pointer;
|
||
color: #666;
|
||
width: 30px;
|
||
height: 30px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border-radius: 4px;
|
||
`;
|
||
closeButton.onmouseover = () => closeButton.style.background = '#f0f0f0';
|
||
closeButton.onmouseout = () => closeButton.style.background = 'none';
|
||
|
||
const closeModal = () => {
|
||
document.body.removeChild(modal);
|
||
};
|
||
|
||
closeButton.onclick = closeModal;
|
||
modal.onclick = (e) => {
|
||
if (e.target === modal) closeModal();
|
||
};
|
||
|
||
modalHeader.appendChild(titleElement);
|
||
modalHeader.appendChild(closeButton);
|
||
|
||
const contentDiv = document.createElement('div');
|
||
contentDiv.innerHTML = content;
|
||
|
||
modalContent.appendChild(modalHeader);
|
||
modalContent.appendChild(contentDiv);
|
||
|
||
modal.appendChild(modalContent);
|
||
document.body.appendChild(modal);
|
||
}
|
||
|
||
// 删除数据集
|
||
async function deleteDataset(fileId, filename) {
|
||
// 确认删除对话框
|
||
const confirmMessage = `确定要删除数据集 "${filename}" 吗?\n\n此操作不可撤销!`;
|
||
|
||
if (!confirm(confirmMessage)) {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const response = await fetch(`${API_BASE}/datasets/${fileId}`, {
|
||
method: 'DELETE'
|
||
});
|
||
|
||
const result = await response.json();
|
||
|
||
if (result.status === 1) {
|
||
alert('删除成功!');
|
||
// 重新加载数据集列表
|
||
loadDatasets();
|
||
} else {
|
||
alert('删除失败: ' + (result.response?.error || '未知错误'));
|
||
}
|
||
} catch (error) {
|
||
console.error('删除失败:', error);
|
||
alert('删除失败: 网络错误');
|
||
}
|
||
}
|
||
</script>
|
||
|
||
</body>
|
||
</html>
|