Commit 4fcaf270 authored by mhw's avatar mhw

版本更新

parent 84bea040
......@@ -23,7 +23,8 @@ module.exports = {
'lines-between-class-members': ['off'],
// 'no-undef': ['off', 'always'],
// 'no-unused-vars': ['off', 'always'],
'no-new-func': ['off', 'always']
'no-new-func': ['off', 'always'],
'space-before-function-paren':0
},
overrides: [
{
......
export default class ModelDeployment {
static list (sender, params, axiosOption, httpOption) {
return sender.doUrl('/admin/app/modelDeploy/list', 'post', params, axiosOption, httpOption);
}
static listForTree (sender, params, axiosOption, httpOption) {
return sender.doUrl('/admin/app/modelManage/listForTree', 'post', params, axiosOption, httpOption);
}
static add (sender, params, axiosOption, httpOption) {
return sender.doUrl('/admin/app/modelDeploy/add', 'post', params, axiosOption, httpOption);
}
static delete (sender, params, axiosOption, httpOption) {
return sender.doUrl('/admin/app/modelDeploy/delete', 'post', params, axiosOption, httpOption);
}
static deploy (sender, params, axiosOption, httpOption) {
return sender.doUrl('/admin/app/modelDeploy/deploy', 'post', params, axiosOption, httpOption);
}
static getGpuInfo (sender, params, axiosOption, httpOption) {
return sender.doUrl('/admin/app/modelDeploy/getGpuInfo', 'post', params, axiosOption, httpOption);
}
static stop (sender, params, axiosOption, httpOption) {
return sender.doUrl('/admin/app/modelDeploy/stop', 'post', params, axiosOption, httpOption);
}
static canUseList (sender, params, axiosOption, httpOption) {
return sender.doUrl('/admin/app/modelDeploy/canUseList', 'post', params, axiosOption, httpOption);
}
}
......@@ -16,6 +16,7 @@ import TuningRun from './GptController/TuningRun.js';
import PyApi from './GptController/PyApi.js';
import KnowledgeManage from './GptController/KnowledgeManage.js';
import DatasetData from './GptController/DatasetData.js';
import ModelDeployment from './GptController/ModelDeployment.js';
export {
TemplateController,
......@@ -34,5 +35,6 @@ export {
TuningRun,
PyApi,
KnowledgeManage,
DatasetData
DatasetData,
ModelDeployment
}
module.exports = {
baseUrl: 'http://218.76.0.69:8082/',
// baseUrl: 'http://218.76.0.69:8082/',
baseUrl: 'http://192.168.0.34:8082/',
wsUrl: 'ws://218.76.0.69:7860/',
projectName: '灵境大模型平台'
}
......@@ -14,20 +14,21 @@ const routers = [
component: _import('login/index'),
name: 'root'
},
{path: '/aggregate', component: _import('welcome/index-2'), name: 'aggregate', meta: { title: '集群' }},
// {path: '/aggregate', component: _import('welcome/index'), name: 'aggregate', meta: { title: '集群' }},
{
path: '/main',
component: _import('layout/index'),
name: 'main',
props: getProps,
redirect: {
name: 'aggregate'
name: 'welcome'
},
meta: {
title: '主页',
showOnly: true
},
children: [
{ path: 'welcome', component: _import('welcome/index'), name: 'welcome', meta: { title: '欢迎' } },
{ path: 'formSysUser', component: _import('upms/formSysUser/index'), name: 'formSysUser', meta: { title: '用户管理' } },
{ path: 'formSysDept', component: _import('upms/formSysDept/index'), name: 'formSysDept', meta: { title: '部门管理' } },
{ path: 'formSysRole', component: _import('upms/formSysRole/index'), name: 'formSysRole', meta: { title: '角色管理' } },
......@@ -52,6 +53,7 @@ const routers = [
{ path: 'modelSquare', component: _import('gptTraining/modelManagement/modelSquare/index'), name: 'modelSquare', props: getProps, meta: { title: '模型广场' } },
{ path: 'modelEvaluation', component: _import('gptTraining/modelManagement/modelEvaluation/index'), name: 'modelEvaluation', props: getProps, meta: { title: '模型评估' } },
{ path: 'modelCompression', component: _import('gptTraining/modelManagement/modelCompression/index'), name: 'modelCompression', props: getProps, meta: { title: '模型压缩' } },
{ path: 'modelDeployment', component: _import('gptTraining/modelManagement/modelDeployment/index'), name: 'modelDeployment', props: getProps, meta: { title: '模型部署' } },
// 模型服务
{ path: 'serviceManagement', component: _import('gptTraining/modelService/serviceManagement/index'), name: 'serviceManagement', props: getProps, meta: { title: '在线服务' } },
{ path: 'applicationAccess', component: _import('gptTraining/modelService/applicationAccess/index'), name: 'applicationAccess', props: getProps, meta: { title: '应用接入' } },
......@@ -89,9 +91,7 @@ const routers = [
// { path: 'onLineOptimization', component: _import('gptTraining/promptProject/onLineOptimization/index'), name: 'onLineOptimization', props: getProps, meta: { title: '在线优化' } },
// { path: 'batchOptimization', component: _import('gptTraining/promptProject/batchOptimization/index'), name: 'batchOptimization', props: getProps, meta: { title: '批量优化' } },
// 知识库
{ path: 'knowledgeBase', component: _import('gptTraining/knowledgeBase/index'), name: 'knowledgeBase', props: getProps, meta: { title: '知识库' } },
{ path: 'welcome', component: _import('welcome/index'), name: 'welcome', meta: { title: '欢迎' } }
{ path: 'knowledgeBase', component: _import('gptTraining/knowledgeBase/index'), name: 'knowledgeBase', props: getProps, meta: { title: '知识库' } }
]
}
];
......
......@@ -455,7 +455,36 @@ const RunningStatus = new DictionaryBase('运行状态', [
symbol: 'TrainingUnderway'
}
]);
Vue.prototype.RunningStatus = RunningStatus;
const DeploymentStatus = new DictionaryBase('部署状态', [
{
id: -1,
name: '部署失败',
symbol: 'DeploymentFailure'
},
{
id: 0,
name: '部署中',
symbol: 'Deployed'
},
{
id: 1,
name: '部署成功',
symbol: 'DeploymentComplete'
},
{
id: 2,
name: '部署中断',
symbol: 'DeploymentInterrupt'
},
{
id: 3,
name: '待部署',
symbol: 'ToBeDeployed'
}
]);
Vue.prototype.DeploymentStatus = DeploymentStatus;
export {
TemplateLabelDict,
ScenarioTypeDict,
......@@ -475,5 +504,6 @@ export {
ModelCreationMode,
TrainingMethod,
ModeOfSpeaking,
RunningStatus
RunningStatus,
DeploymentStatus
}
<!-- 创建sft模板 -->
<template>
<el-form label-position="left" ref="form" label-width="120px" :model="form" :size="defaultFormItemSize" :rules="rules">
<el-row class="title">基本信息</el-row>
<el-form-item label="任务名称:" prop="tuningTaskDto.taskName">
<el-input v-model="form.tuningTaskDto.taskName" :readonly="isEdit||existingTask" class="inputWidth" :size="defaultFormItemSize" v-if="!(isEdit||existingTask)" ></el-input>
<span v-else>{{ form.tuningTaskDto.taskName }}</span>
<el-input v-model="form.tuningTaskDto.taskName" :readonly="isEdit || existingTask" class="inputWidth"
:size="defaultFormItemSize" v-if="!(isEdit || existingTask)"></el-input>
<span v-else>{{ form.tuningTaskDto.taskName }}</span>
</el-form-item>
<!-- <el-form-item label="任务类型:">
<el-select v-model="form.tuningTaskDto.taskType" placeholder="请选择">
......@@ -13,39 +13,41 @@
</el-select>
</el-form-item> -->
<el-form-item label="任务描述:">
<el-input v-model="form.tuningTaskDto.taskDescribe" :readonly="isEdit||existingTask" type="textarea" :rows="4" class="inputWidth" :size="defaultFormItemSize" v-if="!(isEdit||existingTask)"></el-input>
<el-input v-model="form.tuningTaskDto.taskDescribe" :readonly="isEdit || existingTask" type="textarea" :rows="4"
class="inputWidth" :size="defaultFormItemSize" v-if="!(isEdit || existingTask)"></el-input>
<span v-else>{{ form.tuningTaskDto.taskDescribe }}</span>
</el-form-item>
<el-row class="title">训练配置</el-row>
<el-row> <span class="introduce">训练任务的算法选择、参数及相关配置,训练配置参数影响训练速度及模型效果。</span></el-row>
<el-row>
<span class="introduce">训练任务的算法选择、参数及相关配置,训练配置参数影响训练速度及模型效果。</span></el-row>
<el-form-item label="选择基础模型版本:" prop="tuningRunDto.modelVersionId">
<el-cascader v-model="form.tuningRunDto.modelVersionId" :options="modelList"
:props='{ label: "name", value: "id", emitPath: false }'></el-cascader>
:props="{ label: 'name', value: 'id', emitPath: false }"></el-cascader>
</el-form-item>
<el-form-item label="训练方法:">
<el-radio v-for="item in TrainingMethod.getList()" :key="item.id" v-model="form.tuningRunDto.trainMethod" :label="item.name">{{ item.name}}</el-radio>
<el-radio v-for="item in TrainingMethod.getList()" :key="item.id" v-model="form.tuningRunDto.trainMethod"
:label="item.name">{{ item.name }}</el-radio>
</el-form-item>
<el-form-item label="参数配置:">
<parameterConfiguration v-model="form.tuningRunDto.configuration" :existingTask="existingTask"/>
<parameterConfiguration v-model="form.tuningRunDto.configuration" :existingTask="existingTask" />
</el-form-item>
<el-row class="title">数据配置</el-row>
<el-row> <span class="introduce"> 训练任务的选择数据及相关配置,支持选择该模型可使用的数据。</span></el-row>
<el-row>
<span class="introduce">
训练任务的选择数据及相关配置,支持选择该模型可使用的数据。</span></el-row>
<el-form-item label="选择数据集版本" prop="tuningRunDto.datasetVersionId">
<el-cascader v-model="form.tuningRunDto.datasetVersionId" :options="dataList"
:props='{ label: "name", value: "id", emitPath: false }'></el-cascader>
:props="{ label: 'name', value: 'id', emitPath: false }"></el-cascader>
</el-form-item>
<el-form-item label="数据拆分比例:">
<el-input-number v-model="form.tuningRunDto.splitRatio" class="inputWidth" :size="defaultFormItemSize" :min="0" :max="100"></el-input-number>
<el-input-number v-model="form.tuningRunDto.splitRatio" class="inputWidth" :size="defaultFormItemSize" :min="0"
:max="100"></el-input-number>
</el-form-item>
<el-row type="flex" justify="end" class="dialog-btn-layer mt20">
<el-button :size="defaultFormItemSize" :plain="true" @click="onCancel(false)">取消</el-button>
<el-button type="primary" :size="defaultFormItemSize" @click="onSubmit">确定</el-button>
</el-row>
......@@ -53,146 +55,170 @@
</template>
<script>
import { TuningTask, TuningRun, MyModel, MyDataSet } from '@/api/gptController.js';
import parameterConfiguration from './parameterConfiguration/index.vue';
import { TuningTask, TuningRun, MyModel, MyDataSet } from '@/api/gptController.js'
import parameterConfiguration from './parameterConfiguration/index.vue'
export default {
data () {
data() {
return {
modelList: [],
dataList: [],
form: {
'tuningRunDto': {
'configuration': undefined,
'modelId': undefined,
'publishStatus': 0,
'runName': '',
'runStatus': 0,
'runTime': 0,
'runVersion': 0,
'splitRatio': 0,
'taskId': undefined,
'trainMethod': 'full',
'trainMode': '',
tuningRunDto: {
configuration: undefined,
modelId: undefined,
publishStatus: 0,
runName: '',
runStatus: 0,
runTime: 0,
runVersion: 0,
splitRatio: 0,
taskId: undefined,
trainMethod: 'full',
trainMode: '',
datasetVersionId: undefined,
modelVersionId: undefined
},
'tuningTaskDto': {
'taskDescribe': '',
'taskName': '',
'taskType': 0
tuningTaskDto: {
taskDescribe: '',
taskName: '',
taskType: 0
}
},
rules: {
'tuningTaskDto.taskName': [
{ required: true, message: '请输入任务名称', trigger: 'blur' }
],
'tuningTaskDto.taskName': [{ required: true, message: '请输入任务名称', trigger: 'blur' }],
'tuningRunDto.modelVersionId': [{ required: true, message: '请选择基础模型版', trigger: 'blur' }],
'tuningRunDto.datasetVersionId': [{ required: true, message: '请选择数据集版本', trigger: 'blur' }]
}
};
}
},
props: ['isEdit', 'item', 'existingTask'],
components: {parameterConfiguration},
components: { parameterConfiguration },
computed: {
},
computed: {},
mounted () {
mounted() {
this.getModelList()
this.getDataList()
this.intFrom()
},
methods: {
intFrom () {
intFrom() {
if (this.item) {
this.form.tuningTaskDto = this.item.tuningTaskDto
if (this.isEdit) {
this.form.tuningRunDto = {...this.form.tuningRunDto, ...this.item.tuningRunDto}
this.form.tuningRunDto = {
...this.form.tuningRunDto,
...this.item.tuningRunDto
}
}
if (this.existingTask) {
this.form.tuningRunDto.taskId = this.item.tuningTaskDto.taskId
}
}
},
onCancel (isSuccess) {
onCancel(isSuccess) {
if (this.observer != null) {
this.observer.cancel(isSuccess);
this.observer.cancel(isSuccess)
}
},
onSubmit () {
onSubmit() {
let apiFunction = this.existingTask || this.isEdit ? TuningRun : TuningTask
return new Promise((resolve, reject) => {
this.$refs['form'].validate((valid) => {
if (valid) {
let params = {};
params = this.existingTask ? {tuningRunDto: this.form.tuningRunDto} : { ...this.form };
console.log(params);
let params = {}
params = this.existingTask ? { tuningRunDto: this.form.tuningRunDto } : { ...this.form }
console.log(params)
if (this.isEdit) {
apiFunction.update(this, params).then(res => {
resolve(res);
this.$message.success('编辑成功');
this.onCancel(true);
}).catch(e => {
reject(e);
});
apiFunction
.update(this, params)
.then((res) => {
resolve(res)
this.$message.success('编辑成功')
this.onCancel(true)
})
.catch((e) => {
reject(e)
})
} else {
apiFunction.add(this, params).then(res => {
resolve(res);
this.$message.success('添加成功');
this.onCancel(true);
}).catch(e => {
reject(e);
});
apiFunction
.add(this, params)
.then((res) => {
resolve(res)
this.$message.success('添加成功')
this.onCancel(true)
})
.catch((e) => {
reject(e)
})
}
} else {
// reject();
}
});
});
})
})
},
getModelList () {
MyModel.listForTree(this, {}).then(res => {
this.modelList = res.data.filter((item) => item.isBaseModel === 1).map((item) => {
return { id: item.modelId, name: item.modelName, children: item.modelVersionList === [] ? [] : item.modelVersionList.map((item2) => { return { id: item2.versionId, name: 'V' + item2.modelVersion } }) }
getModelList() {
MyModel.listForTree(this, {})
.then((res) => {
this.modelList = res.data
.filter((item) => item.isBaseModel === 1)
.map((item) => {
return {
id: item.modelId,
name: item.modelName,
children: item.modelVersionList === [] ? [] : item.modelVersionList.map((item2) => {
return { id: item2.versionId, name: 'V' + item2.modelVersion }
})
}
})
})
.catch((e) => {
console.log(e)
})
}).catch(e => {
console.log(e);
});
},
getDataList () {
MyDataSet.listForTree(this, {}).then(res => {
this.dataList = res.data.map((item) => {
return { id: item.datasetId, name: item.datasetName, children: item.datasetVersionList === [] ? [] : item.datasetVersionList.map((item2) => { return { id: item2.versionId, name: 'V' + item2.datasetVersion } }) }
getDataList() {
MyDataSet.listForTree(this, {})
.then((res) => {
this.dataList = res.data.map((item) => {
return {
id: item.datasetId,
name: item.datasetName,
// prettier-ignore
children: item.datasetVersionList === [] ? [] : item.datasetVersionList.map((item2) => {
return { id: item2.versionId, name: 'V' + item2.datasetVersion }
})
}
})
})
.catch((e) => {
console.log(e)
})
}).catch(e => {
console.log(e);
});
}
}
};
}
</script>
<style scoped>
.inputWidth {
width: 600px;
}
.title {
font-size: 20px;
margin-bottom: 16px;
}
.introduce {
font-size: 12px;
color: #909399;
margin-bottom: 10px;
display: block;
display: block;
}
.isReadonly input{
.isReadonly input {
border: none;
}
</style>
<!-- 参数配置-->
<template>
<el-table :data="existingTasklist" style="width: 100%">
<el-table-column prop="hyperParameter" label="超参数" width="150">
</el-table-column>
<el-table-column prop="numericalValue" label="数值" >
<template slot-scope="scope">
<component
v-if="configData"
:ref="scope.row.numericalValue"
:is="scope.row.componentOptions.component"
style="width: 100%"
v-bind="scope.row.componentOptions.property"
:value="configData[scope.row.numericalValue]||scope.row.defaultValue"
:size="defaultFormItemSize"
@input=" e => {changeValue(e, scope.row.numericalValue);}"></component>
</template>
</el-table-column>
<el-table-column prop="explain" label="说明">
</el-table-column>
</el-table>
<el-table :data="existingTasklist" style="width: 100%">
<el-table-column prop="hyperParameter" label="超参数" width="150">
</el-table-column>
<el-table-column prop="numericalValue" label="数值">
<template slot-scope="scope">
<component v-if="configData" :ref="scope.row.numericalValue" :is="scope.row.componentOptions.component" style="width: 100%" v-bind="scope.row.componentOptions.property" :value="configData[scope.row.numericalValue]||scope.row.defaultValue" :size="defaultFormItemSize" @input=" e => {changeValue(e, scope.row.numericalValue);}"></component>
</template>
</el-table-column>
<el-table-column prop="explain" label="说明">
</el-table-column>
</el-table>
</template>
<script>
export default {
data () {
data() {
return {
configData: undefined,
parameterConfiguration: [
{
......@@ -35,20 +26,23 @@ export default {
explain: '启用 4/8 比特模型量化(QLoRA)。',
componentOptions: {
component: 'el-cascader',
property:
{
options: [{
value: 'none',
label: 'none'
}, {
value: '8',
label: '8'
}, {
value: '4',
label: '4'
}],
props: { emitPath: false }
}
property: {
options: [
{
value: 'none',
label: 'none'
},
{
value: '8',
label: '8'
},
{
value: '4',
label: '4'
}
],
props: { emitPath: false }
}
}
},
{
......@@ -58,87 +52,111 @@ export default {
explain: '构建提示词时使用的模板',
componentOptions: {
component: 'el-cascader',
property:
{
options: [
{
value: 'alpaca',
label: 'alpaca'
}, {
value: 'aquila',
label: 'aquila'
}, {
value: 'baichuan',
label: 'baichuan'
}, {
value: 'baichuan2',
label: 'baichuan2'
}, {
value: 'belle',
label: 'belle'
}, {
value: 'bluelm',
label: 'bluelm'
}, {
value: 'chatglm2',
label: 'chatglm2'
}, {
value: 'chatglm3',
label: 'chatglm3'
}, {
value: 'chatglm3_raw',
label: 'chatglm3_raw'
}, {
value: 'deepseek',
label: 'deepseek'
}, {
value: 'default',
label: 'default'
}, {
value: 'falcon',
label: 'falcon'
}, {
value: 'intern',
label: 'intern'
}, {
value: 'llama2',
label: 'llama2'
}, {
value: 'llama2_zh',
label: 'llama2_zh'
}, {
value: 'mistral',
label: 'mistral'
}, {
value: 'openchat',
label: 'openchat'
}, {
value: 'qwen',
label: 'qwen'
}, {
value: 'starchat',
label: 'starchat'
}, {
value: 'vanilla',
label: 'vanilla'
}, {
value: 'vicuna',
label: 'vicuna'
}, {
value: 'xverse',
label: 'xverse'
}, {
value: 'yayi',
label: 'yayi'
}, {
value: 'zephyr',
label: 'zephyr'
}, {
value: 'ziya',
label: 'ziya'
}],
props: { emitPath: false }
}
property: {
options: [
{
value: 'alpaca',
label: 'alpaca'
},
{
value: 'aquila',
label: 'aquila'
},
{
value: 'baichuan',
label: 'baichuan'
},
{
value: 'baichuan2',
label: 'baichuan2'
},
{
value: 'belle',
label: 'belle'
},
{
value: 'bluelm',
label: 'bluelm'
},
{
value: 'chatglm2',
label: 'chatglm2'
},
{
value: 'chatglm3',
label: 'chatglm3'
},
{
value: 'chatglm3_raw',
label: 'chatglm3_raw'
},
{
value: 'deepseek',
label: 'deepseek'
},
{
value: 'default',
label: 'default'
},
{
value: 'falcon',
label: 'falcon'
},
{
value: 'intern',
label: 'intern'
},
{
value: 'llama2',
label: 'llama2'
},
{
value: 'llama2_zh',
label: 'llama2_zh'
},
{
value: 'mistral',
label: 'mistral'
},
{
value: 'openchat',
label: 'openchat'
},
{
value: 'qwen',
label: 'qwen'
},
{
value: 'starchat',
label: 'starchat'
},
{
value: 'vanilla',
label: 'vanilla'
},
{
value: 'vicuna',
label: 'vicuna'
},
{
value: 'xverse',
label: 'xverse'
},
{
value: 'yayi',
label: 'yayi'
},
{
value: 'zephyr',
label: 'zephyr'
},
{
value: 'ziya',
label: 'ziya'
}
],
props: { emitPath: false }
}
}
},
{
......@@ -148,12 +166,10 @@ export default {
explain: '输入序列分词后的最大长度。',
componentOptions: {
component: 'el-input-number',
property:
{
min: 4,
max: 8192
}
property: {
min: 4,
max: 8192
}
}
},
{
......@@ -163,11 +179,10 @@ export default {
explain: '学习率(LearningRate)是在梯度下降的过程中更新权重时的超参数,过高会导致模型难以收敛,过低则会导致模型收敛速度过慢,平台已给出默认推荐值,可根据经验调整。',
componentOptions: {
component: 'el-input-number',
property:
{
max: 0.0002,
min: 2e-7
}
property: {
max: 0.0002,
min: 2e-7
}
}
},
{
......@@ -177,11 +192,10 @@ export default {
explain: '迭代轮次(Epoch),控制训练过程中的迭代轮数。',
componentOptions: {
component: 'el-input-number',
property:
{
max: 500,
min: 0
}
property: {
max: 500,
min: 0
}
}
},
{
......@@ -191,11 +205,10 @@ export default {
explain: '每个数据集最多使用的样本数',
componentOptions: {
component: 'el-input-number',
property:
{
max: 100000,
min: 0
}
property: {
max: 100000,
min: 0
}
}
},
{
......@@ -205,17 +218,19 @@ export default {
explain: '是否启用 FP16 或 BF16 混合精度训练。',
componentOptions: {
component: 'el-cascader',
property:
{
options: [{
value: 'fp16',
label: 'fp16'
}, {
value: 'bf16',
label: 'bf16'
}],
props: { emitPath: false }
}
property: {
options: [
{
value: 'fp16',
label: 'fp16'
},
{
value: 'bf16',
label: 'bf16'
}
],
props: { emitPath: false }
}
}
},
{
......@@ -225,14 +240,13 @@ export default {
explain: '批处理大小(BatchSize)表示在每次训练迭代中使用的样本数。较大的批处理大小可以加速训练,但可能会导致内存问题。',
componentOptions: {
component: 'el-input-number',
property:
{
max: 512,
min: 1
}
property: {
max: 512,
min: 1
}
}
},
{
hyperParameter: '梯度累积',
defaultValue: 4,
......@@ -240,11 +254,10 @@ export default {
explain: '梯度累积的步数。',
componentOptions: {
component: 'el-input-number',
property:
{
max: 512,
min: 1
}
property: {
max: 512,
min: 1
}
}
},
{
......@@ -254,38 +267,46 @@ export default {
explain: '采用的学习率调节器名称。',
componentOptions: {
component: 'el-cascader',
property:
{
options: [{
value: 'linear',
label: 'linear'
}, {
value: 'cosine',
label: 'cosine'
}, {
value: 'cosine_with_restarts',
label: 'cosine_with_restarts'
}, {
value: 'polynomial',
label: 'polynomial'
}, {
value: 'constant',
label: 'constant'
}, {
value: 'constant_with_warmup',
label: 'constant_with_warmup'
}, {
value: 'inverse_sqrt',
label: 'inverse_sqrt'
}, {
value: 'reduce_lr_on_plateau',
label: 'reduce_lr_on_plateau'
}],
props: { emitPath: false }
}
property: {
options: [
{
value: 'linear',
label: 'linear'
},
{
value: 'cosine',
label: 'cosine'
},
{
value: 'cosine_with_restarts',
label: 'cosine_with_restarts'
},
{
value: 'polynomial',
label: 'polynomial'
},
{
value: 'constant',
label: 'constant'
},
{
value: 'constant_with_warmup',
label: 'constant_with_warmup'
},
{
value: 'inverse_sqrt',
label: 'inverse_sqrt'
},
{
value: 'reduce_lr_on_plateau',
label: 'reduce_lr_on_plateau'
}
],
props: { emitPath: false }
}
}
},
{
hyperParameter: '最大梯度范数',
defaultValue: 1,
......@@ -293,14 +314,13 @@ export default {
explain: '用于梯度裁剪的范数。',
componentOptions: {
component: 'el-input-number',
property:
{
max: 100000,
min: 0
}
property: {
max: 100000,
min: 0
}
}
},
{
hyperParameter: '验证集比例',
defaultValue: 0,
......@@ -308,14 +328,13 @@ export default {
explain: '验证集占全部样本的百分比。',
componentOptions: {
component: 'el-input-number',
property:
{
max: 1,
min: 0
}
property: {
max: 1,
min: 0
}
}
},
{
hyperParameter: '日志间隔',
defaultValue: 5,
......@@ -323,14 +342,13 @@ export default {
explain: '每两次日志输出间的更新步数。',
componentOptions: {
component: 'el-input-number',
property:
{
max: 1000,
min: 5
}
property: {
max: 1000,
min: 5
}
}
},
{
hyperParameter: '保存间隔',
defaultValue: 100,
......@@ -338,11 +356,10 @@ export default {
explain: '每两次断点保存间的更新步数。',
componentOptions: {
component: 'el-input-number',
property:
{
max: 5000,
min: 10
}
property: {
max: 5000,
min: 10
}
}
},
{
......@@ -352,11 +369,10 @@ export default {
explain: '学习率预热采用的步数。',
componentOptions: {
component: 'el-input-number',
property:
{
max: 5000,
min: 0
}
property: {
max: 5000,
min: 0
}
}
},
{
......@@ -366,11 +382,10 @@ export default {
explain: '嵌入向量所添加的噪声大小。',
componentOptions: {
component: 'el-input-number',
property:
{
max: 10,
min: 0
}
property: {
max: 10,
min: 0
}
}
},
{
......@@ -380,11 +395,10 @@ export default {
explain: 'LoRA 矩阵的秩。',
componentOptions: {
component: 'el-input-number',
property:
{
max: 1024,
min: 0
}
property: {
max: 1024,
min: 0
}
}
},
{
......@@ -394,11 +408,10 @@ export default {
explain: 'LoRA 权重随机丢弃的概率。',
componentOptions: {
component: 'el-input-number',
property:
{
max: 1,
min: 0
}
property: {
max: 1,
min: 0
}
}
},
{
......@@ -408,37 +421,33 @@ export default {
explain: 'DPO 损失函数中 beta 超参数大小。',
componentOptions: {
component: 'el-input-number',
property:
{
max: 1,
min: 0
}
property: {
max: 1,
min: 0
}
}
}
]
};
}
},
props: ['existingTask', 'value'],
components: {},
computed: {
existingTasklist () {
existingTasklist() {
return this.parameterConfiguration
}
},
mounted () {
mounted() {
this.$nextTick(() => {
this.init();
this.init()
})
},
methods: {
getProperty () {
},
init () {
getProperty() {},
init() {
let initConfig = {}
this.parameterConfiguration.forEach((item) => {
initConfig[item.numericalValue] = item.defaultValue
......@@ -448,27 +457,26 @@ export default {
} else {
this.configData = initConfig
}
this.$emit('input', JSON.stringify(this.configData));
this.$emit('input', JSON.stringify(this.configData))
},
isJSON (str) {
isJSON(str) {
try {
JSON.parse(str);
JSON.parse(str)
} catch (e) {
// 转换出错,抛出异常
return false;
return false
}
return true;
return true
},
changeValue (value, numericalValue) {
changeValue(value, numericalValue) {
this.configData[numericalValue] = value
this.$emit('input', JSON.stringify(this.configData));
this.$emit('input', JSON.stringify(this.configData))
}
}
}
</script>
<style >
div /deep/ .el-cascader-menu__wrap{
div /deep/ .el-cascader-menu__wrap {
height: auto;
}
</style>
......
......@@ -5,43 +5,122 @@
<div class="title">模型压缩</div>
<div class="instructions">通过量化、稀疏化等方法在尽量减少精度损失的前提下,降低AI加速卡资源占用,提高推理速度。</div>
</div>
<div class="tableBox" :style="{ height: tableHeight }">
<div
class="tableBox"
:style="{ height: tableHeight }"
>
<el-form ref="myDataSetPage" :model="myDataSetPage" label-width="75px" :size="defaultFormItemSize" label-position="right" @submit.native.prevent>
<filter-box :item-width="350" @search="refresh()" @reset="onReset">
<el-form
ref="myDataSetPage"
:model="myDataSetPage"
label-width="75px"
:size="defaultFormItemSize"
label-position="right"
@submit.native.prevent
>
<filter-box
:item-width="350"
@search="refresh()"
@reset="onReset"
>
<el-form-item label-width="0px">
<el-button class="add" type="primary" icon="el-icon-plus" :size="defaultFormItemSize" @click="add()">创建压缩任务</el-button>
<el-button
class="add"
type="primary"
icon="el-icon-plus"
:size="defaultFormItemSize"
@click="add()"
>创建压缩任务</el-button>
</el-form-item>
<el-form-item label="任务名称" prop="formFilter.taskName" label-width="70px">
<el-input class="filter-item" v-model="myDataSetPage.formFilter.taskName" :clearable="true" placeholder="任务名称" />
<el-form-item
label="任务名称"
prop="formFilter.taskName"
label-width="70px"
>
<el-input
class="filter-item"
v-model="myDataSetPage.formFilter.taskName"
:clearable="true"
placeholder="任务名称"
/>
</el-form-item>
</filter-box>
</el-form>
<vxe-table border show-header-overflow show-overflow :row-config="{ isHover: true }" :data="myDataSetPage.tableData.impl.dataList" min-height="96">
<vxe-column field="taskName" title="任务名称"></vxe-column>
<vxe-column field="taskStatus" title="任务状态">
<vxe-table
border
show-header-overflow
show-overflow
:row-config="{ isHover: true }"
:data="myDataSetPage.tableData.impl.dataList"
min-height="96"
>
<vxe-column
field="taskName"
title="任务名称"
></vxe-column>
<vxe-column
field="taskStatus"
title="任务状态"
>
<template slot-scope="scope">
{{ TaskStatus.getValue(scope.row.taskStatus) }}
</template>
{{ TaskStatus.getValue(scope.row.taskStatus) }}
</template>
</vxe-column>
<vxe-column field="sourceVersionId" title="源模型">
<vxe-column
field="sourceVersionId"
title="源模型"
>
<template slot-scope="scope">
{{ scope.row.modelTask?.versionName }}
</template>
{{ scope.row.modelTask?.versionName }}
</template>
</vxe-column>
<vxe-column field="targetVersionId" title="压缩后模型"></vxe-column>
<vxe-column field="createTime" title="创建时间"></vxe-column>
<vxe-column field="operation" title="操作">
<vxe-column
field="targetVersionId"
title="压缩后模型"
></vxe-column>
<vxe-column
field="createTime"
title="创建时间"
></vxe-column>
<vxe-column
field="operation"
title="操作"
>
<template slot-scope="scope">
<el-button type="text" :size="defaultFormItemSize" @click="particulars(scope.row)">详情</el-button>
<el-button type="text" :size="defaultFormItemSize" @click="copy(scope.row)">复制</el-button>
<el-button type="text" :size="defaultFormItemSize" @click="del(scope.row)">删除</el-button>
<el-button
type="text"
:size="defaultFormItemSize"
@click="particulars(scope.row)"
>详情</el-button>
<el-button
type="text"
:size="defaultFormItemSize"
@click="copy(scope.row)"
>复制</el-button>
<el-button
type="text"
:size="defaultFormItemSize"
@click="del(scope.row)"
>删除</el-button>
</template>
</vxe-column>
</vxe-table>
<el-row slot="pagination" type="flex" justify="end" style="margin-top: 16px;">
<el-pagination :total="myDataSetPage.tableData.impl.totalCount" :current-page="myDataSetPage.tableData.impl.currentPage" :page-size="myDataSetPage.tableData.impl.pageSize" :page-sizes="[10, 20, 50, 100]" layout="total, prev, pager, next, sizes" @current-change="myDataSetPage.tableData.impl.onCurrentPageChange" @size-change="myDataSetPage.tableData.impl.onPageSizeChange">
<el-row
slot="pagination"
type="flex"
justify="end"
style="margin-top: 16px;"
>
<el-pagination
:total="myDataSetPage.tableData.impl.totalCount"
:current-page="myDataSetPage.tableData.impl.currentPage"
:page-size="myDataSetPage.tableData.impl.pageSize"
:page-sizes="[10, 20, 50, 100]"
layout="total, prev, pager, next, sizes"
@current-change="myDataSetPage.tableData.impl.onCurrentPageChange"
@size-change="myDataSetPage.tableData.impl.onPageSizeChange"
>
</el-pagination>
</el-row>
</div>
......@@ -49,40 +128,39 @@
</template>
<script>
import { mapGetters } from 'vuex';
import { mapGetters } from 'vuex'
/* eslint-disable-next-line */
import { DropdownWidget, TableWidget, UploadWidget, ChartWidget } from '@/utils/widget.js';
import { ModelCompress } from '@/api/gptController.js';
import editOrAdd from './dialog/editOrAdd';
import particulars from './dialog/particulars';
import { TableWidget } from '@/utils/widget.js'
import { ModelCompress } from '@/api/gptController.js'
import editOrAdd from './dialog/editOrAdd'
import particulars from './dialog/particulars'
export default {
data () {
data() {
return {
myDataSetPage: {
formFilter: {
'taskName': ''
taskName: ''
},
tableData: {
impl: new TableWidget(this.getwidgetData, true, true, false, undefined, false)
}
}
};
}
},
components: {},
computed: {
...mapGetters(['getMainContextHeight']),
tableHeight () {
return this.getMainContextHeight - 145 + 'px';
tableHeight() {
return this.getMainContextHeight - 145 + 'px'
}
},
methods: {
getwidgetData (params) {
if (params == null) params = {};
getwidgetData(params) {
if (params == null) params = {}
params = {
...params,
// orderParam: [
......@@ -100,94 +178,125 @@ export default {
}
return new Promise((resolve, reject) => {
ModelCompress.list(this, params).then(res => {
resolve({
dataList: res.data.dataList,
totalCount: res.data.totalCount
});
}).catch(e => {
reject(e);
});
});
ModelCompress.list(this, params)
.then((res) => {
resolve({
dataList: res.data.dataList,
totalCount: res.data.totalCount
})
})
.catch((e) => {
reject(e)
})
})
},
particulars (item) {
this.$dialog.show('详情', particulars, {
area: ['100%', '100%']
}, {item: item}).then(res => {
}).catch(e => { });
particulars(item) {
this.$dialog
.show(
'详情',
particulars,
{
area: ['100%', '100%']
},
{ item: item }
)
.then((res) => {})
.catch((e) => {})
},
add () {
this.$dialog.show('创建模版', editOrAdd, {
area: ['100%', '100%']
}, { isEdit: false }).then(res => {
this.refresh();
}).catch(e => { });
add() {
this.$dialog
.show(
'创建模版',
editOrAdd,
{
area: ['100%', '100%']
},
{ isEdit: false }
)
.then((res) => {
this.refresh()
})
.catch((e) => {})
},
copy (item) {
this.$dialog.show('复制任务', editOrAdd, {
area: ['100%', '100%']
}, {
isCopy: true,
item: {
'createMethod': item.createMethod,
'sourceVersionId': item.sourceVersionId,
'targetModelId': item.targetModelId,
'taskDescribe': item.taskDescribe,
'taskName': item.taskName
}
}).then(res => {
this.refresh();
}).catch(e => { });
copy(item) {
this.$dialog
.show(
'复制任务',
editOrAdd,
{
area: ['100%', '100%']
},
{
isCopy: true,
item: {
createMethod: item.createMethod,
sourceVersionId: item.sourceVersionId,
targetModelId: item.targetModelId,
taskDescribe: item.taskDescribe,
taskName: item.taskName
}
}
)
.then((res) => {
this.refresh()
})
.catch((e) => {})
},
edit (item) {
this.$dialog.show('修改模版', editOrAdd, {
area: ['100%', '100%']
}, { isEdit: true, item: item }).then(res => {
this.refresh();
}).catch(e => { });
edit(item) {
this.$dialog
.show(
'修改模版',
editOrAdd,
{
area: ['100%', '100%']
},
{ isEdit: true, item: item }
)
.then((res) => {
this.refresh()
})
.catch((e) => {})
},
del (item) {
del(item) {
this.$confirm('是否确认删除', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
let params = { taskId: item.taskId }
ModelCompress.delete(this, params).then(res => {
this.$message.success('删除成功');
this.refresh()
}).catch(e => {
console.log(e);
});
}
);
ModelCompress.delete(this, params)
.then((res) => {
this.$message.success('删除成功')
this.refresh()
})
.catch((e) => {
console.log(e)
})
})
},
refresh (reloadData = false) {
refresh(reloadData = false) {
if (reloadData) {
this.myDataSetPage.tableData.impl.refreshTable(true, 1);
this.myDataSetPage.tableData.impl.refreshTable(true, 1)
} else {
this.myDataSetPage.tableData.impl.refreshTable();
this.myDataSetPage.tableData.impl.refreshTable()
}
},
onReset () {
this.$refs.myDataSetPage.resetFields();
this.refresh(true);
onReset() {
this.$refs.myDataSetPage.resetFields()
this.refresh(true)
},
formInit () {
this.refresh();
formInit() {
this.refresh()
}
},
mounted () {
mounted() {
this.formInit()
}
};
}
</script>
<style lang="scss" scoped>
@import "@/assets/style/element-variables.scss";
@import '@/assets/style/element-variables.scss';
.topBox {
background-color: white;
width: 100%;
......
<!-- 基本信息-->
<template>
<el-form label-position="left" ref="form" label-width="100px" :model="form" :size="defaultFormItemSize" :rules="rules">
<el-row class="title">基本信息</el-row>
<el-form-item label="服务名称:" prop="modelDeployDto.serviceName">
<el-input v-model="form.modelDeployDto.serviceName" class="inputWidth" placeholder="服务名称"></el-input>
<el-row>
<span class="introduce">支持中英文、数字、下划线(_),2-20个字符,不能以下划线为开头</span></el-row>
</el-form-item>
<el-form-item label="服务描述:">
<el-input type="textarea" :rows="2" v-model="form.modelDeployDto.serviceDescription" placeholder="服务描述"></el-input>
</el-form-item>
<el-form-item label="选择模型:" prop="modelDeployDto.versionId">
<el-cascader v-model="form.modelDeployDto.versionId" :options="modelList" :props='{ label: "name", value: "id", emitPath: false }'></el-cascader>
</el-form-item>
<el-form-item label="API地址:">
<el-input v-model="form.modelDeployDto.apiUrl" class="inputWidth" placeholder="API地址"></el-input>
</el-form-item>
<el-row class="title">模型配置</el-row>
<el-form-item label="资源配置:" prop="modelDeployDto.resourceInfo">
<modelConfiguration v-model="form.modelDeployDto.resourceInfo" />
</el-form-item>
<el-row type="flex" justify="end" class="dialog-btn-layer mt20">
<el-button :plain="true" @click="onCancel(false)">取消</el-button>
<el-button type="primary" @click="onSubmit">确定</el-button>
</el-row>
</el-form>
</template>
<script>
import { ModelDeployment } from '@/api/gptController.js'
import modelConfiguration from './modelConfiguration'
export default {
data() {
return {
modelList: [],
form: {
modelDeployDto: {
apiUrl: undefined,
resourceInfo: '',
serviceName: '',
serviceVersion: undefined,
versionId: undefined
}
},
rules: {
'modelDeployDto.serviceName': [{ required: true, message: '请输入服务名称', trigger: 'blur' }],
'modelDeployDto.resourceInfo': [{ required: true, message: '请选择资源配置', trigger: 'blur' }],
'modelDeployDto.versionId': [{ required: true, message: '请选择模型', trigger: 'blur' }]
}
}
},
props: ['isEdit', 'item'],
components: { modelConfiguration },
computed: {},
mounted() {
this.intFrom()
this.getModelList()
},
methods: {
intFrom() {
this.form = { ...this.form, ...this.item }
try {
this.form.templateLabel = JSON.parse(this.item.templateLabel)
} catch (error) {
// console.log(error);
}
},
onCancel(isSuccess) {
if (this.observer != null) {
this.observer.cancel(isSuccess)
}
},
onSubmit() {
return new Promise((resolve, reject) => {
this.$refs['form'].validate((valid) => {
if (valid) {
let params = {}
params = { ...this.form }
if (this.isEdit) {
ModelDeployment.update(this, params)
.then((res) => {
resolve(res)
this.$message.success('编辑成功')
this.onCancel(true)
})
.catch((e) => {
reject(e)
})
} else {
ModelDeployment.add(this, params)
.then((res) => {
resolve(res)
this.$message.success('添加成功')
this.onCancel(true)
})
.catch((e) => {
reject(e)
})
}
} else {
// reject();
}
})
})
},
getModelList() {
ModelDeployment.listForTree(this, {})
.then((res) => {
this.modelList = res.data
.filter((item) => item.isBaseModel === 1)
.map((item) => {
return {
id: item.modelId,
name: item.modelName,
children:
// prettier-ignore
item.modelVersionList === [] ? [] : item.modelVersionList.map((item2) => {
return { id: item2.versionId, name: 'V' + item2.modelVersion }
})
}
})
})
.catch((e) => {
console.log(e)
})
}
}
}
</script>
<style scoped>
.inputWidth {
width: 600px;
}
.title {
font-size: 20px;
margin-bottom: 16px;
}
.introduce {
font-size: 12px;
color: #909399;
}
</style>
<!-- 参数配置-->
<template>
<el-table :data="list" style="width: 100%" @selection-change="change">
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column prop="gpu_id" label="gpuID" width="150">
</el-table-column>
<el-table-column prop="gpu_name" label="名称">
</el-table-column>
<el-table-column prop="total_memory" label="显存总大小(M)">
</el-table-column>
<el-table-column prop="used_memory" label="使用大小(M)">
</el-table-column>
<el-table-column prop="free_memory" label="剩余大小(M)">
</el-table-column>
<el-table-column prop="gpu_util" label="显卡利用率">
<template slot-scope="scope">
{{ scope.row.gpu_util }}%
</template>
</el-table-column>
</el-table>
</template>
<script>
import { ModelDeployment } from '@/api/gptController.js'
export default {
data() {
return {
list: [],
configData: undefined
}
},
props: ['existingTask', 'value'],
components: {},
computed: {},
mounted() {
this.getGpuInfo()
},
methods: {
change(data) {
console.log(data)
this.$emit('input', JSON.stringify(data))
},
isJSON(str) {
try {
return JSON.parse(str)
} catch (e) {
// 转换出错,抛出异常
return false
}
},
getGpuInfo() {
ModelDeployment.getGpuInfo(this, {})
.then((res) => {
this.list = this.isJSON(res.data).gpu_list
})
.catch((e) => {
console.log(e)
})
}
}
}
</script>
<style >
div /deep/ .el-cascader-menu__wrap {
height: auto;
}
</style>
<!-- 模型部署 -->
<template>
<div style="position: relative">
<div class="topBox">
<div class="title">模型部署</div>
<div class="instructions"></div>
</div>
<div class="tableBox" :style="{ height: tableHeight }">
<el-form ref="myDataSetPage" :model="myDataSetPage" label-width="75px" :size="defaultFormItemSize" label-position="right" @submit.native.prevent>
<filter-box :item-width="350" @search="refresh()" @reset="onReset">
<el-form-item label-width="0px">
<el-button class="add" type="primary" icon="el-icon-plus" :size="defaultFormItemSize" @click="add()">部署模型</el-button>
</el-form-item>
<el-form-item label-width="0px"> </el-form-item>
<el-form-item label="服务名称" prop="formFilter.serviceName" label-width="120px">
<el-input class="filter-item" v-model="myDataSetPage.formFilter.serviceName" :clearable="true" placeholder="服务名称" />
</el-form-item>
</filter-box>
</el-form>
<vxe-table border show-header-overflow show-overflow :row-config="{ isHover: true }" :data="myDataSetPage.tableData.impl.dataList" min-height="96">
<vxe-column field="serviceName" title="服务名称"></vxe-column>
<vxe-column field="versionName" title="模型版本"></vxe-column>
<vxe-column field="deployStatus" title="部署状态">
<template slot-scope="scope">
{{ DeploymentStatus.getValue(scope.row.deployStatus) }}
</template>
</vxe-column>
<vxe-column field="createTime" title="创建时间"></vxe-column>
<vxe-column field="updateTime" title="更新时间"></vxe-column>
<vxe-column field="operation" title="操作">
<template slot-scope="scope">
<el-button type="text" :size="defaultFormItemSize" @click="particulars(scope.row)">详情</el-button>
<el-button type="text" :size="defaultFormItemSize" @click="stop(scope.row)">卸载</el-button>
<el-button type="text" :size="defaultFormItemSize" @click="deploy(scope.row,'start')" v-if="scope.row.deployStatus==-1||scope.row.deployStatus==2||scope.row.deployStatus==3">启动</el-button>
<el-button type="text" :size="defaultFormItemSize" @click="deploy(scope.row,'reload')">重载</el-button>
<el-button type="text" :size="defaultFormItemSize" @click="del(scope.row)">删除</el-button>
</template>
</vxe-column>
</vxe-table>
<el-row slot="pagination" type="flex" justify="end" style="margin-top: 16px">
<el-pagination :total="myDataSetPage.tableData.impl.totalCount" :current-page="myDataSetPage.tableData.impl.currentPage" :page-size="myDataSetPage.tableData.impl.pageSize" :page-sizes="[10, 20, 50, 100]" layout="total, prev, pager, next, sizes" @current-change="myDataSetPage.tableData.impl.onCurrentPageChange" @size-change="myDataSetPage.tableData.impl.onPageSizeChange">
</el-pagination>
</el-row>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
/* eslint-disable-next-line */
import { TableWidget } from '@/utils/widget.js'
import { ModelDeployment } from '@/api/gptController.js'
import editOrAdd from './dialog/editOrAdd'
import particulars from './particulars/index'
export default {
data() {
return {
myDataSetPage: {
formFilter: {
serviceName: '',
isBaseModel: 0
},
tableData: {
impl: new TableWidget(this.getwidgetData, true, true, false, undefined, false)
}
}
}
},
components: {},
computed: {
...mapGetters(['getMainContextHeight']),
tableHeight() {
return this.getMainContextHeight - 145 + 'px'
}
},
methods: {
getwidgetData(params) {
if (params == null) params = {}
params = {
modelDeployDtoFilter: {
...this.myDataSetPage.formFilter
},
...params,
// orderParam: [
// {
// asc: true,
// dateAggregateBy: '',
// fieldName: ''
// }
// ],
// pageParam: {
// pageNum: 0,
// pageSize: 0
// },
promptTemplateDtoFilter: { ...this.myDataSetPage.formFilter }
}
return new Promise((resolve, reject) => {
ModelDeployment.list(this, params)
.then((res) => {
resolve({
dataList: res.data.dataList,
totalCount: res.data.totalCount
})
})
.catch((e) => {
reject(e)
})
})
},
add() {
this.$dialog
.show(
'创建服务',
editOrAdd,
{
area: ['100%', '100%']
},
{ isEdit: false }
)
.then((res) => {
this.refresh()
})
.catch((e) => {})
},
edit(item) {
this.$dialog
.show(
'修改服务',
editOrAdd,
{
area: ['100%', '100%']
},
{ isEdit: true, item: item }
)
.then((res) => {
this.refresh()
})
.catch((e) => {})
},
del(item) {
this.$confirm('是否确认删除', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
let params = { deployId: item.deployId }
ModelDeployment.delete(this, params)
.then((res) => {
this.$message.success('删除成功')
this.refresh()
})
.catch((e) => {
console.log(e)
})
})
},
particulars(item) {
this.$dialog
.show(
'详情',
particulars,
{
area: ['100%', '100%']
},
{ tableItem: item }
)
.then((res) => {
this.refresh()
})
.catch((e) => {})
},
deploy(item, type) {
// 部署
this.$confirm('是否确认部署', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
let params = { modelDeployDto: { deployId: item.deployId }, type }
ModelDeployment.deploy(this, params)
.then((res) => {
this.$message.success('部署成功')
this.refresh()
})
.catch((e) => {
console.log(e)
})
})
},
stop(item) {
// 卸载
this.$confirm('是否确认卸载', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
let params = { modelDeployDto: { deployId: item.deployId } }
ModelDeployment.stop(this, params)
.then((res) => {
this.$message.success('卸载成功')
this.refresh()
})
.catch((e) => {
console.log(e)
})
})
},
refresh(reloadData = false) {
if (reloadData) {
this.myDataSetPage.tableData.impl.refreshTable(true, 1)
} else {
this.myDataSetPage.tableData.impl.refreshTable()
}
},
onReset() {
this.$refs.myDataSetPage.resetFields()
this.refresh(true)
},
formInit() {
this.refresh()
}
},
mounted() {
this.formInit()
}
}
</script>
<style lang="scss" scoped>
@import '@/assets/style/element-variables.scss';
.topBox {
background-color: white;
width: 100%;
height: 95px;
margin-bottom: 16px;
.title {
color: $--color-text-primary;
font-size: 16px;
font-weight: 500;
margin-bottom: 8px;
padding: 20px 20px 10px 20px;
}
}
.instructions {
padding: 0px 20px 20px 20px;
.describe {
color: $--color-text-secondary;
margin-bottom: 16px;
}
.itemTitle {
color: $--color-text-primary;
font-size: 16px;
font-weight: 500;
margin-bottom: 8px;
}
.head-index {
font-size: 24px;
color: #e8e9eb;
line-height: 32px;
}
.itemDescribe {
width: 170px;
color: $--color-text-secondary;
}
.img {
height: 72px;
width: 140px;
}
}
.tableBox {
background-color: white;
width: 100%;
padding: 20px;
overflow: auto;
.add {
margin-bottom: 20px;
}
}
</style>
<!-- 详情 -->
<template>
<div style="position: relative">
<el-form label-position="left" ref="form" label-width="100px" :size="defaultFormItemSize">
<el-row class="title">基本信息</el-row>
<el-form-item label="服务名称:" prop="modelManageDto.serviceName">
{{ tableItem.serviceName }}
</el-form-item>
<el-form-item label="服务描述:">
{{ tableItem.serviceDescription }}
</el-form-item>
<el-form-item label="选择模型:">
{{ tableItem.modelName }}
</el-form-item>
<el-form-item label="API地址:">{{ tableItem.apiUrl}} </el-form-item>
<el-row class="title">模型配置</el-row>
<el-form-item label="资源配置:">
<el-table :data="getResourceInfoList" style="width: 100%">
<el-table-column prop="gpu_id" label="gpuID" width="150">
</el-table-column>
<el-table-column prop="gpu_name" label="名称">
</el-table-column>
<el-table-column prop="total_memory" label="显存总大小(M)">
</el-table-column>
<el-table-column prop="used_memory" label="使用大小(M)">
</el-table-column>
<el-table-column prop="free_memory" label="剩余大小(M)">
</el-table-column>
<el-table-column prop="gpu_util" label="显卡利用率">
<template slot-scope="scope">
{{ scope.row.gpu_util }}%
</template>
</el-table-column>
</el-table>
</el-form-item>
</el-form>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
data() {
return {}
},
components: {},
props: ['tableItem'],
computed: {
...mapGetters(['getMainContextHeight']),
tableHeight() {
return this.getMainContextHeight - 95 + 'px'
},
getResourceInfoList() {
return JSON.parse(this.tableItem.resourceInfo)
}
},
methods: {},
mounted() {}
}
</script>
<style lang="scss" scoped>
@import '@/assets/style/element-variables.scss';
.topBox {
background-color: white;
width: 100%;
height: 95px;
margin-bottom: 16px;
.title {
color: $--color-text-primary;
font-size: 16px;
font-weight: 500;
margin-bottom: 8px;
padding: 20px 20px 10px 20px;
}
}
.instructions {
padding: 0px 20px 20px 20px;
.describe {
color: $--color-text-secondary;
margin-bottom: 16px;
}
.itemTitle {
color: $--color-text-primary;
font-size: 16px;
font-weight: 500;
margin-bottom: 8px;
}
.head-index {
font-size: 24px;
color: #e8e9eb;
line-height: 32px;
}
.itemDescribe {
width: 170px;
color: $--color-text-secondary;
}
.img {
height: 72px;
width: 140px;
}
}
.tableBox {
background-color: white;
width: 100%;
padding: 20px;
overflow: auto;
.add {
margin-bottom: 20px;
}
}
/deep/ .el-descriptions__table {
width: 100%;
}
</style>
<!-- 参数配置-->
<template>
<el-table :data="existingTasklist" style="width: 100%">
<el-table-column prop="hyperParameter" label="超参数" width="150">
</el-table-column>
<el-table-column prop="numericalValue" label="数值" >
<template slot-scope="scope">
<component
v-if="configData"
:ref="scope.row.numericalValue"
:is="scope.row.componentOptions.component"
style="width: 100%"
v-bind="scope.row.componentOptions.property"
:value="configData[scope.row.numericalValue]||scope.row.defaultValue"
:size="defaultFormItemSize"
@input=" e => {changeValue(e, scope.row.numericalValue);}"></component>
</template>
</el-table-column>
<el-table-column prop="explain" label="说明">
</el-table-column>
</el-table>
<el-table :data="existingTasklist" style="width: 100%">
<el-table-column prop="hyperParameter" label="超参数" width="150">
</el-table-column>
<el-table-column prop="numericalValue" label="数值">
<template slot-scope="scope">
<component v-if="configData" :ref="scope.row.numericalValue" :is="scope.row.componentOptions.component" style="width: 100%" v-bind="scope.row.componentOptions.property" :value="configData[scope.row.numericalValue]||scope.row.defaultValue" :size="defaultFormItemSize" @input=" e => {changeValue(e, scope.row.numericalValue);}"></component>
</template>
</el-table-column>
<el-table-column prop="explain" label="说明">
</el-table-column>
</el-table>
</template>
<script>
export default {
data () {
data() {
return {
configData: undefined,
parameterConfiguration: [
......@@ -34,20 +26,23 @@ export default {
explain: '启用 4/8 比特模型量化(QLoRA)。',
componentOptions: {
component: 'el-cascader',
property:
{
options: [{
value: 'none',
label: 'none'
}, {
value: '8',
label: '8'
}, {
value: '4',
label: '4'
}],
props: { emitPath: false }
}
property: {
options: [
{
value: 'none',
label: 'none'
},
{
value: '8',
label: '8'
},
{
value: '4',
label: '4'
}
],
props: { emitPath: false }
}
}
},
{
......@@ -57,87 +52,111 @@ export default {
explain: '构建提示词时使用的模板',
componentOptions: {
component: 'el-cascader',
property:
{
options: [
{
value: 'alpaca',
label: 'alpaca'
}, {
value: 'aquila',
label: 'aquila'
}, {
value: 'baichuan',
label: 'baichuan'
}, {
value: 'baichuan2',
label: 'baichuan2'
}, {
value: 'belle',
label: 'belle'
}, {
value: 'bluelm',
label: 'bluelm'
}, {
value: 'chatglm2',
label: 'chatglm2'
}, {
value: 'chatglm3',
label: 'chatglm3'
}, {
value: 'chatglm3_raw',
label: 'chatglm3_raw'
}, {
value: 'deepseek',
label: 'deepseek'
}, {
value: 'default',
label: 'default'
}, {
value: 'falcon',
label: 'falcon'
}, {
value: 'intern',
label: 'intern'
}, {
value: 'llama2',
label: 'llama2'
}, {
value: 'llama2_zh',
label: 'llama2_zh'
}, {
value: 'mistral',
label: 'mistral'
}, {
value: 'openchat',
label: 'openchat'
}, {
value: 'qwen',
label: 'qwen'
}, {
value: 'starchat',
label: 'starchat'
}, {
value: 'vanilla',
label: 'vanilla'
}, {
value: 'vicuna',
label: 'vicuna'
}, {
value: 'xverse',
label: 'xverse'
}, {
value: 'yayi',
label: 'yayi'
}, {
value: 'zephyr',
label: 'zephyr'
}, {
value: 'ziya',
label: 'ziya'
}],
props: { emitPath: false }
}
property: {
options: [
{
value: 'alpaca',
label: 'alpaca'
},
{
value: 'aquila',
label: 'aquila'
},
{
value: 'baichuan',
label: 'baichuan'
},
{
value: 'baichuan2',
label: 'baichuan2'
},
{
value: 'belle',
label: 'belle'
},
{
value: 'bluelm',
label: 'bluelm'
},
{
value: 'chatglm2',
label: 'chatglm2'
},
{
value: 'chatglm3',
label: 'chatglm3'
},
{
value: 'chatglm3_raw',
label: 'chatglm3_raw'
},
{
value: 'deepseek',
label: 'deepseek'
},
{
value: 'default',
label: 'default'
},
{
value: 'falcon',
label: 'falcon'
},
{
value: 'intern',
label: 'intern'
},
{
value: 'llama2',
label: 'llama2'
},
{
value: 'llama2_zh',
label: 'llama2_zh'
},
{
value: 'mistral',
label: 'mistral'
},
{
value: 'openchat',
label: 'openchat'
},
{
value: 'qwen',
label: 'qwen'
},
{
value: 'starchat',
label: 'starchat'
},
{
value: 'vanilla',
label: 'vanilla'
},
{
value: 'vicuna',
label: 'vicuna'
},
{
value: 'xverse',
label: 'xverse'
},
{
value: 'yayi',
label: 'yayi'
},
{
value: 'zephyr',
label: 'zephyr'
},
{
value: 'ziya',
label: 'ziya'
}
],
props: { emitPath: false }
}
}
},
{
......@@ -147,12 +166,10 @@ export default {
explain: '输入序列分词后的最大长度。',
componentOptions: {
component: 'el-input-number',
property:
{
min: 4,
max: 8192
}
property: {
min: 4,
max: 8192
}
}
},
{
......@@ -162,11 +179,10 @@ export default {
explain: '每个数据集最多使用的样本数',
componentOptions: {
component: 'el-input-number',
property:
{
max: 100000,
min: 0
}
property: {
max: 100000,
min: 0
}
}
},
{
......@@ -176,11 +192,10 @@ export default {
explain: '批处理大小(BatchSize)表示在每次训练迭代中使用的样本数。较大的批处理大小可以加速训练,但可能会导致内存问题。',
componentOptions: {
component: 'el-input-number',
property:
{
max: 512,
min: 1
}
property: {
max: 512,
min: 1
}
}
},
{
......@@ -190,11 +205,10 @@ export default {
explain: '最大生成长度',
componentOptions: {
component: 'el-input-number',
property:
{
max: 2048,
min: 10
}
property: {
max: 2048,
min: 10
}
}
},
{
......@@ -204,12 +218,11 @@ export default {
explain: 'Top-p 采样值',
componentOptions: {
component: 'el-input-number',
property:
{
max: 1,
min: 0.01,
step: 0.01
}
property: {
max: 1,
min: 0.01,
step: 0.01
}
}
},
{
......@@ -219,39 +232,34 @@ export default {
explain: '温度系数',
componentOptions: {
component: 'el-input-number',
property:
{
max: 1.5,
min: 0.01,
step: 0.01
}
property: {
max: 1.5,
min: 0.01,
step: 0.01
}
}
}
]
};
}
},
props: ['existingTask', 'value'],
components: {},
computed: {
existingTasklist () {
existingTasklist() {
return this.parameterConfiguration
}
},
mounted () {
mounted() {
this.$nextTick(() => {
this.init();
this.init()
})
},
methods: {
getProperty () {
},
init () {
getProperty() {},
init() {
let initConfig = {}
this.parameterConfiguration.forEach((item) => {
initConfig[item.numericalValue] = item.defaultValue
......@@ -261,28 +269,27 @@ export default {
} else {
this.configData = initConfig
}
this.$emit('input', JSON.stringify(this.configData));
this.$emit('input', JSON.stringify(this.configData))
},
isJSON (str) {
isJSON(str) {
try {
JSON.parse(str);
JSON.parse(str)
} catch (e) {
// 转换出错,抛出异常
return false;
return false
}
return true;
return true
},
changeValue (value, numericalValue) {
changeValue(value, numericalValue) {
this.configData[numericalValue] = value
this.$emit('input', JSON.stringify(this.configData));
this.$emit('input', JSON.stringify(this.configData))
}
}
}
</script>
<style >
div /deep/ .el-cascader-menu__wrap{
div /deep/ .el-cascader-menu__wrap {
height: auto;
}
</style>
......@@ -2,13 +2,19 @@
<template>
<el-form label-position="left" ref="form" label-width="120px" :model="form" :size="defaultFormItemSize" style="padding:20px;width:400px" v-loading.fullscreen.lock="fullscreenLoading">
<el-form-item label="问答模式:">
<el-select v-model="form.pattern" placeholder="请选择" @change="patternChange">
<el-select v-model="form.pattern" placeholder="请选择" @change="patternChange">
<el-option v-for="item in ModeOfSpeaking.getList()" :key="item.id" :label="item.name" :value="item.name">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="模型选择:">
<!-- <el-form-item label="模型选择:">
<el-cascader v-model="form.model_name" ref="modelCascader" :options="modelList" :props='{ label: "name", value: "name", emitPath: false }' @change="changeModel"></el-cascader>
</el-form-item> -->
<el-form-item label="服务选择:">
<el-select ref="serveCascader" v-model="form.model_name" placeholder="请选择">
<el-option v-for="item in serveList" :key="item.createUserId" :label="item.serviceName" :value="item.versionName">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="Temperature:">
<el-slider v-model="temperature" :format-tooltip="formatTooltip" @change="form.temperature = temperature / 100"></el-slider>
......@@ -41,7 +47,7 @@
</el-option>
</el-select>
<div class="el-upload__tip" >{{knowledgeDescribe}}</div>
<div class="el-upload__tip">{{knowledgeDescribe}}</div>
</el-form-item>
<el-form-item label="匹配知识条数:" style="margin-bottom:30px">
......@@ -69,19 +75,19 @@
</el-collapse-item>
</el-collapse>
</el-form-item>
<el-form-item label-width="0px" v-if="form.pattern == '文件对话'">
<el-form-item label-width="0px" v-if="form.pattern == '基于文件问答'">
<el-collapse value="1">
<el-collapse-item name="1">
<template slot="title">文件配置</template>
<el-form-item label="上传文件:" style="margin-bottom:30px">
<el-button @click="clickUp" :size="defaultFormItemSize" type="primary">选择文件</el-button>
<input style="display:none" ref="upFile" type="file" @change="fileinfo($event.target.files)" multiple accept=".html, .md, .json, .jsonl, .csv, .pdf, .png, .jpg, .jpeg, .bmp, .eml, .msg, .epub, .xlsx, .xls, .ipynb, .odt, .py, .rst, .rtf, .srt, .toml, .tsv, .docx, .doc, .xml, .ppt, .pptx, .txt, .htm">
<div class="el-upload__tip" >可上传HTML, MD, JSON, JSONL, CSV, PDF, PNG, JPG, JPEG, BMP, EML, MSG, EPUB, XLSX, XLSD, IPYNB, ODT, PY, RST, RTF, SRT, TOML, TSV, DOCX, DOC, XML, PPT, PPTX, TXT, HTM文件</div>
<div class="itemFile" v-for="(item,index) in files" :key="item.name"><i class="el-icon-document" style="color:#909399;margin-right:5px"></i>{{ item.name }}
<input style="display:none" ref="upFile" type="file" @change="fileinfo($event.target.files)" multiple accept=".html, .md, .json, .jsonl, .csv, .pdf, .png, .jpg, .jpeg, .bmp, .eml, .msg, .epub, .xlsx, .xls, .ipynb, .odt, .py, .rst, .rtf, .srt, .toml, .tsv, .docx, .doc, .xml, .ppt, .pptx, .txt, .htm">
<div class="el-upload__tip">可上传HTML, MD, JSON, JSONL, CSV, PDF, PNG, JPG, JPEG, BMP, EML, MSG, EPUB, XLSX, XLSD, IPYNB, ODT, PY, RST, RTF, SRT, TOML, TSV, DOCX, DOC, XML, PPT, PPTX, TXT, HTM文件</div>
<div class="itemFile" v-for="(item,index) in files" :key="item.name"><i class="el-icon-document" style="color:#909399;margin-right:5px"></i>{{ item.name }}
<i class="el-icon-circle-close" style="color:#0092FF;cursor: pointer;" @click="clearFile(index)"></i>
</div>
<el-button style="display:block;margin-top:10px" :size="defaultFormItemSize" type="primary" @click="uploadFiles" :disabled="files.length===0" >上传</el-button>
<el-button style="display:block;margin-top:10px" :size="defaultFormItemSize" type="primary" @click="uploadFiles" :disabled="files.length===0">上传</el-button>
</el-form-item>
<el-form-item label="匹配知识条数:" style="margin-bottom:30px">
<el-input-number v-model="form.fileConfige.top_k" :min="1" :max="20"></el-input-number>
......@@ -97,7 +103,7 @@
<el-collapse-item name="1">
<template slot="title">知识图谱配置</template>
<el-form-item label="请选择知识图谱:" style="margin-bottom:30px">
<el-select ref="knowledgeSelect" v-model="form.knowledgeGraphConfige. knowledge_graph_name" placeholder="请选择" >
<el-select ref="knowledgeSelect" v-model="form.knowledgeGraphConfige. knowledge_graph_name" placeholder="请选择">
<el-option v-for="item in []" :key="item.knowledgeId" :label="item.knowledgeGraphName" :value="item.knowledgeGraphName">
</el-option>
</el-select>
......@@ -116,10 +122,10 @@
</template>
<script>
import { KnowledgeManage, MyModel, ModelVersion, TemplateController } from '@/api/gptController.js';
import promptWordTemplate from '../promptWordTemplate';
import { KnowledgeManage, MyModel, ModelVersion, TemplateController, ModelDeployment } from '@/api/gptController.js'
import promptWordTemplate from '../promptWordTemplate'
export default {
data () {
data() {
return {
knowledgeDescribe: '',
files: [],
......@@ -128,6 +134,7 @@ export default {
promptTemplate: '',
templateControllerList: [],
modelList: [],
serveList: [],
activeModelList: [],
loading: undefined,
temperature: 70,
......@@ -141,28 +148,30 @@ export default {
temperature: 0.7,
prompt_template: '',
heistoryRotate: 10, // 历史对话轮数
knowledgeConfige: {// 知识库配置
knowledgeConfige: {
// 知识库配置
knowledge_base_name: '',
top_k: 1,
score_threshold: 0.5
},
searchConfige: {// 搜索引擎配置
searchConfige: {
// 搜索引擎配置
search_engine_name: 'bing',
top_k: 1
},
fileConfige: {// 文件对哈配置
fileConfige: {
// 文件对哈配置
top_k: 1,
score_threshold: 0.5,
knowledge_id: undefined,
// max_tokens: 0,
prompt_name: 'default'
},
knowledgeGraphConfige: {// 知识图谱对话
knowledgeGraphConfige: {
// 知识图谱对话
knowledge_graph_name: '',
top_k: 1,
score_threshold: 0.5
}
},
filesForm: {
......@@ -171,177 +180,216 @@ export default {
chunk_overlap: 50,
zh_title_enhance: false
}
};
}
},
components: {},
computed: {
},
computed: {},
watch: {
form: {
handler (newVal, oldVal) {
handler(newVal, oldVal) {
this.$emit('chatForm', this.form)
},
deep: true, // 是否深度监听
immediate: true // 是否在组件创建时立即执行回调函数
}
},
mounted () {
mounted() {
this.getKnowledgeList()
this.getModelList()
// this.getModelList()
this.getTemplateControllerList()
this.getServeList()
},
methods: {
getTemplateControllerList () {
TemplateController.listForTree(this, {}).then(res => {
this.templateControllerList = res.data.map((item) => {
return {
templateId: item.templateId,
label: item.templateName,
value: item.templateContent,
parameterFormat: item.parameterFormat
}
getTemplateControllerList() {
TemplateController.listForTree(this, {})
.then((res) => {
this.templateControllerList = res.data.map((item) => {
return {
templateId: item.templateId,
label: item.templateName,
value: item.templateContent,
parameterFormat: item.parameterFormat
}
})
})
.catch((e) => {
console.log(e)
})
}).catch(e => {
console.log(e);
});
},
getModelList () {
MyModel.listForTree(this, {}).then(res => {
this.modelList = res.data.map((item) => {
return { id: item.modelId, name: item.modelName, children: item.modelVersionList === [] ? [] : item.modelVersionList.map((item2) => { return { id: item2.versionId, name: item2.versionName } }) }
getServeList() {
ModelDeployment.canUseList(this, {})
.then((res) => {
console.log(res)
this.serveList = res?.data?.dataList
this.form.model_name = this.serveList[0].versionName
})
.catch((e) => {
console.log(e)
})
},
getModelList() {
MyModel.listForTree(this, {})
.then((res) => {
this.modelList = res.data.map((item) => {
return {
id: item.modelId,
name: item.modelName,
// prettier-ignore
children: item.modelVersionList === [] ? [] : item.modelVersionList.map((item2) => {
return { id: item2.versionId, name: item2.versionName }
})
}
})
this.getActiveModelList()
}).catch(e => {
console.log(e);
});
this.getActiveModelList()
})
.catch((e) => {
console.log(e)
})
},
getKnowledgeList () {
getKnowledgeList() {
let params = {}
KnowledgeManage.load(this, params).then(res => {
this.knowledgeList = res.data
}).catch(e => {
console.log(e);
});
KnowledgeManage.load(this, params)
.then((res) => {
this.knowledgeList = res.data
})
.catch((e) => {
console.log(e)
})
},
getActiveModelList () { // 获取当前挂载上的模型列表
getActiveModelList() {
// 获取当前挂载上的模型列表
let params = {}
ModelVersion.listModels(this, params).then(res => {
this.activeModelList = res.data
if (this.activeModelList.length === 0) {
this.form.model_name = this.modelList[0].children[0].name
this.switchModel(this.modelList[0].children[0].id)
} else {
this.form.model_name = this.activeModelList[0]
}
}).catch(e => {
console.log(e);
});
ModelVersion.listModels(this, params)
.then((res) => {
this.activeModelList = res.data
if (this.activeModelList.length === 0) {
this.form.model_name = this.modelList[0].children[0].name
this.switchModel(this.modelList[0].children[0].id)
} else {
this.form.model_name = this.activeModelList[0]
}
})
.catch((e) => {
console.log(e)
})
},
openLoading (text) {
openLoading(text) {
this.loading = this.$loading({
lock: true,
text: text,
customClass: 'myLoading',
spinner: 'el-icon-loading',
background: 'rgba(255, 255, 255, 0.9)'
});
})
// loading.close();
},
formatTooltip (val) {
return val / 100;
formatTooltip(val) {
return val / 100
},
switchModel (versionId) { // 切换模型
switchModel(versionId) {
// 切换模型
this.openLoading('LLM模型加载中')
ModelVersion.change(this, { versionId: versionId }).then(res => {
this.loading.close();
}).catch(e => {
this.loading.close();
console.log(e);
});
ModelVersion.change(this, { versionId: versionId })
.then((res) => {
this.loading.close()
})
.catch((e) => {
this.loading.close()
console.log(e)
})
},
changeModel (data) { // 修改模型
changeModel(data) {
// 修改模型
// this.openLoading('LLM模型加载中')
let id = this.$refs.modelCascader.getCheckedNodes()[0].data.id
this.switchModel(id)
},
changeKnowledge (data) { // 修改知识库
changeKnowledge(data) {
// 修改知识库
// this.openLoading('知识库加载中')
this.knowledgeDescribe = this.knowledgeList.filter((item) => {
return item.knowledgeCode === data
})[0].knowledgeDescribe
},
changeSe (data) { // 修改模型引擎
changeSe(data) {
// 修改模型引擎
// this.openLoading('模型引擎加载中')
// console.log(this.$refs.searchSelect);
},
templateControllerChange (data) {
templateControllerChange(data) {
if (!data) {
this.form.prompt_template = ''
return
}
this.$dialog.show(data.label, promptWordTemplate, {
area: ['50%', '40%']
}, { data: data }).then(res => {
this.form.prompt_template = res
}).catch(e => {
this.promptTemplate = undefined
});
this.$dialog
.show(
data.label,
promptWordTemplate,
{
area: ['50%', '40%']
},
{ data: data }
)
.then((res) => {
this.form.prompt_template = res
})
.catch((e) => {
this.promptTemplate = undefined
})
},
changePromptTemplate () {
this.$bus.$emit('isPromptTemplate', this.isPromptTemplate);
changePromptTemplate() {
this.$bus.$emit('isPromptTemplate', this.isPromptTemplate)
},
fileinfo (files) {
fileinfo(files) {
for (const key in files) {
if (Object.hasOwnProperty.call(files, key)) {
const element = files[key];
const element = files[key]
if (this.files.map((item) => item.name).indexOf(element.name) === -1) {
this.files.push(element)
this.filesForm.filesArr = this.files
} else {
console.log('重复上传');
console.log('重复上传')
}
}
}
},
clickUp () {
clickUp() {
this.$refs.upFile.click()
},
clearFile (index) {
clearFile(index) {
this.files.splice(index, 1)
},
uploadFiles () {
uploadFiles() {
this.fullscreenLoading = true
let params = this.filesForm
this.upload('/2api/knowledge_base/upload_temp_docs', params, false).then(res => {
this.$message.success('上传成功');
this.fullscreenLoading = false;
this.form.fileConfige.knowledge_id = res.data.id
}).catch(e => {
console.log(e);
});
this.upload('/2api/knowledge_base/upload_temp_docs', params, false)
.then((res) => {
this.$message.success('上传成功')
this.fullscreenLoading = false
this.form.fileConfige.knowledge_id = res.data.id
})
.catch((e) => {
console.log(e)
})
},
patternChange () {
patternChange() {
// console.log(111);
// Object.assign(this.$data.form, this.$options.data().form);
}
}
}
</script>
<style scoped>
.myLoading .el-loading-spinner i {
font-size: 24px !important;
}
.el-upload__tip{
.el-upload__tip {
line-height: normal;
font-size: 12px !important;
}
......
<!-- 右侧聊天界面 -->
<template>
<div class="box"
ref="box">
<div class="contentBox"
ref="contentBox"
v-if="myHistory.length > 0">
<div v-for="item in myHistory"
:key="item.id">
<div class="box" ref="box">
<div class="contentBox" ref="contentBox" v-if="myHistory.length > 0">
<div v-for="item in myHistory" :key="item.id">
<div class="userBox">
<div class="content">
<contentView :content="item.content" />
......@@ -15,19 +11,15 @@
{{ item.role }}
</div>
</div>
<div v-if="item.answer"
class="gptBox">
<div v-if="item.answer" class="gptBox">
<div class="icon">GPT</div>
<div class="content">
<contentView :content="item.answer"
:ref="'contentView' + item.id" />
<contentView :content="item.answer" :ref="'contentView' + item.id" />
</div>
</div>
</div>
</div>
<div class="initBox"
ref="initBox"
v-else>
<div class="initBox" ref="initBox" v-else>
<div class="text">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;你好,<br />
我是人工智能语言模型<br />
......@@ -35,32 +27,22 @@
</div>
</div>
<div class="inputBox">
<el-input placeholder="请输入内容"
v-model="inputContent"
class="input-with-select"
@keyup.enter.native="submit">
<el-button slot="append"
icon="el-icon-position"
@click="submit"></el-button>
<el-input placeholder="请输入内容" v-model="inputContent" class="input-with-select" @keyup.enter.native="submit">
<el-button slot="append" icon="el-icon-position" @click="submit"></el-button>
</el-input>
<el-button icon="el-icon-delete"
style="margin-left: 10px"
@click="clear"
type="danger"
plain></el-button>
<el-button icon="el-icon-delete" style="margin-left: 10px" @click="clear" type="danger" plain></el-button>
</div>
<div id="network"></div>
</div>
</template>
<script>
import { GetStreaming } from '@/utils/getStreaming.js';
import { GetStreaming } from '@/utils/getStreaming.js'
// import codePreview from '../codePreview';
import contentView from '../contentView';
import contentView from '../contentView'
export default {
data () {
data() {
return {
templateController: undefined,
isPromptTemplate: true,
......@@ -71,38 +53,35 @@ export default {
query: null,
history: [],
prompt_template: '',
'stream': true,
'model_name': '',
'temperature': 0.7
stream: true,
model_name: '',
temperature: 0.7
}
};
}
},
props: ['chatForm'],
components: { contentView },
computed: {
},
computed: {},
mounted () {
mounted() {
this.$bus.$on('isPromptTemplate', (data) => {
this.isPromptTemplate = data
})
},
beforeDestroy () {
beforeDestroy() {
// 移除监听事件 "share"
this.$bus.$off('isPromptTemplate')
},
methods: {
clear () {
clear() {
this.param.query = null
this.param.history = []
this.inputContent = null
this.myHistory = []
},
submit () {
submit() {
this.param.model_name = this.chatForm.model_name
this.param.temperature = this.chatForm.temperature
this.heistoryRotate = this.chatForm.heistoryRotate
......@@ -120,7 +99,7 @@ export default {
apiUrl = '/2api/chat/file_chat'
this.param = { ...this.param, ...this.chatForm.fileConfige }
if (!this.chatForm.fileConfige.knowledge_id) {
this.$message.error('请先上传文件');
this.$message.error('请先上传文件')
return
}
} else if (this.chatForm.pattern === '知识图谱问答') {
......@@ -128,54 +107,60 @@ export default {
this.param = { ...this.param, ...this.chatForm.knowledgeGraphConfige }
}
if (!this.inputContent) return
this.param.query = this.inputContent;
this.param.query = this.inputContent
this.myHistory.push({
'role': 'user',
'content': this.inputContent,
'answer': '',
'excludeReferenceAnswer': '',
'id': this.generateRandomString(8)
role: 'user',
content: this.inputContent,
answer: '',
excludeReferenceAnswer: '',
id: this.generateRandomString(8)
})
this.inputContent = null;
this.inputContent = null
this.param.history = []
this.myHistory.slice(0, -1).slice(-this.heistoryRotate).forEach((item) => {
this.param.history.push(...[{ role: item.role, content: item.content }, { role: 'assistant', content: item.excludeReferenceAnswer }])
})
this.myHistory
.slice(0, -1)
.slice(-this.heistoryRotate)
.forEach((item) => {
this.param.history.push(
...[
{ role: item.role, content: item.content },
{ role: 'assistant', content: item.excludeReferenceAnswer }
]
)
})
this.$emit('submit')
let getData = new GetStreaming(apiUrl, this.param, this.onmessage, this.setSuccess)
getData.initeventSource()
},
setSuccess () {
setSuccess() {
this.$nextTick(() => {
let nowChat = this.myHistory[this.myHistory.length - 1]
this.$refs['contentView' + nowChat.id][0].isSuccess()
})
},
onmessage (data) {
onmessage(data) {
let nowChat = this.myHistory[this.myHistory.length - 1]
if (this.chatForm.pattern === '通用智能问答') {
// data = data.replace(/^data:\s+|\s+$/g, '')
nowChat.excludeReferenceAnswer += data
nowChat.answer += data;
nowChat.answer += data
} else if (this.chatForm.pattern === '专业知识库问答') {
console.log(data);
// console.log(data)
let temporary = JSON.parse(`[${data}]`.replace(/}{/g, '},{'))
temporary.forEach((item) => {
this.modifyContent(item)// 修改返回内容
this.modifyContent(item) // 修改返回内容
nowChat.excludeReferenceAnswer += item.answer || '' // 排除回答中的引用内容
nowChat.answer += item.answer || '\n' + item.docs
})
} else if (this.chatForm.pattern === '搜索引擎问答') {
} else if (this.chatForm.pattern === '基于文件问答') {
let temporary = JSON.parse(`[${data}]`.replace(/}{/g, '},{'))
temporary.forEach((item) => {
this.modifyContent(item)// 修改返回内容
this.modifyContent(item) // 修改返回内容
nowChat.excludeReferenceAnswer += item.answer || '' // 排除回答中的引用内容
nowChat.answer += item.answer || '\n' + item.docs
})
......@@ -183,8 +168,8 @@ export default {
let temporary = JSON.parse(`[${data}]`.replace(/}{/g, '},{'))
temporary.forEach((item) => {
console.log(item);
this.modifyContent(item)// 修改返回内容
console.log(item)
this.modifyContent(item) // 修改返回内容
nowChat.excludeReferenceAnswer += item.answer || '' // 排除回答中的引用内容
nowChat.answer += item.answer || '\n' + item.docs.join()
// nowChat.answer += item.answer += '\n' + item.docs.join()
......@@ -195,36 +180,37 @@ export default {
this.$refs.contentBox.scrollTo(0, this.$refs.contentBox.scrollHeight)
})
},
modifyContent (item) { // 修改返回内容
modifyContent(item) {
// 修改返回内容
if (item.docs) {
item.docs = item.docs.map((item2) => {
let tagUrl = ((item2?.match(/\]\((.*?)\)/g) || [])[0] || '').slice(2, -1)
let url = ''
// item2 = item2.replace(/\n/g, '<br>')
if (tagUrl.indexOf('https') !== -1) {
url = tagUrl.replace(/^https:\/\/[^/]+\//, `https://${window.location.hostname}:${window.location.port}/`);
url = tagUrl.replace(/^https:\/\/[^/]+\//, `https://${window.location.hostname}:${window.location.port}/`)
item2 = item2.replace(/\]\((.*?)\)/g, `](${url})`)
} else {
url = tagUrl.replace(/^http:\/\/[^/]+\//, `http://${window.location.hostname}:${window.location.port}/`);
url = tagUrl.replace(/^http:\/\/[^/]+\//, `http://${window.location.hostname}:${window.location.port}/`)
item2 = item2.replace(/\]\((.*?)\)/g, `](${url})`)
}
/// ////////出处内容包装div
var match = (item2.match(/出处(.*)\)/) || [])[0]
// 查找指定字符串的位置
var indexOfSpecifiedString = item2.indexOf(match);
var indexOfSpecifiedString = item2.indexOf(match)
if (indexOfSpecifiedString !== -1) {
// 使用 slice 获取指定字符串后面的所有内容
var contentAfterSpecifiedString = item2.slice(indexOfSpecifiedString + match.length);
var contentAfterSpecifiedString = item2.slice(indexOfSpecifiedString + match.length)
item2 = item2.replace(contentAfterSpecifiedString, `<div class="describe-view">${contentAfterSpecifiedString}</div>`)
} else {
console.log('未找到匹配的指定字符串');
console.log('未找到匹配的指定字符串')
}
/// ////////特殊标签后包装div
// var specifiedString = '<a class="show_detail"></a>';
// var match2 = item2.match(new RegExp(specifiedString + '(.*)')) || [];
const match2 = item2.match(/<a\s+class="show_detail"\s+data="([^"]*)"><\/a>([\s\S]*)/);
const match2 = item2.match(/<a\s+class="show_detail"\s+data="([^"]*)"><\/a>([\s\S]*)/)
if (match2 && match2.length === 3) {
var textAfterSpecifiedString = match2[2];
var textAfterSpecifiedString = match2[2]
var data = match2[1]
// 修改文本内容
textAfterSpecifiedString = `<div class="describe-view" data="${data}" >${textAfterSpecifiedString}</div>`
......@@ -234,24 +220,22 @@ export default {
})
}
},
generateRandomString (length) {
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
const charactersLength = characters.length;
const randomValues = new Uint32Array(length);
generateRandomString(length) {
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
const charactersLength = characters.length
const randomValues = new Uint32Array(length)
crypto.getRandomValues(randomValues);
crypto.getRandomValues(randomValues)
let result = '';
let result = ''
for (let i = 0; i < length; i++) {
result += characters.charAt(randomValues[i] % charactersLength);
result += characters.charAt(randomValues[i] % charactersLength)
}
return result;
return result
}
}
}
</script>
<style scoped>
.contentBox {
......@@ -283,7 +267,7 @@ export default {
position: relative;
display: flex;
flex-direction: column;
background-image: url("~@/assets/img/ai.png");
background-image: url('~@/assets/img/ai.png');
background-repeat: no-repeat;
background-position: center center;
background-size: auto 50%;
......
<template>
<div class="aggregate">
<div class="logo">
<img src="@/assets/img/logo2.png" alt="">
<span class="title">陆军装备知识图谱系统</span>
</div>
<div class="aggregateBox">
<div class="itemBox" v-for="(item,index) in itemList" :key="index" @click="goPage(item.url)">
<span class="text">
{{ item.name }}
</span>
</div>
</div>
</div>
</template>
<script>
export default {
data () {
return {
itemList: [
{
name: '基于NEO4J的知识图谱构建',
url: `http://${window.location.hostname}:${window.location.port}/#/main/welcome`
},
{
name: '基于大语言模型与知识图谱双轮驱动的机械维修保障智能问答系统',
url: `http://${window.location.hostname}:${window.location.port}/#/main/welcome`
},
{
name: '基于gstore的知识图谱系统',
url: `http://${window.location.hostname}:${window.location.port}/#/main/welcome`
}
]
}
},
components: {},
mounted () {
},
methods: {
goPage (url) {
location.href = url
}
}
}
</script>
<style lang="scss" scoped>
.logo {
position: absolute;
top: 20px;
left: 20px;
display: flex;
img {
height: 40px;
}
.title {
color: #fff;
font-size: 18px;
height: 40px;
line-height: 40px;
display: inline-block;
margin-left: 20px;
}
}
.aggregate {
height: 100%;
width: 100%;
background: url(~@/assets/img/login_bg_2.jpg) center center;
background-size: cover;
display: flex;
justify-content: center;
align-items: center;
position: relative;
overflow: hidden;
}
.aggregateBox {
width: 80%;
height: 50%;
min-width: 1000px;
min-height: 400px;
border-radius: 20px;
background-color: rgba(255, 255, 255, 0.1); /* 背景色透明度,根据需要调整 */
backdrop-filter: blur(10px); /* 模糊程度,根据需要调整 */
display: flex;
padding: 20px; /* 内边距,根据需要调整 */
justify-content: space-around;
flex-direction: row;
align-items: center;
.itemBox {
width: 400px;
cursor: pointer;
height: 200px;
background: url(~@/assets/img/cardBg.png) center center;
background-size: cover;
border-radius: 10px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
padding: 20px;
border: 1px solid #b1b1b1;
font-size: 20px;
line-height: 30px;
// color: #5b6fab;
color: #273379;
font-weight: 900;
.text {
background-color: #fff;
padding: 10px;
border-radius: 5px;
}
}
}
.aggregateBox :hover {
box-shadow: 1px 1px 8px 1px #fff;
transition: all 0.5s;
}
</style>
<template>
<div style="background-color: white;padding: 16px;" class="allCard">
<Card v-for="(item,index) in cardList" @click="cardClick(item)" :key="index">
<Card v-for="(item,index) in cardList" @click="cardClick(item)" :key="index">
<template #title>
<div class="title">
{{ item.name }}
</div>
<div class="title">
{{ item.name }}
</div>
</template>
<template #content>
<div class="content">
......@@ -18,15 +18,14 @@
</div>
</template>
</Card>
</div>
</template>
<script>
import Card from './card';
import * as echarts from 'echarts';
import Card from './card'
import * as echarts from 'echarts'
export default {
data () {
data() {
return {
echarts: undefined,
cardList: [
......@@ -52,10 +51,15 @@ export default {
},
{
name: '调用统计'
}
],
option: {
tooltip: {
trigger: 'axis',
position: function (pt) {
return [pt[0], '10%']
}
},
color: ['#37A2FF', '#FFBF00'],
legend: {
type: 'scroll',
......@@ -65,15 +69,15 @@ export default {
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [
{
smooth: true,
smooth: false,
lineStyle: {
width: 0
},
......@@ -99,20 +103,20 @@ export default {
}
}
},
components: {Card},
mounted () {
components: { Card },
mounted() {
this.$nextTick(() => {
this.echarts = echarts.init(document.getElementById('homeMain'));
this.echarts.setOption(this.option, true);
this.echarts = echarts.init(document.getElementById('homeMain'))
this.echarts.setOption(this.option, true)
})
},
methods: {
cardClick () {
console.log(1);
cardClick() {
console.log(1)
},
resize () {
resize() {
if (this.echarts != null) {
this.echarts.resize();
this.echarts.resize()
}
}
}
......@@ -120,50 +124,50 @@ export default {
</script>
<style lang="scss" scoped>
@import '@/assets/style/element-variables.scss';
.title {
border-left: 1px solid;
border-left-width: 5px;
border-left-color: $--color-primary;
margin-bottom: 20px;
font-size: 17px;
padding-left: 10px;
}
#homeMain{
height:400px;
width:100%;
@import '@/assets/style/element-variables.scss';
.title {
border-left: 1px solid;
border-left-width: 5px;
border-left-color: $--color-primary;
margin-bottom: 20px;
font-size: 17px;
padding-left: 10px;
}
#homeMain {
height: 400px;
width: 100%;
}
.title p {
height: 40px;
line-height: 40px;
font-size: 16px;
margin: 0px;
padding-left: 20px;
}
.title p {
height: 40px;
line-height: 40px;
font-size: 16px;
margin: 0px;
padding-left: 20px;
}
.title p span {
font-size: 20px;
color: $--color-primary;
}
.title p span {
font-size: 20px;
color: $--color-primary;
}
.item-list {
margin: 0px;
}
.item-list li {
margin: 10px 0px;
}
.item-list {
margin: 0px;
}
.item-list li {
margin: 10px 0px;
}
.item {
height: 48px;
display: flex;
align-items: center;
}
.item {
height: 48px;
display: flex;
align-items: center;
}
strong.warning {
color: red;
font-size: 16px;
}
.allCard {
strong.warning {
color: red;
font-size: 16px;
}
.allCard {
display: grid !important;
/* grid-column-gap: 50px;
grid-row-gap: 50px; */
......@@ -175,23 +179,20 @@ height:400px;
.allCard :nth-child(5) {
grid-column-start: 1;
grid-column-end: 5;
}
.content{
.content {
height: calc(100% - 45px);
display: flex;
flex-direction: column;
justify-content: space-around;
align-items: center;
flex-direction: column;
justify-content: space-around;
align-items: center;
}
.num{
.num {
font-size: 40px;
font-weight: bold;
text-align: center;
}
.describe{
.describe {
text-align: center;
}
</style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment