maxkb/ui/src/views/application/CreateAndSetting.vue
2023-11-29 15:44:33 +08:00

333 lines
11 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<LayoutContainer :header="id ? '设置' : '创建应用'" back-to="-1" class="create-application">
<el-row v-loading="loading">
<el-col :span="10">
<div class="p-24 mb-16" style="padding-bottom: 0">
<h4 class="title-decoration-1">应用信息</h4>
</div>
<div class="scrollbar-height-left">
<el-scrollbar>
<el-form
ref="applicationFormRef"
:model="applicationForm"
:rules="rules"
label-position="top"
require-asterisk-position="right"
class="p-24"
style="padding-top: 0"
>
<el-form-item label="应用名称" prop="name">
<el-input
v-model="applicationForm.name"
maxlength="64"
placeholder="请输入应用名称"
show-word-limit
/>
</el-form-item>
<el-form-item label="应用描述">
<el-input
v-model="applicationForm.desc"
type="textarea"
placeholder="描述该应用的应用场景及用途MaxKB 小助手回答用户提出的 MaxKB 产品使用问题"
:rows="3"
maxlength="500"
show-word-limit
/>
</el-form-item>
<el-form-item label="选择模型" prop="model_id">
<el-select
v-model="applicationForm.model_id"
placeholder="请选择模型"
style="width: 100%"
>
<el-option-group
v-for="(value, label) in modelOptions"
:key="value"
:label="realatedObject(providerOptions, label, 'provider')?.name"
>
<el-option
v-for="item in value"
:key="item.id"
:label="item.name"
:value="item.id"
class="flex-between"
>
<div class="flex">
<span
v-html="realatedObject(providerOptions, label, 'provider')?.icon"
class="model-icon mr-8"
></span>
<span>{{ item.name }}</span>
</div>
<el-icon class="check-icon" v-if="item.id === applicationForm.model_id"
><Check
/></el-icon>
</el-option>
</el-option-group>
<div class="border-t" style="padding: 8px 11px">
<el-button type="primary" link>
<el-icon class="mr-4"><Plus /></el-icon> 添加模型
</el-button>
</div>
</el-select>
</el-form-item>
<el-form-item label="多轮对话" @click.prevent>
<el-switch v-model="applicationForm.multiple_rounds_dialogue"></el-switch>
</el-form-item>
<el-form-item label="关联数据集">
<template #label>
<div class="flex-between">
<span>关联数据集</span>
<el-button type="primary" link @click="openDatasetDialog">
<el-icon class="mr-4"><Plus /></el-icon> 添加
</el-button>
</div>
</template>
<div v-if="applicationForm.dataset_id_list.length == 0">
<el-text type="info">关联的数据集展示在这里</el-text>
</div>
<div class="w-full" v-else>
<el-row :gutter="12">
<el-col
:xs="24"
:sm="24"
:md="12"
:lg="12"
:xl="12"
class="mb-8"
v-for="(item, index) in applicationForm.dataset_id_list"
:key="index"
>
<el-card class="relate-dataset-card" shadow="never">
<div class="flex-between">
<div class="flex align-center">
<AppAvatar class="mr-12" shape="square" :size="32">
<img src="@/assets/icon_document.svg" style="width: 58%" alt="" />
</AppAvatar>
<div class="ellipsis-1">
{{ realatedObject(datasetList, item, 'id')?.name }}
</div>
</div>
<el-button text @click="removeDataset(item)">
<el-icon><Close /></el-icon>
</el-button>
</div>
</el-card>
</el-col>
</el-row>
</div>
</el-form-item>
<el-form-item label="开场白">
<el-input
v-model="applicationForm.prologue"
type="textarea"
placeholder="开始对话的欢迎语。您可以这样写:您好,我是 MaxKB 智能小助手,您可以向我提出 MaxKB 产品使用中遇到的任何问题。"
:rows="4"
/>
</el-form-item>
<el-form-item label="示例">
<template v-for="(item, index) in exampleList" :key="index">
<el-input
v-model="exampleList[index]"
:placeholder="`用户提问 示例${index + 1}`"
class="mb-8"
/>
</template>
</el-form-item>
</el-form>
</el-scrollbar>
</div>
<div class="text-right border-t p-16">
<el-button v-if="!id" @click="router.push({ path: `/application` })"> 取消 </el-button>
<el-button type="primary" @click="submit(applicationFormRef)" :disabled="loading">
{{ id ? '保存' : '创建' }}
</el-button>
</div>
</el-col>
<el-col :span="14" class="p-24 border-l">
<h4 class="title-decoration-1 mb-16">调试预览</h4>
<div class="dialog-bg">
<h4 class="p-24">{{ applicationForm?.name || '应用名称' }}</h4>
<div class="scrollbar-height">
<AiDialog :data="applicationForm"></AiDialog>
</div>
</div>
</el-col>
</el-row>
<AddDatasetDialog ref="AddDatasetDialogRef" @addData="addDataset" :data="datasetList" />
</LayoutContainer>
</template>
<script setup lang="ts">
import { reactive, ref, watch, onMounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { groupBy } from 'lodash'
import AiDialog from '@/components/ai-dialog/index.vue'
import AddDatasetDialog from './components/AddDatasetDialog.vue'
import applicationApi from '@/api/application'
import type { FormInstance, FormRules } from 'element-plus'
import type { ApplicationFormType } from '@/api/type/application'
import type { Provider } from '@/api/type/model'
import { realatedObject } from '@/utils/utils'
import { MsgSuccess } from '@/utils/message'
import useStore from '@/stores'
const { model, dataset, application, user } = useStore()
const router = useRouter()
const route = useRoute()
const {
params: { id }
} = route as any
const applicationFormRef = ref<FormInstance>()
const AddDatasetDialogRef = ref()
const loading = ref(false)
const exampleList = ref(['', ''])
const applicationForm = ref<ApplicationFormType>({
name: '',
desc: '',
model_id: '',
multiple_rounds_dialogue: false,
prologue: '',
example: [],
dataset_id_list: []
})
const rules = reactive<FormRules<ApplicationFormType>>({
name: [{ required: true, message: '请输入应用名称', trigger: 'blur' }],
model_id: [
{
required: true,
message: '请选择模型',
trigger: 'change'
}
]
})
const modelOptions = ref<any>(null)
const providerOptions = ref<Array<Provider>>([])
const datasetList = ref([])
watch(exampleList.value, () => {
applicationForm.value.example = exampleList.value.filter((v) => v)
})
const submit = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate((valid, fields) => {
if (valid) {
if (id) {
applicationApi.putApplication(id, applicationForm.value, loading).then((res) => {
MsgSuccess('保存成功')
})
} else {
applicationApi.postApplication(applicationForm.value, loading).then((res) => {
MsgSuccess('创建成功')
router.push({ path: `/application` })
})
}
} else {
console.log('error submit!')
}
})
}
function removeDataset(id: string) {
applicationForm.value.dataset_id_list.splice(applicationForm.value.dataset_id_list.indexOf(id), 1)
}
function addDataset(val: Array<string>) {
applicationForm.value.dataset_id_list = val
}
function openDatasetDialog() {
AddDatasetDialogRef.value.open(applicationForm.value.dataset_id_list)
}
function getDetail() {
application.asyncGetApplicationDetail(id, loading).then((res: any) => {
applicationForm.value = res.data
applicationForm.value.model_id = res.data.model
})
}
function getDataset() {
loading.value = true
if (id) {
applicationApi.getApplicationDataset(id, loading).then((res) => {
datasetList.value = res.data
})
} else {
dataset
.asyncGetAllDateset()
.then((res: any) => {
datasetList.value = res.data?.filter((v) => v.user_id === user.userInfo?.id)
loading.value = false
})
.catch(() => {
loading.value = false
})
}
}
function getModel() {
loading.value = true
model
.asyncGetModel()
.then((res: any) => {
modelOptions.value = groupBy(res?.data, 'provider')
loading.value = false
})
.catch(() => {
loading.value = false
})
}
function getProvider() {
loading.value = true
model
.asyncGetProvider()
.then((res: any) => {
providerOptions.value = res?.data
loading.value = false
})
.catch(() => {
loading.value = false
})
}
onMounted(() => {
getProvider()
getModel()
getDataset()
if (id) {
getDetail()
}
})
</script>
<style lang="scss" scoped>
.create-application {
.relate-dataset-card {
color: var(--app-text-color);
border-radius: 4px;
}
.dialog-bg {
border-radius: 8px;
background: var(--dialog-bg-gradient-color);
overflow: hidden;
box-sizing: border-box;
}
.scrollbar-height-left {
height: calc(var(--app-main-height) - 127px);
}
.scrollbar-height {
height: calc(var(--app-main-height) - 150px);
}
}
.model-icon {
width: 20px;
}
.check-icon {
position: absolute;
right: 10px;
}
</style>