diff --git a/frontend/public/favicon.ico b/frontend/public/favicon.ico new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/frontend/public/favicon.ico @@ -0,0 +1 @@ + diff --git a/frontend/public/logo.png b/frontend/public/logo.png new file mode 100644 index 0000000..1de89ad Binary files /dev/null and b/frontend/public/logo.png differ diff --git a/frontend/src/App.vue b/frontend/src/App.vue new file mode 100644 index 0000000..856a59f --- /dev/null +++ b/frontend/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/frontend/src/constants/dimension.ts b/frontend/src/constants/dimension.ts new file mode 100644 index 0000000..7258d24 --- /dev/null +++ b/frontend/src/constants/dimension.ts @@ -0,0 +1,106 @@ +import type { DimensionType } from '@/types' + +/** 各指标类型的评估方法选项 */ +export const EVAL_METHODS: Record< + DimensionType | string, + { value: string; name: string; desc: string }[] +> = { + classification: [ + { value: 'standard', name: '标准匹配', desc: '根据预设标准评估' }, + { value: 'sentiment', name: '情感分析', desc: '识别文本情感倾向' }, + { value: 'custom', name: '自定义评分器', desc: '自定义评估规则' }, + ], + metric: [ + { value: 'metric_standard', name: '综合评测', desc: '根据预设标准评分' }, + { value: 'semantic', name: '语义相似度', desc: '计算语义相似程度' }, + { value: 'custom', name: '自定义评分器', desc: '自定义评估规则' }, + ], + text_similarity: [ + { value: 'bleu_4', name: 'BLEU-4', desc: 'N-gram 精确度评估' }, + { value: 'cosine', name: 'Cosine', desc: '余弦相似度' }, + { value: 'rouge_1', name: 'ROUGE-1', desc: 'unigram 重叠评估' }, + { value: 'rouge_2', name: 'ROUGE-2', desc: 'bigram 重叠评估' }, + { value: 'rouge_4', name: 'ROUGE-4', desc: '4-gram 重叠评估' }, + ], +} + +/** 各评估方法的预置 Prompt 模板 */ +export const EVAL_METHOD_PROMPTS: Record = { + standard: `# 角色 +你是一位专业的对话评估专家,擅长根据提供的标准对助理在对话中的最终反应进行评估,并确定其是否[[Pass]]或[[Fail]]。 + +## 技能 +### 技能 1: 对话回顾 +- 通读整个对话以理解上下文和背景信息。 +- 确保全面理解对话的意图和用户的需求。 + +### 技能 2: 最终回答识别 +- 从对话中准确识别出助理给出的最后一个回答。 +- 确保关注的是最终的回答,而不是中间的部分。 + +### 技能 3: 标准应用 +- 仔细审查每个评价标准。 +- 将助理的最终回答与标准的各个方面进行详细比较。 + +### 技能 4: 逐步推理 +- 记录每个标准以及最终响应如何满足或不满足该标准。 +- 提供详细的证据,并解释为什么最终答复满足或不满足期望。 + +### 技能 5: 结果判定 +- 根据逐步推理的结果,判断最终回答是[[Pass]]或[[Fail]] +- 提供明确的结论并解释理由。 + +## 输出格式 +以下列格式提供结果: +- **分步推理:**[详细推理在这里] +- **最终结果:**[[Pass]]或[[Fail]] + +## 限制 +- 只针对对话中的最终回答进行评估。 +- 在评估过程中,确保遵循提供的标准,避免主观判断。`, + + sentiment: `# 角色 +你是一位专业的情感分析专家,擅长识别文本中的情感倾向,并给出[[Positive]]、[[Neutral]]或[[Negative]]的判断。 + +## 技能 +### 技能 1: 文本理解 +- 通读输入文本,理解其内容和语境。 + +### 技能 2: 情感识别 +- 识别文本中表达的情感词汇、语气和情感强度。 +- 分析上下文中的情感线索。 + +### 技能 3: 情感判定 +- 根据识别到的情感信息,判断整体情感倾向。 + +## 输出格式 +- **情感分析:**[分析过程] +- **最终结果:**[[Positive]]/[[Neutral]]/[[Negative]]`, + + metric_standard: `# 角色 +你是一位专业的模型评估专家,擅长根据预设标准对模型输出进行综合评分(0-5分)。 + +## 评估标准 +请从以下维度对模型输出进行评分: +1. 准确性:回答是否准确无误 +2. 完整性:是否完整覆盖了问题的各个方面 +3. 连贯性:回答是否逻辑清晰、结构合理 +4. 可读性:语言表达是否流畅、易懂 + +## 输出格式 +- **评分理由:**[详细说明] +- **最终评分:**[0-5 的分数]`, + + semantic: `# 角色 +你是一位专业的语义相似度评估专家,擅长计算两段文本之间的语义相似程度。 + +## 任务 +请评估生成文本与参考文本在语义上的相似程度,给出 0-1 之间的分数。 + +## 输出格式 +- **相似度分析:**[分析过程] +- **相似度分数:**[0-1 的分数]`, + + custom: `# 自定义评估器 +请在此编写您的自定义评估 Prompt...`, +} diff --git a/frontend/src/constants/index.ts b/frontend/src/constants/index.ts new file mode 100644 index 0000000..48eb5b8 --- /dev/null +++ b/frontend/src/constants/index.ts @@ -0,0 +1,144 @@ +/** + * 全局常量与映射表 + */ + +/** 模型类型 */ +export const MODEL_TYPE_MAP: Record = { + LLM: '大语言模型', + CV: '计算机视觉', + NLP: '自然语言处理', + Embedding: '向量模型', + Other: '其他', +} + +/** 模型用途 */ +export const PURPOSE_MAP: Record = { + training: { text: '训练', type: 'primary' }, + inference: { text: '推理', type: 'success' }, + evaluation: { text: '评测', type: 'warning' }, +} + +/** 模型来源 */ +export const MODEL_SOURCE_MAP: Record = { + local: '本地模型', + api: '在线模型', + online: '在线模型', +} + +/** 训练方式 */ +export const TRAIN_TYPE_MAP: Record = { + SFT: 'SFT', + DPO: 'DPO', + CPT: 'CPT', +} + +/** 训练方法 */ +export const TRAIN_METHOD_MAP: Record = { + lora: 'LoRA', + qlora: 'QLoRA', + full: '全量微调', + prefix: 'Prefix Tuning', + adapter: 'Adapter', + peft: 'PEFT', + adalora: 'AdaLoRA', + longlora: 'LongLoRA', + dpo: 'DPO', + cpt: 'CPT', +} + +/** 数据集类型 */ +export const DATASET_TYPE_MAP: Record = { + train: '训练数据', + test: '测试数据', + eval: '评测数据', + val: '验证数据', + other: '其他', +} + +/** 存储位置 */ +export const STORAGE_MAP: Record = { + local: '本地存储', + minio: 'MinIO', + cloud: '云存储', +} + +/** 评测维度指标类型 */ +export const DIMENSION_TYPE_MAP: Record = { + classification: '大模型-分类型', + metric: '大模型-指标型', + text_similarity: '规则-文本相似度', +} + +/** 学习率调度器类型 */ +export const LR_SCHEDULER_OPTIONS = [ + { label: 'cosine', value: 'cosine' }, + { label: 'linear', value: 'linear' }, + { label: 'constant', value: 'constant' }, +] + +/** 训练模板分组(按模型系列) */ +export const TEMPLATE_GROUPS: { label: string; options: { label: string; value: string }[] }[] = [ + { + label: 'Qwen 系列', + options: [ + { label: 'qwen', value: 'qwen' }, + { label: 'qwen2', value: 'qwen2' }, + { label: 'qwen2_5', value: 'qwen2_5' }, + ], + }, + { + label: 'Llama 系列', + options: [ + { label: 'llama2', value: 'llama2' }, + { label: 'llama3', value: 'llama3' }, + { label: 'llama3_1', value: 'llama3_1' }, + ], + }, + { + label: 'DeepSeek 系列', + options: [ + { label: 'deepseek', value: 'deepseek' }, + { label: 'deepseek2', value: 'deepseek2' }, + ], + }, + { + label: '其他系列', + options: [ + { label: 'glm4', value: 'glm4' }, + { label: 'chatglm3', value: 'chatglm3' }, + { label: 'gemma', value: 'gemma' }, + { label: 'gemma2', value: 'gemma2' }, + { label: 'phi', value: 'phi' }, + { label: 'intern2', value: 'intern2' }, + { label: 'mistral', value: 'mistral' }, + { label: 'default', value: 'default' }, + ], + }, +] + +/** 默认工具列表(其他工具页) */ +export const DEFAULT_TOOLS = [ + { id: 'data-generate', name: '数据生成', icon: 'fa-database', description: '基于LLM生成微调数据集' }, + { id: 'json2jsonl', name: 'JSON转JSONL', icon: 'fa-code', description: '将JSON文件转换为JSONL格式' }, + { id: 'md-convert', name: '转换Markdown', icon: 'fa-file-text', description: '将Markdown文件转换为训练数据' }, +] + +/** 自定义工具可选图标 */ +export const TOOL_ICONS = [ + 'fa-cog', 'fa-database', 'fa-code', 'fa-file-text', 'fa-wrench', 'fa-cube', + 'fa-line-chart', 'fa-bar-chart', 'fa-server', 'fa-cogs', 'fa-tasks', 'fa-trophy', + 'fa-sliders', 'fa-rocket', 'fa-cloud', 'fa-cloud-download', 'fa-microchip', + 'fa-hdd-o', 'fa-globe', 'fa-info-circle', 'fa-question-circle-o', 'fa-user-o', + 'fa-lock-o', 'fa-sign-in', 'fa-sign-out', 'fa-search', 'fa-plus', 'fa-refresh', + 'fa-times', 'fa-check', 'fa-pencil', 'fa-trash', 'fa-play', 'fa-arrow-left', + 'fa-arrow-down', 'fa-arrow-up', +] + +/** 会话超时:5 分钟 */ +export const SESSION_TIMEOUT = 5 * 60 * 1000 + +/** 系统监控刷新间隔 */ +export const METRICS_INTERVAL = 30000 + +/** 训练进度刷新间隔 */ +export const TRAINING_REFRESH_INTERVAL = 5000 diff --git a/frontend/src/layouts/MainLayout.vue b/frontend/src/layouts/MainLayout.vue new file mode 100644 index 0000000..ff87d99 --- /dev/null +++ b/frontend/src/layouts/MainLayout.vue @@ -0,0 +1,116 @@ + + + + + diff --git a/frontend/src/main.ts b/frontend/src/main.ts new file mode 100644 index 0000000..c2516ea --- /dev/null +++ b/frontend/src/main.ts @@ -0,0 +1,25 @@ +import { createApp } from 'vue' +import { createPinia } from 'pinia' +import ElementPlus from 'element-plus' +import zhCn from 'element-plus/es/locale/lang/zh-cn' +import 'element-plus/dist/index.css' + +// Font Awesome 图标 +import '@/assets/font-awesome/css/font-awesome.min.css' + +// ECharts(按需引入)+ vue-echarts 组件 +import '@/plugins/echarts' +import VChart from 'vue-echarts' + +import App from './App.vue' +import router from './router' +import './styles/index.scss' + +const app = createApp(App) + +app.use(createPinia()) +app.use(router) +app.use(ElementPlus, { locale: zhCn }) +app.component('VChart', VChart) + +app.mount('#app') diff --git a/frontend/src/plugins/echarts.ts b/frontend/src/plugins/echarts.ts new file mode 100644 index 0000000..7be7f7e --- /dev/null +++ b/frontend/src/plugins/echarts.ts @@ -0,0 +1,24 @@ +/** + * ECharts 按需引入 + * 仅注册训练曲线所需的模块,避免引入全量包以减小体积 + */ +import { use } from 'echarts/core' +import { CanvasRenderer } from 'echarts/renderers' +import { LineChart } from 'echarts/charts' +import { + GridComponent, + TooltipComponent, + LegendComponent, + DataZoomComponent, + MarkLineComponent, +} from 'echarts/components' + +use([ + CanvasRenderer, + LineChart, + GridComponent, + TooltipComponent, + LegendComponent, + DataZoomComponent, + MarkLineComponent, +]) diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts new file mode 100644 index 0000000..4f1d313 --- /dev/null +++ b/frontend/src/router/index.ts @@ -0,0 +1,239 @@ +import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router' +import { useAuthStore } from '@/stores/auth' + +const routes: RouteRecordRaw[] = [ + { + path: '/login', + name: 'login', + component: () => import('@/views/login/LoginView.vue'), + meta: { title: '登录', public: true }, + }, + { + path: '/', + component: () => import('@/layouts/MainLayout.vue'), + redirect: '/fine-tune', + children: [ + // 服务看板 + { + path: 'dashboard', + name: 'dashboard', + component: () => import('@/components/PlaceholderView.vue'), + meta: { title: '服务看板' }, + }, + // 模型调优 + { + path: 'fine-tune', + name: 'fine-tune', + component: () => import('@/views/fine-tune/FineTuneListView.vue'), + meta: { title: '模型微调', pageSurface: 'self' }, + }, + { + path: 'fine-tune/create', + name: 'fine-tune-create', + component: () => import('@/views/fine-tune/FineTuneCreateView.vue'), + meta: { title: '创建训练任务' }, + }, + // 模型评测 + { + path: 'model-eval', + name: 'model-eval', + component: () => import('@/views/eval/EvalView.vue'), + meta: { title: '模型评测', pageSurface: 'self' }, + }, + { + path: 'model-eval/create', + name: 'model-eval-create', + component: () => import('@/views/eval/EvalCreateView.vue'), + meta: { title: '新建评测' }, + }, + { + path: 'model-eval/dimension/create', + name: 'dimension-create', + component: () => import('@/views/eval/DimensionCreateView.vue'), + meta: { title: '添加评测维度' }, + }, + { + path: 'model-eval/dimension/:id/edit', + name: 'dimension-edit', + component: () => import('@/views/eval/DimensionCreateView.vue'), + meta: { title: '编辑评测维度' }, + }, + // 模型推理 + { + path: 'model-inference', + name: 'model-inference', + component: () => import('@/views/inference/InferenceListView.vue'), + meta: { title: '模型推理', pageSurface: 'self' }, + }, + { + path: 'model-inference/create', + name: 'model-inference-create', + component: () => import('@/views/inference/InferenceCreateView.vue'), + meta: { title: '新建推理' }, + }, + { + path: 'model-inference/chat/:id', + name: 'inference-chat', + component: () => import('@/views/inference/InferenceChatView.vue'), + meta: { title: '模型对话', pageSurface: 'self' }, + }, + // 模型对比 + { + path: 'model-compare/chat/:id', + name: 'compare-chat', + component: () => import('@/views/compare/CompareChatView.vue'), + meta: { title: '模型对比' }, + }, + { + path: 'model-compare/result', + name: 'compare-result', + component: () => import('@/views/compare/CompareResultView.vue'), + meta: { title: '对比结果' }, + }, + // 模型管理 + { + path: 'model-manage', + name: 'model-manage', + component: () => import('@/views/model/ModelManageView.vue'), + meta: { title: '模型管理', pageSurface: 'self' }, + }, + { + path: 'model-manage/create', + name: 'model-manage-create', + component: () => import('@/views/model/ModelCreateView.vue'), + meta: { title: '添加模型' }, + }, + { + path: 'model-manage/:id/edit', + name: 'model-manage-edit', + component: () => import('@/views/model/ModelCreateView.vue'), + meta: { title: '编辑模型' }, + }, + { + path: 'model-manage/merge', + name: 'merge-weights', + component: () => import('@/views/model/MergeWeightsView.vue'), + meta: { title: '合并权重' }, + }, + // 数据处理 + { + path: 'data-process', + name: 'data-process', + component: () => import('@/views/data-process/DataProcessListView.vue'), + meta: { title: '数据处理', pageSurface: 'self' }, + }, + { + path: 'data-process/create', + name: 'data-process-create', + component: () => import('@/views/data-process/DataProcessCreateView.vue'), + meta: { title: '新建数据处理任务', pageSurface: 'self' }, + }, + // 数据集管理 + { + path: 'dataset', + name: 'dataset', + component: () => import('@/views/dataset/DatasetListView.vue'), + meta: { title: '数据集管理', pageSurface: 'self' }, + }, + { + path: 'dataset/create', + name: 'dataset-create', + component: () => import('@/views/dataset/DatasetCreateView.vue'), + meta: { title: '上传数据集' }, + }, + { + path: 'dataset/:id/edit', + name: 'dataset-edit', + component: () => import('@/views/dataset/DatasetCreateView.vue'), + meta: { title: '编辑数据集' }, + }, + { + path: 'dataset/:id/preview', + name: 'dataset-preview', + component: () => import('@/views/dataset/DatasetPreviewView.vue'), + meta: { title: '数据集预览' }, + }, + // 其他工具 + { + path: 'tools', + name: 'tools', + component: () => import('@/views/tools/ToolsView.vue'), + meta: { title: '其他工具' }, + }, + { + path: 'tools/create', + name: 'tools-create', + component: () => import('@/views/tools/ToolCreateView.vue'), + meta: { title: '添加自定义工具' }, + }, + { + path: 'tools/:id/edit', + name: 'tools-edit', + component: () => import('@/views/tools/ToolCreateView.vue'), + meta: { title: '编辑自定义工具' }, + }, + // 数据类型转换 + { + path: 'data-convert', + name: 'data-convert', + component: () => import('@/components/PlaceholderView.vue'), + meta: { title: '数据类型转换' }, + }, + // 系统设置 + { + path: 'hardware', + name: 'hardware', + component: () => import('@/views/system/HardwareView.vue'), + meta: { title: '平台性能' }, + }, + { + path: 'logs', + name: 'logs', + component: () => import('@/views/system/LogsView.vue'), + meta: { title: '查看日志' }, + }, + { + path: 'training-log/:id', + name: 'training-log', + component: () => import('@/views/system/TrainingLogView.vue'), + meta: { title: '训练日志' }, + }, + ], + }, + { + path: '/:pathMatch(.*)*', + redirect: '/fine-tune', + }, +] + +const router = createRouter({ + history: createWebHistory(), + routes, +}) + +// 全局守卫:登录校验 + 会话超时 +router.beforeEach((to, _from, next) => { + const auth = useAuthStore() + document.title = to.meta.title ? `${to.meta.title} - 远光软件微调平台` : '远光软件微调平台' + + if (to.meta.public) { + // 已登录访问登录页则跳转主页 + if (to.name === 'login' && auth.isLoggedIn) { + next('/fine-tune') + return + } + next() + return + } + + if (!auth.isLoggedIn) { + next({ name: 'login' }) + return + } + + // 续期会话 + auth.refresh() + next() +}) + +export default router diff --git a/frontend/src/styles/index.scss b/frontend/src/styles/index.scss new file mode 100644 index 0000000..7ad1238 --- /dev/null +++ b/frontend/src/styles/index.scss @@ -0,0 +1,190 @@ +/* Element Plus 主题变量覆盖:使用原生 CSS 变量替代 SCSS 编译以解决加载卡顿和 FOUC 问题 */ +:root { + /* 全局页面层级:灰色仅作为外层留白,业务页面统一使用白色画布 */ + --app-shell-bg: #f3f5f8; + --app-page-bg: #ffffff; + --app-surface-bg: #ffffff; + --el-bg-color-page: var(--app-shell-bg); + + /* Element Plus 基础颜色覆盖 */ + --el-color-primary: #4f46e5; + --el-color-primary-light-3: #818cf8; + --el-color-primary-light-5: #a5b4fc; + --el-color-primary-light-7: #c7d2fe; + --el-color-primary-light-8: #e0e7ff; + --el-color-primary-light-9: #eef2ff; + --el-color-primary-dark-2: #4338ca; + + --el-color-success: #10b981; + --el-color-warning: #f59e0b; + --el-color-danger: #ef4444; + --el-color-info: #64748b; + + /* Element Plus 圆角覆盖 */ + --el-border-radius-base: 8px; + --el-border-radius-small: 6px; + --el-border-radius-round: 20px; + + /* 项目自定义 CSS 变量 */ + --primary-color: var(--el-color-primary); + --primary-hover: var(--el-color-primary-light-3); + --danger-color: var(--el-color-danger); + --success-color: var(--el-color-success); + --sidebar-bg: #f9fafb; /* Light Gray */ + --sidebar-text: #606266; /* Regular Text */ + --sidebar-active-bg: #f1f5f9; /* Active Item Bg */ + --sidebar-active-text: #303133; /* Darker Text for Active */ + --card-shadow: 0 4px 24px rgba(0, 0, 0, 0.04); + --header-height: 60px; +} + +html, +body, +#app { + height: 100%; + margin: 0; + padding: 0; +} + +body { + font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, + 'Helvetica Neue', Arial, 'PingFang SC', sans-serif; + background-color: var(--app-shell-bg); + color: var(--el-text-color-primary); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +* { + box-sizing: border-box; +} + +/* 滚动条美化 */ +::-webkit-scrollbar { + width: 6px; + height: 6px; +} +::-webkit-scrollbar-thumb { + background-color: rgba(148, 163, 184, 0.4); + border-radius: 4px; + transition: all 0.3s; +} +::-webkit-scrollbar-thumb:hover { + background-color: rgba(148, 163, 184, 0.7); +} +::-webkit-scrollbar-track { + background: transparent; +} + +/* 覆盖 Element Plus 的一些默认样式,使其更高级 */ + +/* 1. 卡片 (el-card) 无边框,柔和阴影 */ +.el-card { + background-color: var(--app-surface-bg); + border: none !important; + box-shadow: var(--card-shadow) !important; + border-radius: 12px !important; + transition: transform 0.2s ease, box-shadow 0.2s ease; +} + +/* 2. 表格 (el-table) 现代化 */ +.el-table { + --el-table-border-color: #f1f5f9; + --el-table-header-bg-color: #f8fafc; + --el-table-header-text-color: #475569; + border-radius: 8px; + overflow: hidden; +} +.el-table th.el-table__cell { + font-weight: 600 !important; + font-size: 13px; + text-transform: uppercase; + letter-spacing: 0.5px; + border-bottom: 1px solid var(--el-table-border-color) !important; +} +.el-table td.el-table__cell { + padding: 12px 0 !important; +} +.el-table--enable-row-hover .el-table__body tr:hover > td.el-table__cell { + background-color: #f8fafc !important; +} +.el-table::before { + display: none; /* 移除底部基础边框 */ +} + +/* 3. 按钮动效 */ +.el-button { + font-weight: 500; + transition: all 0.2s ease; +} +.el-button:hover { + transform: translateY(-1px); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05); +} +.el-button:active { + transform: translateY(0); +} +.el-button.is-link:hover { + transform: none; + box-shadow: none; +} + +/* 4. 标签 (el-tag) 圆润化 */ +.el-tag { + border-radius: 6px; + border: none !important; + font-weight: 500; +} +.el-tag--primary { + background-color: rgba(79, 70, 229, 0.1); + color: #4f46e5; +} +.el-tag--success { + background-color: rgba(16, 185, 129, 0.1); + color: #10b981; +} +.el-tag--warning { + background-color: rgba(245, 158, 11, 0.1); + color: #d97706; +} +.el-tag--danger { + background-color: rgba(239, 68, 68, 0.1); + color: #ef4444; +} +.el-tag--info { + background-color: rgba(100, 116, 139, 0.1); + color: #475569; +} + +/* 5. 分页组件 */ +.el-pagination { + --el-pagination-bg-color: #ffffff; + --el-pagination-hover-color: var(--primary-color); + margin-top: 16px; + justify-content: flex-end; +} +.el-pagination.is-background .el-pager li { + border-radius: 6px; + background-color: #f1f5f9; + border: none; +} +.el-pagination.is-background .el-pager li.is-active { + background-color: var(--primary-color); + color: #fff; + box-shadow: 0 2px 8px rgba(79, 70, 229, 0.3); +} + +/* 6. 模态框 (Dialog) */ +.el-dialog { + border-radius: 16px !important; + box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1) !important; +} +.el-dialog__header { + margin-right: 0 !important; + padding-bottom: 16px !important; + border-bottom: 1px solid #f1f5f9; +} +.el-dialog__title { + font-weight: 600 !important; + font-size: 16px !important; +} diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts new file mode 100644 index 0000000..258ac9b --- /dev/null +++ b/frontend/src/types/index.ts @@ -0,0 +1,260 @@ +/** + * 全局业务类型定义 + */ + +/** 通用分页/列表响应暂用数组,后端未分页 */ + +// ============ 模型管理 ============ +export type ModelType = 'LLM' | 'CV' | 'NLP' | 'Embedding' | 'Other' +export type ModelPurpose = 'training' | 'inference' | 'evaluation' +export type ModelSource = 'local' | 'api' | 'online' + +export interface TrainMethod { + name: string +} + +/** 数据库配置模型 */ +export interface ModelItem { + id: number | string + name: string + type: ModelType | string + purpose: ModelPurpose | string + model_source: ModelSource | string + description?: string + path?: string + api_url?: string + api_key?: string + online_model_name?: string + create_time?: string +} + +/** 已训练模型 */ +export interface TrainedModel { + id: number | string + name: string + train_methods?: TrainMethod[] + base_model_path?: string + create_time?: string + merged?: boolean + merging?: boolean + merged_path?: string +} + +/** 创建/编辑模型请求体 */ +export interface ModelForm { + id?: number | string + name: string + type: ModelType | string + purpose: ModelPurpose | string + model_source: ModelSource | string + description?: string + path?: string + api_url?: string + api_key?: string + online_model_name?: string +} + +// ============ 数据集 ============ +export type DatasetType = 'train' | 'test' | 'eval' | 'val' | 'other' +export type DatasetStorage = 'local' | 'cloud' | 'minio' + +export interface DatasetFile { + id?: string + name: string + size?: string | number + [k: string]: any +} + +export interface DatasetItem { + id: number | string + name: string + type: DatasetType | string + storage_type: DatasetStorage | string + size?: string | number + count?: number + description?: string + create_time?: string + files?: DatasetFile[] +} + +// ============ 训练任务 ============ +export type TrainType = 'SFT' | 'DPO' | 'CPT' +export type TrainMethodType = 'lora' | 'full' +export type TaskStatus = 'pending' | 'running' | 'completed' | 'failed' | string + +export interface FineTuneTask { + id: number | string + name: string + description?: string + status: TaskStatus + train_type: TrainType | string + train_method?: TrainMethodType | string + template?: string + base_model: number | string + train_dataset_id?: number | string + output_model_name?: string + gpus?: number[] + batch_size?: number + learning_rate?: number + n_epochs?: number + save_steps?: number + lr_scheduler_type?: string + max_length?: number + warmup_ratio?: number + weight_decay?: number + lora_alpha?: number + lora_dropout?: number + lora_rank?: number + progress?: number + process_id?: number + train_duration?: string + create_time?: string +} + +export interface TrainingProgress { + status?: string + progress?: number + step?: string + speed?: string + eta?: string +} + +// ============ 模型推理 / 对比 (model-compare) ============ +export interface LoadedModel { + model_id?: number | string + model_name?: string + status?: string + pid?: number + port?: number +} + +export interface CompareTask { + id: number | string + model_name?: string + name?: string + description?: string + status?: string + models?: CompareModelRef[] | string + load_status?: string | { loaded_models: LoadedModel[] } + create_time?: string +} + +export interface CompareModelRef { + model_id: number | string + model_name: string + model_path: string + gpu_id: number + source?: string + port?: number +} + +// ============ 模型评测 ============ +export type EvalType = 'custom' | 'baseline' +export type DimensionType = 'classification' | 'metric' | 'text_similarity' + +export interface EvalTask { + id: number | string + eval_task_name?: string + model_name?: string + model_id?: number | string + dataset?: string + metric?: string + score?: number + status?: string + create_time?: string +} + +export interface Dimension { + id: number | string + name: string + type: DimensionType | string + description?: string + eval_model?: string + eval_method?: string | string[] + eval_prompt?: string + is_active?: boolean + is_default?: boolean + bleu_n?: number + output_precision?: number + score_min?: number + score_max?: number + pass_threshold?: number + create_time?: string +} + +// ============ 系统监控 ============ +export interface GpuInfo { + name: string + gpu_percent: number + memory_used_gb: number + memory_total_gb: number + temperature: number + power_w: number + fan_speed?: number + clock_mhz?: number + driver_version?: string +} + +export interface SystemInfo { + cpu?: { + percent: number + cores: number + percents?: number[] + } + memory?: { + used_gb: number + total_gb: number + percent: number + available_gb: number + cached_gb: number + } + disk?: { + used_gb: number + total_gb: number + percent: number + } + gpu?: GpuInfo[] + network?: { + download_mb?: number + upload_mb?: number + } + system?: { + uptime_seconds?: number + process_count?: number + os?: string + } +} + +export interface HealthMetrics { + cpu_percent?: number + memory_percent?: number + disk_percent?: number +} + +// ============ 日志 ============ +export interface LogFile { + file: string + name: string + size: string + pid?: number + date?: string +} + +export interface LogContent { + content: string + file: string + size: string +} + +export interface TrainingLogFile extends LogFile { + pid?: number +} + +// ============ 其他工具 ============ +export interface CustomTool { + id: string + name: string + description: string + url: string + icon: string +}