From c9575b255387f6c863f4ea06bf675000834941ad Mon Sep 17 00:00:00 2001 From: "WIN-JHFT4D3SIVT\\caoxiaozhu" Date: Fri, 30 Jan 2026 21:03:09 +0800 Subject: [PATCH] =?UTF-8?q?1.=20main.html=20=E9=A1=B5=E9=9D=A2=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=EF=BC=8C=E6=8B=86=E8=A7=A3=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/pages/hardware.html | 479 +++++++ web/pages/logs.html | 434 ++++++ web/pages/main.html | 1898 +-------------------------- web/pages/model-compare-create.html | 35 +- web/pages/model-manage.html | 1470 ++++++++++----------- web/pages/tools.html | 373 ++++++ 6 files changed, 2120 insertions(+), 2569 deletions(-) create mode 100644 web/pages/hardware.html create mode 100644 web/pages/logs.html create mode 100644 web/pages/tools.html diff --git a/web/pages/hardware.html b/web/pages/hardware.html new file mode 100644 index 0000000..5e56e2a --- /dev/null +++ b/web/pages/hardware.html @@ -0,0 +1,479 @@ + + + + + + 平台性能 - 远光软件微调平台 + + + + + + + + + + +
+
+ +
+ +
+ +
+
+

平台性能

+
+ + 刷新频率: + +
+
+
+ +
+ +
+
+
+
+ +
+
+

CPU 使用率

+

4 核心

+
+
+
+ 0% +
+
+
+
+
+
+
+
核心1
+
0%
+
+
+
核心2
+
0%
+
+
+
核心3
+
0%
+
+
+
核心4
+
0%
+
+
+
+ + +
+
+
+
+ +
+
+

内存使用

+

总计: 16 GB

+
+
+
+ 0% +
+
+
+
+
+
+
+
已用
+
0 GB
+
+
+
可用
+
0 GB
+
+
+
缓存
+
0 GB
+
+
+
+ + +
+
+
+
+ +
+
+

磁盘使用

+

SSD 512 GB

+
+
+
+ 0% +
+
+
+
+
+
+
+
已用空间
+
0 GB
+
+
+
可用空间
+
0 GB
+
+
+
读写速度
+
0 MB/s
+
+
+
+
+ + +
+
+
+ +
+
+

GPU监控

+

检测中...

+
+
+
+ +
+
+ + +
+
+
+ +
+
+

系统信息

+

服务器状态

+
+
+
+
+ 操作系统 + Ubuntu 22.04 LTS +
+
+ 运行时间 + 0 天 0 时 0 分 +
+
+ 进程数 + 0 +
+
+ 负载均值 + 0.00, 0.00, 0.00 +
+
+
+
+
+
+ + + + + + diff --git a/web/pages/logs.html b/web/pages/logs.html new file mode 100644 index 0000000..3b7a26f --- /dev/null +++ b/web/pages/logs.html @@ -0,0 +1,434 @@ + + + + + + 查看日志 - 远光软件微调平台 + + + + + + + + + + +
+
+ +
+ +
+ +
+
+

系统日志

+
+ +
+
+
+ +
+
+ + +
+
+ + +
+ +
+
+ + +
+ + +
+
+ 请选择日志文件 +
+ + + +
+
+
日志内容将在这里显示...
+
+
+
+
+
+ + + + diff --git a/web/pages/main.html b/web/pages/main.html index 024c26a..107ed52 100644 --- a/web/pages/main.html +++ b/web/pages/main.html @@ -17,165 +17,16 @@ } + + + + + + + + - + @@ -233,7 +84,7 @@ - ${config.api === 'model-manage/trained-models' ? ` + ${config.hasModelTabs ? `
+ + +
+ ` : ''} ${supportsMultiSelect ? `
@@ -1442,1006 +1258,17 @@ `; } - // 渲染日志查看页面 - function renderLogViewerPage(config) { - return ` -
-
-

${config.title}

-
- -
-
-
- -
-
- - -
-
- - -
- -
-
- - -
-
- - -
- -
- -
- - -
-
- - - - - -
-
- 请选择日志文件 -
- - - -
-
-
日志内容将在这里显示...
-
-
-
- `; - } - - // 当前日志类型:system 或 training - let currentLogTab = 'system'; - - // 切换日志类型标签 - function switchLogTab(tab) { - currentLogTab = tab; - const systemTab = document.getElementById('logTabSystem'); - const trainingTab = document.getElementById('logTabTraining'); - const systemOptions = document.getElementById('systemLogOptions'); - const trainingOptions = document.getElementById('trainingLogOptions'); - - if (tab === 'system') { - systemTab.className = 'px-4 py-1.5 text-sm rounded-md transition-colors bg-white shadow-sm text-primary'; - trainingTab.className = 'px-4 py-1.5 text-sm rounded-md transition-colors text-gray-600 hover:text-gray-800'; - systemOptions.classList.remove('hidden'); - trainingOptions.classList.add('hidden'); - loadLogFiles(); - } else { - trainingTab.className = 'px-4 py-1.5 text-sm rounded-md transition-colors bg-white shadow-sm text-primary'; - systemTab.className = 'px-4 py-1.5 text-sm rounded-md transition-colors text-gray-600 hover:text-gray-800'; - trainingOptions.classList.remove('hidden'); - systemOptions.classList.add('hidden'); - loadTrainingLogFiles(); - } - } - - // 初始化日志查看器 - function initLogViewer() { - const datePicker = document.getElementById('logDatePicker'); - if (datePicker) { - const today = new Date().toISOString().split('T')[0]; - datePicker.value = today; - } - // 加载默认日志类型 - loadLogFiles(); - // 启动自动刷新 - setRefreshInterval(); - } - - // 加载训练日志文件列表 - async function loadTrainingLogFiles() { - const logSelect = document.getElementById('trainingLogSelect'); - if (!logSelect) return; - - logSelect.innerHTML = ''; - - try { - const response = await fetch(`${API_BASE}/training-log-files`); - const result = await response.json(); - - if (result.code === 0 && result.data) { - logSelect.innerHTML = ''; - result.data.forEach(log => { - const option = document.createElement('option'); - option.value = log.file; - option.textContent = `${log.name} (PID: ${log.pid}, ${log.date}, ${log.size})`; - logSelect.appendChild(option); - }); - // 如果有日志文件,自动加载第一个 - if (result.data.length > 0) { - logSelect.value = result.data[0].file; - loadSelectedTrainingLog(); - } else { - document.getElementById('logContent').textContent = '暂无训练日志'; - document.getElementById('logFileInfo').textContent = '无训练日志'; - } - } else { - logSelect.innerHTML = ''; - document.getElementById('logContent').textContent = '暂无训练日志'; - document.getElementById('logFileInfo').textContent = '无训练日志'; - } - } catch (error) { - console.error('加载训练日志列表失败:', error); - logSelect.innerHTML = ''; - document.getElementById('logContent').textContent = '加载训练日志列表失败: ' + error.message; - } - } - - // 加载选中的训练日志 - async function loadSelectedTrainingLog() { - const logSelect = document.getElementById('trainingLogSelect'); - const logFile = logSelect.value; - const logContent = document.getElementById('logContent'); - const logFileInfo = document.getElementById('logFileInfo'); - - if (!logFile) { - logContent.textContent = '请选择训练日志'; - logFileInfo.textContent = '无训练日志'; - return; - } - - logContent.textContent = '加载中...'; - logFileInfo.textContent = '加载中...'; - - try { - const response = await fetch(`${API_BASE}/training-log-content?file=${encodeURIComponent(logFile)}`); - const result = await response.json(); - - if (result.code === 0 && result.data) { - logFullContent = result.data.content || ''; - logContent.textContent = logFullContent || '(空日志)'; - logFileInfo.textContent = result.data.file + ' (' + result.data.size + ')'; - // 清空搜索 - document.getElementById('logSearchInput').value = ''; - document.getElementById('logMatchCount').textContent = ''; - // 滚动到底部 - scrollToLogBottom(); - } else { - logContent.textContent = '加载失败: ' + (result.message || '未知错误'); - logFileInfo.textContent = '加载失败'; - } - } catch (error) { - console.error('加载训练日志内容失败:', error); - logContent.textContent = '加载失败: ' + error.message; - logFileInfo.textContent = '加载失败'; - } - } - - // 加载日志文件列表 - async function loadLogFiles() { - const datePicker = document.getElementById('logDatePicker'); - const logTypeSelect = document.getElementById('logTypeSelect'); - const selectedDate = datePicker ? datePicker.value : new Date().toISOString().split('T')[0]; - - if (!logTypeSelect) return; - logTypeSelect.innerHTML = ''; - - try { - const response = await fetch(`${API_BASE}/log-files?date=${selectedDate}`); - const result = await response.json(); - - if (result.code === 0 && result.data) { - logTypeSelect.innerHTML = ''; - result.data.forEach(log => { - const option = document.createElement('option'); - option.value = log.file; - option.textContent = log.name + ' (' + log.size + ')'; - logTypeSelect.appendChild(option); - }); - // 如果有日志文件,自动加载第一个 - if (result.data.length > 0) { - logTypeSelect.value = result.data[0].file; - loadSelectedLog(); - } else { - logTypeSelect.innerHTML = ''; - document.getElementById('logContent').textContent = '该日期暂无日志文件'; - document.getElementById('logFileInfo').textContent = '无日志文件'; - } - } else { - logTypeSelect.innerHTML = ''; - document.getElementById('logContent').textContent = '该日期暂无日志文件'; - document.getElementById('logFileInfo').textContent = '无日志文件'; - } - } catch (error) { - console.error('加载日志文件列表失败:', error); - logTypeSelect.innerHTML = ''; - document.getElementById('logContent').textContent = '加载日志文件列表失败: ' + error.message; - } - } - - // 加载选中的日志 - async function loadSelectedLog() { - const logTypeSelect = document.getElementById('logTypeSelect'); - const logFile = logTypeSelect.value; - const logContent = document.getElementById('logContent'); - const logFileInfo = document.getElementById('logFileInfo'); - - if (!logFile) { - logContent.textContent = '请选择日志文件'; - logFileInfo.textContent = '无日志文件'; - return; - } - - logContent.textContent = '加载中...'; - logFileInfo.textContent = '加载中...'; - - try { - const response = await fetch(`${API_BASE}/log-content?file=${encodeURIComponent(logFile)}`); - const result = await response.json(); - - if (result.code === 0) { - logFullContent = result.data.content || ''; - logContent.textContent = logFullContent || '(空日志)'; - logFileInfo.textContent = result.data.file + ' (' + result.data.size + ')'; - // 清空搜索框和匹配计数 - document.getElementById('logSearchInput').value = ''; - document.getElementById('logMatchCount').textContent = ''; - // 滚动到最底部 - scrollToLogBottom(); - } else { - logContent.textContent = '加载失败: ' + (result.message || '未知错误'); - logFileInfo.textContent = '加载失败'; - } - } catch (error) { - console.error('加载日志内容失败:', error); - logContent.textContent = '加载日志内容失败: ' + error.message; - logFileInfo.textContent = '加载失败'; - } - } - - // 刷新日志 - function refreshLogs() { - if (currentLogTab === 'system') { - loadLogFiles(); - if (document.getElementById('logTypeSelect').value) { - loadSelectedLog(); - } - } else { - loadTrainingLogFiles(); - } - // 重置倒计时 - const select = document.getElementById('logRefreshInterval'); - const secondsEl = document.getElementById('countdownNumber'); - if (select && select.value !== '0' && secondsEl) { - secondsEl.textContent = logCurrentInterval; - } - } - - // 停止日志自动刷新(离开页面时调用) - function stopLogAutoRefresh() { - if (logRefreshTimer) { - clearInterval(logRefreshTimer); - logRefreshTimer = null; - } - if (logCountdownTimer) { - clearInterval(logCountdownTimer); - logCountdownTimer = null; - } - } - - // 滚动到日志底部 - function scrollToLogBottom() { - const logContent = document.getElementById('logContent'); - if (logContent) { - logContent.scrollTop = logContent.scrollHeight; - } - } - - // 过滤日志内容 - function filterLogContent() { - const searchInput = document.getElementById('logSearchInput'); - const matchCount = document.getElementById('logMatchCount'); - const logContent = document.getElementById('logContent'); - - if (!searchInput || !matchCount || !logContent) return; - - const keyword = searchInput.value.trim(); - - if (!keyword) { - logContent.textContent = logFullContent || '(空日志)'; - matchCount.textContent = ''; - scrollToLogBottom(); - return; - } - - const lines = logFullContent.split('\n'); - const matchingLines = lines.filter(line => line.toLowerCase().includes(keyword.toLowerCase())); - - if (matchingLines.length > 0) { - logContent.textContent = matchingLines.join('\n'); - matchCount.textContent = `(${matchingLines.length}条匹配)`; - // 滚动到最底部查看最新匹配 - scrollToLogBottom(); - } else { - logContent.textContent = '未找到匹配的日志'; - matchCount.textContent = '(0条匹配)'; - } - } - - // 清空日志内容显示 - function clearLogContent() { - document.getElementById('logContent').textContent = '日志内容将在这里显示...'; - document.getElementById('logFileInfo').textContent = '请选择日志文件'; - document.getElementById('logTypeSelect').value = ''; - document.getElementById('logSearchInput').value = ''; - document.getElementById('logMatchCount').textContent = ''; - logFullContent = ''; + // 切换模型管理tab + function switchModelTab(tab) { + currentModelTab = tab; + // 清除选中状态 + clearSelection(); + // 重新加载模型管理页面 + loadPage('model-manage'); } // 渲染工具卡片页面 - function renderToolsPage(config) { - // 渲染单个工具卡片 - const renderToolCard = (tool, canDelete = false, isCustom = false) => ` -
-
- -
-

${tool.name}

-

${tool.description}

- ${canDelete ? ` - - - ` : ''} -
- `; - const defaultCards = config.defaultTools.map(t => renderToolCard(t, false, false)).join(''); - const customCards = config.customTools.map(t => renderToolCard(t, true, true)).join(''); - - return ` -
-
-

${config.title}

- -
-
- -

默认工具

-
- ${defaultCards || '

暂无默认工具

'} -
- - -

自定义工具

-
- ${customCards || '

暂无自定义工具,点击右上角添加

'} -
-
-
- `; - } - - // 删除自定义工具 - function deleteCustomTool(toolId) { - showConfirm('确认删除', '确定要删除这个自定义工具吗?', () => { - const config = tableConfigs['data-generate']; - config.customTools = config.customTools.filter(t => t.id !== toolId); - // 保存到 localStorage - localStorage.setItem('customTools', JSON.stringify(config.customTools)); - document.getElementById('page-content').innerHTML = renderToolsPage(config); - // 删除成功,无需额外弹窗提示 - }); - } - - // 修改自定义工具 - function editCustomTool(toolId) { - const config = tableConfigs['data-generate']; - const tool = config.customTools.find(t => t.id === toolId); - if (tool) { - // 将工具信息存储到 localStorage,编辑页面读取 - localStorage.setItem('editTool', JSON.stringify(tool)); - window.location.href = 'custom-tool-create.html?edit=true'; - } - } - - // 显示创建工具弹窗 - function showCreateToolModal() { - window.location.href = 'custom-tool-create.html'; - } - - // 跳转到工具页面 - function navigateToTool(toolId, url, isCustom = false) { - if (isCustom && url) { - // 自定义工具,使用配置的URL - if (url.startsWith('http')) { - window.open(url, '_blank'); - } else { - window.location.href = url; - } - } else if (toolId === 'data-generate') { - window.location.href = 'data-generate.html'; - } else if (toolId === 'json2jsonl') { - showMessage('提示', 'JSON转JSONL 工具开发中...', 'info'); - } else if (toolId === 'md-convert') { - showMessage('提示', '转换Markdown 工具开发中...', 'info'); - } else { - showMessage('提示', `${toolId} 功能开发中...`, 'info'); - } - } - - // 渲染配置页面(硬件监控) - function renderConfigPage(config, data) { - return ` -
-
-

${config.title}

-
- - 刷新频率: - -
-
-
- -
- -
-
-
-
- -
-
-

CPU 使用率

-

4 核心

-
-
-
- 0% -
-
- -
-
-
- -
-
-
核心1
-
0%
-
-
-
核心2
-
0%
-
-
-
核心3
-
0%
-
-
-
核心4
-
0%
-
-
-
- - -
-
-
-
- -
-
-

内存使用

-

总计: 16 GB

-
-
-
- 0% -
-
- -
-
-
- -
-
-
已用
-
0 GB
-
-
-
可用
-
0 GB
-
-
-
缓存
-
0 GB
-
-
-
- - -
-
-
-
- -
-
-

磁盘使用

-

SSD 512 GB

-
-
-
- 0% -
-
- -
-
-
- -
-
-
已用空间
-
0 GB
-
-
-
可用空间
-
0 GB
-
-
-
读写速度
-
0 MB/s
-
-
-
-
- - -
-
-
- -
-
-

GPU监控

-

多GPU并行监控

-
-
- -
- -
-
- - -
- -
-
-
- -
-
-

网络流量

-

实时带宽使用

-
-
-
-
-
- - 下载速度 -
-
0 MB/s
-
-
-
- - 上传速度 -
-
0 MB/s
-
-
-
- 总流入: 0 GB - 总流出: 0 GB -
-
- - -
-
-
- -
-
-

系统信息

-

服务器状态

-
-
-
-
- 操作系统 - Ubuntu 22.04 LTS -
-
- 运行时间 - 0 天 0 时 0 分 -
-
- 进程数 - 0 -
-
- 负载均值 - 0.00, 0.00, 0.00 -
-
-
-
-
-
- `; - } - - // 刷新间隔定时器 - let refreshTimer = null; - let currentRefreshInterval = 5000; - - // 刷新硬件信息(使用真实API) - async function refreshHardwareInfo() { - try { - const response = await fetch(`${API_BASE}/system-info`); - const result = await response.json(); - - if (result.code === 0 && result.data) { - const data = result.data; - - // 更新CPU - const cpu = data.cpu || {}; - const cpuPercent = cpu.percent || 0; - document.getElementById('cpuPercent').textContent = cpuPercent + '%'; - document.getElementById('cpuBar').style.width = cpuPercent + '%'; - document.getElementById('cpuCores').textContent = (cpu.cores || 0) + ' 核心'; - - // 更新内存 - const mem = data.memory || {}; - const memUsed = mem.used_gb || 0; - const memTotal = mem.total_gb || 0; - const memPercent = mem.percent || 0; - document.getElementById('memoryPercent').textContent = memPercent + '%'; - document.getElementById('memoryBar').style.width = memPercent + '%'; - document.getElementById('memoryUsed').textContent = memUsed + ' GB'; - document.getElementById('memoryAvailable').textContent = (mem.available_gb || 0) + ' GB'; - document.getElementById('memoryCached').textContent = (mem.cached_gb || 0) + ' GB'; - - // 更新磁盘 - const disk = data.disk || {}; - const diskUsed = disk.used_gb || 0; - const diskTotal = disk.total_gb || 0; - const diskPercent = disk.percent || 0; - document.getElementById('diskPercent').textContent = diskPercent + '%'; - document.getElementById('diskBar').style.width = diskPercent + '%'; - document.getElementById('diskUsed').textContent = diskUsed + ' GB'; - document.getElementById('diskAvailable').textContent = (diskTotal - diskUsed) + ' GB'; - - // 更新网络 - const net = data.network || {}; - document.getElementById('totalDownload').textContent = (net.download_mb || 0) + ' GB'; - document.getElementById('totalUpload').textContent = (net.upload_mb || 0) + ' GB'; - - // 更新系统信息 - const sys = data.system || {}; - const uptime = sys.uptime_seconds || 0; - const days = Math.floor(uptime / 86400); - const hours = Math.floor((uptime % 86400) / 3600); - const mins = Math.floor((uptime % 3600) / 60); - document.getElementById('uptime').textContent = days + ' 天 ' + hours + ' 时 ' + mins + ' 分'; - document.getElementById('processCount').textContent = sys.process_count || 0; - - // 更新GPU信息(传入真实数据) - updateGPUInfo(data.gpu || []); - } - } catch (error) { - console.error('获取系统信息失败:', error); - // 如果API调用失败,使用模拟数据作为后备 - useMockData(); - } - } - - // 使用模拟数据(当API不可用时) - function useMockData() { - // 更新CPU - const cpuUsage = Math.floor(Math.random() * 30) + 20; - document.getElementById('cpuPercent').textContent = cpuUsage + '%'; - document.getElementById('cpuBar').style.width = cpuUsage + '%'; - document.getElementById('core1').textContent = Math.floor(Math.random() * 40 + 20) + '%'; - document.getElementById('core2').textContent = Math.floor(Math.random() * 40 + 15) + '%'; - document.getElementById('core3').textContent = Math.floor(Math.random() * 40 + 25) + '%'; - document.getElementById('core4').textContent = Math.floor(Math.random() * 40 + 10) + '%'; - - // 更新内存 - const memUsed = (Math.random() * 4 + 6).toFixed(1); - const memTotal = 16; - const memPercent = Math.floor((memUsed / memTotal) * 100); - document.getElementById('memoryPercent').textContent = memPercent + '%'; - document.getElementById('memoryBar').style.width = memPercent + '%'; - document.getElementById('memoryUsed').textContent = memUsed + ' GB'; - document.getElementById('memoryAvailable').textContent = (memTotal - memUsed).toFixed(1) + ' GB'; - document.getElementById('memoryCached').textContent = (Math.random() * 3 + 1).toFixed(1) + ' GB'; - - // 更新磁盘 - const diskUsed = Math.floor(Math.random() * 100 + 150); - const diskTotal = 512; - const diskPercent = Math.floor((diskUsed / diskTotal) * 100); - document.getElementById('diskPercent').textContent = diskPercent + '%'; - document.getElementById('diskBar').style.width = diskPercent + '%'; - document.getElementById('diskUsed').textContent = diskUsed + ' GB'; - document.getElementById('diskAvailable').textContent = (diskTotal - diskUsed) + ' GB'; - document.getElementById('diskSpeed').textContent = (Math.random() * 500 + 100).toFixed(0) + ' MB/s'; - - // 更新多GPU信息 - updateGPUInfo(); - - // 更新网络 - document.getElementById('downloadSpeed').textContent = (Math.random() * 100 + 10).toFixed(1) + ' MB/s'; - document.getElementById('uploadSpeed').textContent = (Math.random() * 50 + 5).toFixed(1) + ' MB/s'; - document.getElementById('totalDownload').textContent = (Math.random() * 500 + 100).toFixed(1) + ' GB'; - document.getElementById('totalUpload').textContent = (Math.random() * 200 + 50).toFixed(1) + ' GB'; - - // 更新系统信息 - const days = Math.floor(Math.random() * 30); - const hours = Math.floor(Math.random() * 24); - const mins = Math.floor(Math.random() * 60); - document.getElementById('uptime').textContent = days + ' 天 ' + hours + ' 时 ' + mins + ' 分'; - document.getElementById('processCount').textContent = Math.floor(Math.random() * 200 + 100); - document.getElementById('loadAvg').textContent = (Math.random() * 2).toFixed(2) + ', ' + (Math.random() * 1.5).toFixed(2) + ', ' + (Math.random() * 1).toFixed(2); - } - - // GPU配置 - 支持模拟1-8块GPU - const GPU_COUNT = 4; // 可配置GPU数量 - const gpuConfigs = [ - { name: 'NVIDIA RTX 3090', memory: 24 }, - { name: 'NVIDIA RTX 4090', memory: 24 }, - { name: 'NVIDIA A100', memory: 80 }, - { name: 'NVIDIA V100', memory: 32 }, - { name: 'NVIDIA T4', memory: 16 }, - { name: 'NVIDIA L40S', memory: 48 }, - { name: 'NVIDIA H100', memory: 80 }, - { name: 'NVIDIA RTX 4080', memory: 16 } - ]; - - // 初始化GPU列表(获取真实数据) - async function initGPUList() { - try { - const response = await fetch(`${API_BASE}/system-info`); - const result = await response.json(); - const gpuData = (result.data && result.data.gpu) || []; - updateGPUInfo(gpuData); - } catch (error) { - console.error('初始化GPU列表失败:', error); - useMockGPUData(); - } - } - - // 更新GPU信息 - function updateGPUInfo(gpuData) { - // 如果有真实数据,使用真实数据 - if (gpuData && gpuData.length > 0) { - const gpuCount = gpuData.length; - document.getElementById('gpuCount').textContent = `检测到 ${gpuCount} 块 GPU`; - - let totalUsedMemory = 0; - let totalMemory = 0; - - // 重新初始化GPU列表 - const gpuList = document.getElementById('gpuList'); - if (gpuList) { - let gpuCardsHTML = ''; - for (let i = 0; i < gpuCount; i++) { - const gpu = gpuData[i]; - totalUsedMemory += gpu.memory_used_gb; - totalMemory += gpu.memory_total_gb; - - gpuCardsHTML += ` -
-
-
-
- -
-
-
${gpu.name}
-
PCIe
-
-
-
- ${gpu.gpu_percent}% -
-
-
-
-
-
-
-
显存
-
${gpu.memory_used_gb}/${gpu.memory_total_gb} GB
-
-
-
温度
-
${gpu.temperature}°C
-
-
-
功耗
-
${gpu.power_w} W
-
-
-
Fan
-
${gpu.fan_speed || 0}%
-
-
-
-
Clock: ${gpu.clock_mhz || 0} MHz
-
Driver: ${gpu.driver_version || '-'}
-
-
- `; - } - gpuList.innerHTML = gpuCardsHTML; - } - - // 更新总显存 - const gpuTotalMem = document.getElementById('gpuTotalMemory'); - if (gpuTotalMem) { - gpuTotalMem.textContent = `${totalUsedMemory}/${totalMemory} GB`; - } - return; - } - - // 没有真实数据,使用模拟数据 - useMockGPUData(); - } - - // 使用模拟GPU数据 - function useMockGPUData() { - const gpuCount = Math.min(GPU_COUNT, 8); - let totalUsedMemory = 0; - let totalMemory = 0; - - // 重新初始化GPU列表 - const gpuList = document.getElementById('gpuList'); - if (gpuList) { - let gpuCardsHTML = ''; - for (let i = 0; i < gpuCount; i++) { - const config = gpuConfigs[i % gpuConfigs.length]; - const gpuUsage = Math.floor(Math.random() * 60 + 20); - const memUsed = (Math.random() * config.memory * 0.7 + config.memory * 0.1).toFixed(1); - const temp = Math.floor(Math.random() * 30 + 40); - const power = Math.floor(Math.random() * 150 + 100); - const fan = Math.floor(gpuUsage + Math.random() * 10); - - totalUsedMemory += parseFloat(memUsed); - totalMemory += config.memory; - - gpuCardsHTML += ` -
-
-
-
- -
-
-
${config.name}
-
PCIe ${Math.floor(Math.random() * 4 + 1)}:00.0
-
-
-
- ${gpuUsage}% -
-
-
-
-
-
-
-
显存
-
${parseFloat(memUsed).toFixed(1)}/${config.memory} GB
-
-
-
温度
-
${temp}°C
-
-
-
功耗
-
${power} W
-
-
-
Fan
-
${fan}%
-
-
-
- `; - } - gpuList.innerHTML = gpuCardsHTML; - document.getElementById('gpuCount').textContent = `检测到 ${gpuCount} 块 GPU`; - } - - // 更新总显存 - const gpuTotalMem = document.getElementById('gpuTotalMemory'); - if (gpuTotalMem) { - gpuTotalMem.textContent = `${totalUsedMemory.toFixed(1)}/${totalMemory} GB`; - } - } - - // 启动硬件监控自动刷新 - function startRefreshTimer() { - if (refreshTimer) { - clearInterval(refreshTimer); - } - refreshTimer = setInterval(refreshHardwareInfo, currentRefreshInterval); - } - - // 改变刷新频率 - function changeRefreshRate() { - const select = document.getElementById('refreshInterval'); - currentRefreshInterval = parseInt(select.value); - startRefreshTimer(); - } - - // 页面加载后初始化并启动定时器 - document.addEventListener('DOMContentLoaded', function() { - // 只在平台性能页面初始化GPU列表 - const gpuCountEl = document.getElementById('gpuCount'); - if (gpuCountEl) { - initGPUList(); - startRefreshTimer(); - } - }); - - function saveConfig() { - showMessage('提示', '配置保存功能开发中...', 'info'); - } // 当前页面状态 let currentPage = 'fine-tune'; @@ -2449,6 +1276,7 @@ let selectedItems = new Set(); // 存储选中的项ID let currentPageData = []; // 存储当前页面数据 let modelListCache = []; // 模型列表缓存 + let currentModelTab = 'config'; // 模型管理页面当前tab: 'config'=配置模型, 'trained'=训练模型 // 加载模型列表缓存 async function loadModelListCache() { @@ -2559,588 +1387,6 @@ } } - // 渲染创建训练任务页面 - function renderFineTuneCreatePage() { - return ` -
-
- -
- 模型调优 - / - 创建训练任务 -
-
-
-
- -
-

基本信息

-
- -
- -

0 / 50

-
-
-
- - -
-

训练配置

- -
- -
- - - -
-
- -
- -
- - -
-
- -
-
- -
- -
- - -
-
- - - - - - -
- - -
-

数据配置

- -
- -
- -
-
- -
- -
- - -
- -
- 从当前训练集随机分割 - - % 作为验证集 -
- - -
-
- - -
-

训练产出

- -
- -
- -

0 / 50

-
-
- -
-
- 模型加密 - 安全升级 -
-

为保障您的数据安全,平台会为导出的模型文件开启 OSS 服务端加密

-
-
- - -
-
- - -
- -
-
-
-
- `; - } - - // 绑定创建页面事件 - function bindCreatePageEvents() { - // 卡片式单选框 - document.querySelectorAll('.card-radio').forEach(card => { - card.addEventListener('click', () => { - const parent = card.parentElement; - parent.querySelectorAll('.card-radio').forEach(c => c.classList.remove('active')); - card.classList.add('active'); - card.querySelector('input').checked = true; - }); - }); - - // 任务名称字数统计 - const nameInput = document.querySelector('input[name="name"]'); - if (nameInput) { - nameInput.addEventListener('input', () => { - const countEl = document.getElementById('nameCount'); - if (countEl) countEl.textContent = nameInput.value.length; - }); - } - - // 模型名称字数统计 - const modelNameInput = document.querySelector('input[name="output_model_name"]'); - if (modelNameInput) { - modelNameInput.addEventListener('input', () => { - const countEl = document.getElementById('modelNameCount'); - if (countEl) countEl.textContent = modelNameInput.value.length; - }); - } - - // 选择模型后启用训练方法 - const baseModelSelect = document.getElementById('baseModelSelect'); - if (baseModelSelect) { - baseModelSelect.addEventListener('change', () => { - const trainMethodLora = document.getElementById('trainMethodLora'); - const trainMethodFull = document.getElementById('trainMethodFull'); - const paramConfigPanelLora = document.getElementById('paramConfigPanelLora'); - const paramConfigPanelFull = document.getElementById('paramConfigPanelFull'); - if (baseModelSelect.value) { - // 启用训练方法 - trainMethodLora.classList.remove('opacity-50', 'cursor-not-allowed'); - trainMethodFull.classList.remove('opacity-50', 'cursor-not-allowed'); - trainMethodLora.querySelector('input').disabled = false; - trainMethodFull.querySelector('input').disabled = false; - } else { - // 禁用训练方法 - trainMethodLora.classList.add('opacity-50', 'cursor-not-allowed'); - trainMethodFull.classList.add('opacity-50', 'cursor-not-allowed'); - trainMethodLora.querySelector('input').disabled = true; - trainMethodFull.querySelector('input').disabled = true; - // 隐藏参数配置面板 - paramConfigPanelLora.classList.add('hidden'); - paramConfigPanelFull.classList.add('hidden'); - // 取消选择训练方法 - document.querySelectorAll('input[name="train_method"]').forEach(input => input.checked = false); - } - }); - } - - // 训练方法选择后显示/隐藏对应的参数配置面板 - document.querySelectorAll('input[name="train_method"]').forEach(input => { - input.addEventListener('change', () => { - const paramConfigPanelLora = document.getElementById('paramConfigPanelLora'); - const paramConfigPanelFull = document.getElementById('paramConfigPanelFull'); - if (input.checked && input.value === 'lora') { - paramConfigPanelLora.classList.remove('hidden'); - paramConfigPanelFull.classList.add('hidden'); - } else if (input.checked && input.value === 'full') { - paramConfigPanelLora.classList.add('hidden'); - paramConfigPanelFull.classList.remove('hidden'); - } else { - paramConfigPanelLora.classList.add('hidden'); - paramConfigPanelFull.classList.add('hidden'); - } - }); - }); - } - - // 加载数据集列表 - async function loadDatasets() { - try { - const response = await fetch(`${API_BASE}/dataset-manage`); - const result = await response.json(); - if (result.code === 0) { - // 训练集下拉框 - const trainSelect = document.querySelector('select[name="dataset_id"]'); - if (trainSelect) { - trainSelect.innerHTML = '' + - result.data.map(d => ``).join(''); - } - // 验证集下拉框 - const validSelect = document.querySelector('select[name="valid_dataset_id"]'); - if (validSelect) { - validSelect.innerHTML = '' + - result.data.map(d => ``).join(''); - } - } - } catch (e) { - console.error('加载数据集失败:', e); - } - } - - // 切换验证集面板显示 - function toggleValidSetPanel(type) { - const autoPanel = document.getElementById('validAutoPanel'); - const customPanel = document.getElementById('validCustomPanel'); - if (type === 'auto') { - autoPanel.classList.remove('hidden'); - customPanel.classList.add('hidden'); - } else { - autoPanel.classList.add('hidden'); - customPanel.classList.remove('hidden'); - } - } - - // 恢复默认配置 - function resetDefaultConfig(type) { - if (type === 'lora') { - const defaults = { - 'batch_size_lora': '16', - 'learning_rate_lora': '3e-4', - 'n_epochs_lora': '3', - 'save_steps_lora': '50', - 'lora_alpha': '32', - 'lora_dropout': '0.1', - 'lora_rank': '8', - 'lr_scheduler_type_lora': 'linear', - 'max_length_lora': '8192', - 'warmup_ratio_lora': '0.05', - 'weight_decay_lora': '0.01' - }; - for (const [name, value] of Object.entries(defaults)) { - const input = document.querySelector(`input[name="${name}"]`); - if (input) input.value = value; - const select = document.querySelector(`select[name="${name}"]`); - if (select) select.value = value; - } - } else { - const defaults = { - 'batch_size_full': '16', - 'learning_rate_full': '1e-5', - 'n_epochs_full': '3', - 'save_steps_full': '50', - 'lr_scheduler_type_full': 'linear', - 'max_length_full': '8192', - 'warmup_ratio_full': '0.05', - 'weight_decay_full': '0.01' - }; - for (const [name, value] of Object.entries(defaults)) { - const input = document.querySelector(`input[name="${name}"]`); - if (input) input.value = value; - const select = document.querySelector(`select[name="${name}"]`); - if (select) select.value = value; - } - } - } - - // 收起/展开参数配置表格 - function toggleParamTable(type) { - const container = type === 'lora' ? document.getElementById('paramTableContainerLora') : document.getElementById('paramTableContainerFull'); - const btn = type === 'lora' ? document.getElementById('toggleParamBtnLora') : document.getElementById('toggleParamBtnFull'); - const icon = btn.querySelector('i'); - const text = type === 'lora' ? document.getElementById('toggleParamTextLora') : document.getElementById('toggleParamTextFull'); - if (container.classList.contains('hidden')) { - container.classList.remove('hidden'); - icon.className = 'fa fa-chevron-up mr-1'; - text.textContent = '收起配置'; - } else { - container.classList.add('hidden'); - icon.className = 'fa fa-chevron-down mr-1'; - text.textContent = '展开配置'; - } - } - // ============ 自定义消息弹窗 ============ // 显示消息弹窗 - 使用 window 确保全局可访问 window.showMessage = function(title, message, type = 'info', onConfirm) { diff --git a/web/pages/model-compare-create.html b/web/pages/model-compare-create.html index 51fe07f..1b6150b 100644 --- a/web/pages/model-compare-create.html +++ b/web/pages/model-compare-create.html @@ -345,7 +345,9 @@ type: 'LLM', source: 'trained', model_path: model.path, - train_method: method.name + train_method: method.name, + merged: model.merged, // 是否已合并 + merging: model.merging // 是否正在合并 }); }); } @@ -402,10 +404,15 @@ // 已训练模型区域 if (trainedModels.length > 0) { + // 统计已合并和未合并的数量 + const mergedCount = trainedModels.filter(m => m.merged).length; html += `
-
- 已训练模型 (${trainedModels.length}) +
+
+ 已训练模型 (${trainedModels.length}) +
+ ${mergedCount > 0 ? `${mergedCount}个已合并可选择` : '需合并后才可选择'}
`; @@ -420,7 +427,9 @@ // 渲染单个模型卡片 function renderModelCard(model) { const isSelected = selectedModels.has(model.id); - const isDisabled = !isSelected && selectedModels.size >= 4; + // 未合并的已训练模型不可选择 + const isTrainedNotMerged = model.source === 'trained' && !model.merged; + const isDisabled = !isSelected && (selectedModels.size >= 4 || isTrainedNotMerged); const typeText = { 'LLM': '大语言模型', 'CV': '计算机视觉', @@ -430,19 +439,24 @@ }[model.type] || model.type || '其他'; // 处理字符串类型的ID const modelId = typeof model.id === 'string' ? `'${model.id.replace(/'/g, "\\'")}'` : model.id; + // 未合并提示文字 + const unmergedTip = isTrainedNotMerged ? '请先合并权重后再选择' : ''; return `
+ onclick="${isTrainedNotMerged ? `showMessage('提示', '该模型未合并权重,无法参与对比。请先在模型管理中合并权重。', 'warning')` : `toggleModel(${modelId})`}" + title="${unmergedTip}">
-
+
${isSelected ? '' : ''}
${model.name} ${typeText} + ${isTrainedNotMerged ? '未合并' : ''} + ${model.source === 'trained' && model.merged ? '已合并' : ''}

${model.description || '暂无描述'}

@@ -519,10 +533,15 @@ // 已训练模型区域 if (trainedModels.length > 0) { + // 统计已合并和未合并的数量 + const mergedCount = trainedModels.filter(m => m.merged).length; html += `
-
- 已训练模型 (${trainedModels.length}) +
+
+ 已训练模型 (${trainedModels.length}) +
+ ${mergedCount > 0 ? `${mergedCount}个已合并可选择` : '需合并后才可选择'}
`; diff --git a/web/pages/model-manage.html b/web/pages/model-manage.html index d7b8d98..0580645 100644 --- a/web/pages/model-manage.html +++ b/web/pages/model-manage.html @@ -1,735 +1,735 @@ - - - - - - 模型管理 / 远光软件微调平台 - - - - - - - - - - -
- -
- -
- - -
- -
-

模型管理

-
- - - - - -
-
- - -
- -
-
- -
- -
- - -
-
- - - - - - - - - - - - - - - - -
模型名称模型类型用途模型来源描述模型路径创建时间操作
-
- - -
- - - -
- - - - + + + + + + 模型管理 / 远光软件微调平台 + + + + + + + + + + +
+ +
+ +
+ + +
+ +
+

模型管理

+
+ + + + + +
+
+ + +
+ +
+
+ +
+ +
+ + +
+
+ + + + + + + + + + + + + + + + +
模型名称模型类型用途模型来源描述模型路径创建时间操作
+
+ + +
+ + + +
+ + + + diff --git a/web/pages/tools.html b/web/pages/tools.html new file mode 100644 index 0000000..b706d2e --- /dev/null +++ b/web/pages/tools.html @@ -0,0 +1,373 @@ + + + + + + 其他工具 - 远光软件微调平台 + + + + + + + + + + +
+
+ +
+ +
+ +
+
+ + + + + + +