mirror of
https://github.com/1Panel-dev/MaxKB.git
synced 2025-12-29 16:12:55 +00:00
feat: model
This commit is contained in:
parent
275ec80701
commit
1dab1ebc47
|
|
@ -144,7 +144,7 @@
|
|||
@load="getList"
|
||||
:loading="loading"
|
||||
>
|
||||
<el-row v-if="applicationList.length > 0" :gutter="15">
|
||||
<el-row v-if="applicationList.length > 0" :gutter="15" class="w-full">
|
||||
<template v-for="(item, index) in applicationList" :key="index">
|
||||
<el-col
|
||||
v-if="item.resource_type === 'folder'"
|
||||
|
|
|
|||
|
|
@ -236,9 +236,9 @@
|
|||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import type { Provider, BaseModel } from '@/api/type/model'
|
||||
import type { Dict, KeyValue } from '@/api/type/common'
|
||||
import ModelApi from '@/api/model/model'
|
||||
import ProviderApi from '@/api/model/provider'
|
||||
import type { FormField } from '@/components/dynamics-form/type'
|
||||
import DynamicsForm from '@/components/dynamics-form/index.vue'
|
||||
|
|
@ -248,7 +248,19 @@ import { PermissionType, PermissionDesc } from '@/enums/model'
|
|||
import { input_type_list } from '@/components/dynamics-form/constructor/data'
|
||||
import AddParamDrawer from '@/views/model/component/AddParamDrawer.vue'
|
||||
import { t } from '@/locales'
|
||||
import { loadSharedApi } from '@/utils/dynamics-api/shared-api'
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
const type = computed(() => {
|
||||
if (route.path.includes('shared')) {
|
||||
return 'systemShare'
|
||||
} else if (route.path.includes('resource-management')) {
|
||||
return 'systemManage'
|
||||
} else {
|
||||
return 'workspace'
|
||||
}
|
||||
})
|
||||
const providerValue = ref<Provider>()
|
||||
const dynamicsFormRef = ref<InstanceType<typeof DynamicsForm>>()
|
||||
const emit = defineEmits(['change', 'submit'])
|
||||
|
|
@ -378,18 +390,20 @@ const submit = () => {
|
|||
?.validate()
|
||||
.then(() => {
|
||||
if (providerValue.value) {
|
||||
ModelApi.createModel(
|
||||
{
|
||||
...base_form_data.value,
|
||||
credential: credential_form_data.value,
|
||||
provider: providerValue.value.provider,
|
||||
},
|
||||
loading,
|
||||
).then((ok) => {
|
||||
close()
|
||||
MsgSuccess(t('views.model.tip.createSuccessMessage'))
|
||||
emit('submit')
|
||||
})
|
||||
loadSharedApi({ type: 'model', systemType: type.value })
|
||||
.createModel(
|
||||
{
|
||||
...base_form_data.value,
|
||||
credential: credential_form_data.value,
|
||||
provider: providerValue.value.provider,
|
||||
},
|
||||
loading,
|
||||
)
|
||||
.then((ok: any) => {
|
||||
close()
|
||||
MsgSuccess(t('views.model.tip.createSuccessMessage'))
|
||||
emit('submit')
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
<template #header="{ close, titleId, titleClass }">
|
||||
<el-breadcrumb separator=">">
|
||||
<el-breadcrumb-item
|
||||
><span class="active-breadcrumb">{{
|
||||
><span class="active-breadcrumb">{{
|
||||
`${$t('common.edit')} ${providerValue?.name}`
|
||||
}}</span></el-breadcrumb-item
|
||||
>
|
||||
|
|
@ -74,8 +74,8 @@
|
|||
<div class="mr-4">
|
||||
<span>{{ $t('views.model.modelForm.base_model.label') }} </span>
|
||||
<span class="danger ml-4">{{
|
||||
$t('views.model.modelForm.base_model.tooltip')
|
||||
}}</span>
|
||||
$t('views.model.modelForm.base_model.tooltip')
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -119,17 +119,30 @@
|
|||
</el-dialog>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import {ref, computed} from 'vue'
|
||||
import type {Provider, BaseModel, Model} from '@/api/type/model'
|
||||
import type {Dict, KeyValue} from '@/api/type/common'
|
||||
import ModelApi from '@/api/model/model'
|
||||
import { ref, computed } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import type { Provider, BaseModel, Model } from '@/api/type/model'
|
||||
import type { Dict, KeyValue } from '@/api/type/common'
|
||||
import ProviderApi from '@/api/model/provider'
|
||||
import type {FormField} from '@/components/dynamics-form/type'
|
||||
import type { FormField } from '@/components/dynamics-form/type'
|
||||
import DynamicsForm from '@/components/dynamics-form/index.vue'
|
||||
import type {FormRules} from 'element-plus'
|
||||
import {MsgSuccess} from '@/utils/message'
|
||||
import {PermissionType, PermissionDesc} from '@/enums/model'
|
||||
import {t} from '@/locales'
|
||||
import type { FormRules } from 'element-plus'
|
||||
import { MsgSuccess } from '@/utils/message'
|
||||
import { PermissionType, PermissionDesc } from '@/enums/model'
|
||||
import { t } from '@/locales'
|
||||
import { loadSharedApi } from '@/utils/dynamics-api/shared-api'
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
const type = computed(() => {
|
||||
if (route.path.includes('shared')) {
|
||||
return 'systemShare'
|
||||
} else if (route.path.includes('resource-management')) {
|
||||
return 'systemManage'
|
||||
} else {
|
||||
return 'workspace'
|
||||
}
|
||||
})
|
||||
|
||||
const providerValue = ref<Provider>()
|
||||
const dynamicsFormRef = ref<InstanceType<typeof DynamicsForm>>()
|
||||
|
|
@ -167,13 +180,13 @@ const base_form_data = ref<{
|
|||
model_type: string
|
||||
|
||||
model_name: string
|
||||
}>({name: '', model_type: '', model_name: ''})
|
||||
}>({ name: '', model_type: '', model_name: '' })
|
||||
|
||||
const credential_form_data = ref<Dict<any>>({})
|
||||
|
||||
const form_data = computed({
|
||||
get: () => {
|
||||
return {...credential_form_data.value, ...base_form_data.value}
|
||||
return { ...credential_form_data.value, ...base_form_data.value }
|
||||
},
|
||||
set: (event: any) => {
|
||||
credential_form_data.value = event
|
||||
|
|
@ -209,27 +222,29 @@ const list_base_model = (model_type: any, change?: boolean) => {
|
|||
}
|
||||
const open = (provider: Provider, model: Model) => {
|
||||
modelValue.value = model
|
||||
ModelApi.getModelById(model.id, formLoading).then((ok) => {
|
||||
modelValue.value = ok.data
|
||||
ProviderApi.listModelType(model.provider, model_type_loading).then((ok) => {
|
||||
model_type_list.value = ok.data
|
||||
list_base_model(model.model_type)
|
||||
})
|
||||
providerValue.value = provider
|
||||
loadSharedApi({ type: 'model', systemType: type.value })
|
||||
.getModelById(model.id, formLoading)
|
||||
.then((ok: any) => {
|
||||
modelValue.value = ok.data
|
||||
ProviderApi.listModelType(model.provider, model_type_loading).then((ok) => {
|
||||
model_type_list.value = ok.data
|
||||
list_base_model(model.model_type)
|
||||
})
|
||||
providerValue.value = provider
|
||||
|
||||
base_form_data.value = {
|
||||
name: model.name,
|
||||
model_type: model.model_type,
|
||||
model_name: model.model_name,
|
||||
}
|
||||
form_data.value = model.credential
|
||||
getModelForm(model.model_name)
|
||||
})
|
||||
base_form_data.value = {
|
||||
name: model.name,
|
||||
model_type: model.model_type,
|
||||
model_name: model.model_name,
|
||||
}
|
||||
form_data.value = model.credential
|
||||
getModelForm(model.model_name)
|
||||
})
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
const close = () => {
|
||||
base_form_data.value = {name: '', model_type: '', model_name: ''}
|
||||
base_form_data.value = { name: '', model_type: '', model_name: '' }
|
||||
dynamicsFormRef.value?.ruleFormRef?.resetFields()
|
||||
credential_form_data.value = {}
|
||||
model_form_field.value = []
|
||||
|
|
@ -240,23 +255,25 @@ const close = () => {
|
|||
const submit = () => {
|
||||
dynamicsFormRef.value?.validate().then(() => {
|
||||
if (modelValue.value) {
|
||||
ModelApi.updateModel(
|
||||
modelValue.value.id,
|
||||
{
|
||||
...base_form_data.value,
|
||||
credential: credential_form_data.value,
|
||||
},
|
||||
loading,
|
||||
).then((ok) => {
|
||||
MsgSuccess(t('views.model.tip.updateSuccessMessage'))
|
||||
close()
|
||||
emit('submit')
|
||||
})
|
||||
loadSharedApi({ type: 'model', systemType: type.value })
|
||||
.updateModel(
|
||||
modelValue.value.id,
|
||||
{
|
||||
...base_form_data.value,
|
||||
credential: credential_form_data.value,
|
||||
},
|
||||
loading,
|
||||
)
|
||||
.then((ok: any) => {
|
||||
MsgSuccess(t('views.model.tip.updateSuccessMessage'))
|
||||
close()
|
||||
emit('submit')
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({open, close})
|
||||
defineExpose({ open, close })
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.select-provider {
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
</el-text>
|
||||
</template>
|
||||
<template #tag>
|
||||
<el-tag v-if="isShared" type="info" class="info-tag">
|
||||
<el-tag v-if="isShared || isSystemShare" type="info" class="info-tag">
|
||||
{{ t('views.system.shared.label') }}
|
||||
</el-tag>
|
||||
</template>
|
||||
|
|
@ -85,6 +85,12 @@
|
|||
>
|
||||
{{ $t('common.modify') }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item
|
||||
v-if="isSystemShare"
|
||||
icon="Lock"
|
||||
@click.stop="openAuthorizedWorkspaceDialog(model)"
|
||||
>{{ $t('views.system.shared.authorized_workspace') }}</el-dropdown-item
|
||||
>
|
||||
|
||||
<el-dropdown-item
|
||||
v-if="
|
||||
|
|
@ -93,7 +99,6 @@
|
|||
currentModel.model_type === 'IMAGE' ||
|
||||
currentModel.model_type === 'TTI' ||
|
||||
permissionPrecise.paramSetting()
|
||||
|
||||
"
|
||||
:disabled="!is_permisstion"
|
||||
icon="Setting"
|
||||
|
|
@ -107,9 +112,7 @@
|
|||
:disabled="!is_permisstion"
|
||||
text
|
||||
@click.stop="deleteModel"
|
||||
v-if="
|
||||
permissionPrecise.delete()
|
||||
"
|
||||
v-if="permissionPrecise.delete()"
|
||||
>
|
||||
{{ $t('common.delete') }}
|
||||
</el-dropdown-item>
|
||||
|
|
@ -119,11 +122,14 @@
|
|||
</template>
|
||||
<EditModel ref="editModelRef" @submit="emit('change')"></EditModel>
|
||||
<ParamSettingDialog ref="paramSettingRef" :model="model" />
|
||||
<AuthorizedWorkspace
|
||||
ref="AuthorizedWorkspaceDialogRef"
|
||||
v-if="isSystemShare"
|
||||
></AuthorizedWorkspace>
|
||||
</card-box>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import type { Provider, Model } from '@/api/type/model'
|
||||
import ModelApi from '@/api/model/model'
|
||||
import { computed, ref, onMounted, onBeforeUnmount } from 'vue'
|
||||
import EditModel from '@/views/model/component/EditModel.vue'
|
||||
// import DownloadLoading from '@/components/loading/DownloadLoading.vue'
|
||||
|
|
@ -131,36 +137,28 @@ import { MsgConfirm } from '@/utils/message'
|
|||
import { modelType } from '@/enums/model'
|
||||
import useStore from '@/stores'
|
||||
import ParamSettingDialog from './ParamSettingDialog.vue'
|
||||
import AuthorizedWorkspace from '@/views/system-shared/AuthorizedWorkspaceDialog.vue'
|
||||
import { t } from '@/locales'
|
||||
import { PermissionConst, RoleConst } from '@/utils/permission/data'
|
||||
import { hasPermission } from '@/utils/permission'
|
||||
import { useRoute } from 'vue-router'
|
||||
import permissionMap from '@/permission'
|
||||
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
const type = computed(() => {
|
||||
if (route.path.includes('shared')) {
|
||||
return 'systemShare'
|
||||
} else if (route.path.includes('resource-management')) {
|
||||
return 'systemManage'
|
||||
} else {
|
||||
return 'workspace'
|
||||
}
|
||||
})
|
||||
const permissionPrecise = computed(() => {
|
||||
return permissionMap['model'][type.value]
|
||||
})
|
||||
import { loadSharedApi } from '@/utils/dynamics-api/shared-api'
|
||||
|
||||
const props = defineProps<{
|
||||
model: Model
|
||||
provider_list: Array<Provider>
|
||||
updateModelById: (model_id: string, model: Model) => void
|
||||
isShared?: boolean | undefined
|
||||
isSystemShare?: boolean | undefined
|
||||
sharedType: 'systemShare' | 'workspace' | 'systemManage'
|
||||
}>()
|
||||
|
||||
const { user } = useStore()
|
||||
|
||||
const permissionPrecise = computed(() => {
|
||||
return permissionMap['model'][props.sharedType]
|
||||
})
|
||||
|
||||
const downModel = ref<Model>()
|
||||
|
||||
const is_permisstion = computed(() => {
|
||||
|
|
@ -196,18 +194,22 @@ const deleteModel = () => {
|
|||
},
|
||||
)
|
||||
.then(() => {
|
||||
ModelApi.deleteModel(props.model.id).then(() => {
|
||||
emit('change')
|
||||
})
|
||||
loadSharedApi({ type: 'model', systemType: props.sharedType })
|
||||
.deleteModel(props.model.id)
|
||||
.then(() => {
|
||||
emit('change')
|
||||
})
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
|
||||
const cancelDownload = () => {
|
||||
ModelApi.pauseDownload(props.model.id).then(() => {
|
||||
downModel.value = undefined
|
||||
emit('change')
|
||||
})
|
||||
loadSharedApi({ type: 'model', systemType: type.value })
|
||||
.pauseDownload(props.model.id)
|
||||
.then(() => {
|
||||
downModel.value = undefined
|
||||
emit('change')
|
||||
})
|
||||
}
|
||||
const openEditModel = () => {
|
||||
const provider = props.provider_list.find((p) => p.provider === props.model.provider)
|
||||
|
|
@ -225,9 +227,11 @@ const icon = computed(() => {
|
|||
const initInterval = () => {
|
||||
interval = setInterval(() => {
|
||||
if (currentModel.value.status === 'DOWNLOAD') {
|
||||
ModelApi.getModelMetaById(props.model.id).then((ok) => {
|
||||
downModel.value = ok.data
|
||||
})
|
||||
loadSharedApi({ type: 'model', systemType: type.value })
|
||||
.getModelMetaById(props.model.id)
|
||||
.then((ok: any) => {
|
||||
downModel.value = ok.data
|
||||
})
|
||||
} else {
|
||||
if (downModel.value) {
|
||||
props.updateModelById(props.model.id, downModel.value)
|
||||
|
|
@ -251,6 +255,13 @@ const openParamSetting = () => {
|
|||
paramSettingRef.value?.open()
|
||||
}
|
||||
|
||||
const AuthorizedWorkspaceDialogRef = ref()
|
||||
function openAuthorizedWorkspaceDialog(row: any) {
|
||||
if (AuthorizedWorkspaceDialogRef.value) {
|
||||
AuthorizedWorkspaceDialogRef.value.open(row, 'Model')
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initInterval()
|
||||
})
|
||||
|
|
|
|||
|
|
@ -81,17 +81,29 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import type { Model } from '@/api/type/model'
|
||||
import { ref } from 'vue'
|
||||
import AddParamDrawer from './AddParamDrawer.vue'
|
||||
import { MsgError, MsgSuccess } from '@/utils/message'
|
||||
import ModelApi from '@/api/model/model'
|
||||
import { input_type_list } from '@/components/dynamics-form/constructor/data'
|
||||
import { t } from '@/locales'
|
||||
import { loadSharedApi } from '@/utils/dynamics-api/shared-api'
|
||||
const props = defineProps<{
|
||||
model: Model
|
||||
}>()
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
const type = computed(() => {
|
||||
if (route.path.includes('shared')) {
|
||||
return 'systemShare'
|
||||
} else if (route.path.includes('resource-management')) {
|
||||
return 'systemManage'
|
||||
} else {
|
||||
return 'workspace'
|
||||
}
|
||||
})
|
||||
const loading = ref<boolean>(false)
|
||||
const dialogVisible = ref<boolean>(false)
|
||||
const modelParamsForm = ref<any[]>([])
|
||||
|
|
@ -100,8 +112,9 @@ const AddParamRef = ref()
|
|||
const open = () => {
|
||||
dialogVisible.value = true
|
||||
loading.value = true
|
||||
ModelApi.getModelParamsForm(props.model.id, loading)
|
||||
.then((ok) => {
|
||||
loadSharedApi({ type: 'model', systemType: type.value })
|
||||
.getModelParamsForm(props.model.id, loading)
|
||||
.then((ok: any) => {
|
||||
loading.value = false
|
||||
modelParamsForm.value = ok.data
|
||||
})
|
||||
|
|
@ -151,13 +164,13 @@ function refresh(data: any, index: any) {
|
|||
}
|
||||
|
||||
function submit() {
|
||||
ModelApi.updateModelParamsForm(props.model.id, modelParamsForm.value, loading).then(
|
||||
(ok) => {
|
||||
loadSharedApi({ type: 'model', systemType: type.value })
|
||||
.updateModelParamsForm(props.model.id, modelParamsForm.value, loading)
|
||||
.then((ok: any) => {
|
||||
MsgSuccess(t('views.model.tip.saveSuccessMessage'))
|
||||
close()
|
||||
// emit('submit')
|
||||
},
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({ open, close })
|
||||
|
|
|
|||
|
|
@ -75,8 +75,8 @@
|
|||
:xs="24"
|
||||
:sm="12"
|
||||
:md="12"
|
||||
:lg="8"
|
||||
:xl="6"
|
||||
:lg="isSystemShare ? 12 : 8"
|
||||
:xl="isSystemShare ? 12 : 8"
|
||||
class="mb-16"
|
||||
v-for="(model, i) in row"
|
||||
:key="i"
|
||||
|
|
@ -87,6 +87,8 @@
|
|||
:model="model"
|
||||
:provider_list="provider_list"
|
||||
:isShared="isShared"
|
||||
:isSystemShare="isSystemShare"
|
||||
:sharedType="type"
|
||||
>
|
||||
</ModelCard>
|
||||
</el-col>
|
||||
|
|
@ -125,11 +127,9 @@ import { t } from '@/locales'
|
|||
import { PermissionConst, RoleConst } from '@/utils/permission/data'
|
||||
import { loadSharedApi } from '@/utils/dynamics-api/shared-api'
|
||||
import { useRoute } from 'vue-router'
|
||||
import useStore from '@/stores'
|
||||
import permissionMap from '@/permission'
|
||||
|
||||
const route = useRoute()
|
||||
const { folder, user } = useStore()
|
||||
|
||||
const type = computed(() => {
|
||||
if (route.path.includes('shared')) {
|
||||
|
|
@ -143,7 +143,9 @@ const type = computed(() => {
|
|||
const permissionPrecise = computed(() => {
|
||||
return permissionMap['model'][type.value]
|
||||
})
|
||||
|
||||
const isSystemShare = computed(() => {
|
||||
return type.value === 'systemShare'
|
||||
})
|
||||
const commonList1 = ref()
|
||||
const commonList2 = ref()
|
||||
const loading = ref<boolean>(false)
|
||||
|
|
@ -200,7 +202,7 @@ const openCreateModel = (provider?: Provider, model_type?: string) => {
|
|||
|
||||
const list_model = () => {
|
||||
const params = active_provider.value?.provider ? { provider: active_provider.value.provider } : {}
|
||||
loadSharedApi({ type: 'model', isShared: isShared.value })
|
||||
loadSharedApi({ type: 'model', isShared: isShared.value, systemType: type.value })
|
||||
.getModel({ ...model_search_form.value, ...params }, list_model_loading)
|
||||
.then((ok: any) => {
|
||||
model_list.value = ok.data
|
||||
|
|
|
|||
|
|
@ -1,229 +0,0 @@
|
|||
<template>
|
||||
<div class="model-shared">
|
||||
<ContentContainer
|
||||
:header="t('views.system.shared.shared_model')"
|
||||
v-loading="list_model_loading"
|
||||
>
|
||||
<template #search>
|
||||
<div class="flex">
|
||||
<div class="flex-between complex-search">
|
||||
<el-select
|
||||
class="complex-search__left"
|
||||
v-model="search_type"
|
||||
style="width: 120px"
|
||||
@change="search_type_change"
|
||||
>
|
||||
<el-option :label="$t('common.creator')" value="create_user" />
|
||||
|
||||
<el-option
|
||||
:label="$t('views.model.modelForm.model_type.label')"
|
||||
value="model_type"
|
||||
/>
|
||||
<el-option :label="$t('views.model.modelForm.modeName.label')" value="name" />
|
||||
</el-select>
|
||||
<el-input
|
||||
v-if="search_type === 'name'"
|
||||
v-model="model_search_form.name"
|
||||
@change="list_model"
|
||||
:placeholder="$t('common.searchBar.placeholder')"
|
||||
style="width: 220px"
|
||||
clearable
|
||||
/>
|
||||
<el-select
|
||||
v-else-if="search_type === 'create_user'"
|
||||
v-model="model_search_form.create_user"
|
||||
@change="list_model"
|
||||
clearable
|
||||
style="width: 220px"
|
||||
>
|
||||
<el-option
|
||||
v-for="u in user_options"
|
||||
:key="u.id"
|
||||
:value="u.id"
|
||||
:label="u.username"
|
||||
/>
|
||||
</el-select>
|
||||
|
||||
<el-select
|
||||
v-else-if="search_type === 'model_type'"
|
||||
v-model="model_search_form.model_type"
|
||||
clearable
|
||||
@change="list_model"
|
||||
style="width: 220px"
|
||||
>
|
||||
<template v-for="item in modelTypeList" :key="item.value">
|
||||
<el-option :label="item.text" :value="item.value" />
|
||||
</template>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="model-list-height">
|
||||
<el-scrollbar>
|
||||
<el-row v-if="model_split_list.length > 0" :gutter="15" class="w-full">
|
||||
<template v-for="(row, index) in model_split_list" :key="index">
|
||||
<el-col
|
||||
:xs="24"
|
||||
:sm="12"
|
||||
:md="12"
|
||||
:lg="8"
|
||||
:xl="6"
|
||||
class="mb-16"
|
||||
v-for="(model, i) in row"
|
||||
:key="i"
|
||||
>
|
||||
<ModelCard
|
||||
@change="list_model"
|
||||
:updateModelById="updateModelById"
|
||||
:model="model"
|
||||
:provider_list="provider_list"
|
||||
>
|
||||
</ModelCard>
|
||||
</el-col>
|
||||
</template>
|
||||
</el-row>
|
||||
<el-empty :description="$t('common.noData')" v-else />
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</ContentContainer>
|
||||
|
||||
<CreateModelDialog
|
||||
ref="createModelRef"
|
||||
@submit="list_model"
|
||||
@change="openCreateModel($event)"
|
||||
></CreateModelDialog>
|
||||
|
||||
<SelectProviderDialog
|
||||
ref="selectProviderRef"
|
||||
@change="(provider, modelType) => openCreateModel(provider, modelType)"
|
||||
></SelectProviderDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, computed } from 'vue'
|
||||
import ProviderApi from '@/api/model/provider'
|
||||
import ModelApi from '@/api/system-shared/model'
|
||||
import ModelWorkspaceApi from '@/api/shared-workspace'
|
||||
import type { Provider, Model } from '@/api/type/model'
|
||||
import ModelCard from '@/views/shared/model-shared/component/ModelCardSharedWorkspace.vue'
|
||||
import ProviderComponent from '@/views/shared/model-shared/component/Provider.vue'
|
||||
import { splitArray } from '@/utils/common'
|
||||
import { modelTypeList, allObj } from '@/views/shared/model-shared/component/data'
|
||||
import CreateModelDialog from '@/views/shared/model-shared/component/CreateModelDialog.vue'
|
||||
import iconMap from '@/components/app-icon/icons/common'
|
||||
import SelectProviderDialog from '@/views/shared/model-shared/component/SelectProviderDialog.vue'
|
||||
import useStore from '@/stores/modules-shared-system'
|
||||
import { t } from '@/locales'
|
||||
|
||||
const { model } = useStore()
|
||||
const rightOutlined = iconMap['right-outlined'].iconReader()
|
||||
|
||||
const commonList1 = ref()
|
||||
const commonList2 = ref()
|
||||
const loading = ref<boolean>(false)
|
||||
|
||||
const active_provider = ref<Provider>()
|
||||
const search_type = ref('name')
|
||||
const model_search_form = ref<{
|
||||
name: string
|
||||
create_user: string
|
||||
model_type: string
|
||||
}>({
|
||||
name: '',
|
||||
create_user: '',
|
||||
model_type: '',
|
||||
})
|
||||
const user_options = ref<any[]>([])
|
||||
const list_model_loading = ref<boolean>(false)
|
||||
const provider_list = ref<Array<Provider>>([])
|
||||
|
||||
const model_list = ref<Array<Model>>([])
|
||||
|
||||
const updateModelById = (model_id: string, model: Model) => {
|
||||
model_list.value
|
||||
.filter((m) => m.id == model_id)
|
||||
.forEach((m) => {
|
||||
m.status = model.status
|
||||
})
|
||||
}
|
||||
const model_split_list = computed(() => {
|
||||
return splitArray(model_list.value, 2)
|
||||
})
|
||||
const createModelRef = ref<InstanceType<typeof CreateModelDialog>>()
|
||||
const selectProviderRef = ref<InstanceType<typeof SelectProviderDialog>>()
|
||||
|
||||
const clickListHandle = (item: Provider) => {
|
||||
active_provider.value = item
|
||||
list_model()
|
||||
if (active_provider.value.provider === '') {
|
||||
commonList1.value.clearCurrent()
|
||||
commonList2.value.clearCurrent()
|
||||
}
|
||||
}
|
||||
|
||||
const openCreateModel = (provider?: Provider, model_type?: string) => {
|
||||
if (provider && provider.provider) {
|
||||
createModelRef.value?.open(provider, model_type)
|
||||
} else {
|
||||
selectProviderRef.value?.open()
|
||||
}
|
||||
}
|
||||
|
||||
const list_model = () => {
|
||||
const params = active_provider.value?.provider ? { provider: active_provider.value.provider } : {}
|
||||
ModelWorkspaceApi
|
||||
.getSharedWorkspaceModelPage({ ...model_search_form.value, ...params }, list_model_loading)
|
||||
.then((ok: any) => {
|
||||
model_list.value = ok.data
|
||||
const v = model_list.value.map((m) => ({ id: m.user_id, username: m.username }))
|
||||
if (user_options.value.length === 0) {
|
||||
user_options.value = Array.from(new Map(v.map((item) => [item.id, item])).values())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const search_type_change = () => {
|
||||
model_search_form.value = { name: '', create_user: '', model_type: '' }
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
ProviderApi.getProvider(loading).then((ok) => {
|
||||
active_provider.value = allObj
|
||||
provider_list.value = [allObj, ...ok.data]
|
||||
|
||||
list_model()
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.model-shared {
|
||||
height: 100%;
|
||||
|
||||
.shared-header {
|
||||
color: #646a73;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 21px;
|
||||
|
||||
:deep(.el-icon i) {
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
.sub-title {
|
||||
color: #1f2329;
|
||||
}
|
||||
}
|
||||
|
||||
.h-full {
|
||||
border-radius: 8px;
|
||||
box-shadow: 0px 2px 4px 0px #1f23291f;
|
||||
background: #fff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
<template>
|
||||
<el-drawer
|
||||
v-model="drawer"
|
||||
:direction="direction"
|
||||
size="600"
|
||||
:destroy-on-close="true"
|
||||
:before-close="cancelClick"
|
||||
>
|
||||
<template #header>
|
||||
<h4>
|
||||
{{
|
||||
isEdit
|
||||
? $t('common.param.editParam')
|
||||
: $t('common.param.addParam')
|
||||
}}
|
||||
</h4>
|
||||
</template>
|
||||
<template #default>
|
||||
<DynamicsFormConstructor
|
||||
v-model="currentItem"
|
||||
label-position="top"
|
||||
require-asterisk-position="right"
|
||||
ref="DynamicsFormConstructorRef"
|
||||
></DynamicsFormConstructor>
|
||||
</template>
|
||||
<template #footer>
|
||||
<div style="flex: auto">
|
||||
<el-button @click="cancelClick">{{ $t('common.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="confirmClick()">{{
|
||||
isEdit ? $t('common.save') : $t('common.add')
|
||||
}}</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import type { DrawerProps } from 'element-plus'
|
||||
import { cloneDeep } from 'lodash'
|
||||
import DynamicsFormConstructor from '@/components/dynamics-form/constructor/index.vue'
|
||||
|
||||
const drawer = ref(false)
|
||||
const direction = ref<DrawerProps['direction']>('rtl')
|
||||
const isEdit = ref(false)
|
||||
const DynamicsFormConstructorRef = ref<InstanceType<typeof DynamicsFormConstructor>>()
|
||||
|
||||
const currentItem = ref(null)
|
||||
const currentIndex = ref(null)
|
||||
|
||||
const emit = defineEmits(['refresh'])
|
||||
|
||||
const open = (row: any, index: any) => {
|
||||
if (row) {
|
||||
currentItem.value = cloneDeep(row)
|
||||
currentIndex.value = index
|
||||
isEdit.value = true
|
||||
}
|
||||
drawer.value = true
|
||||
}
|
||||
|
||||
function cancelClick() {
|
||||
drawer.value = false
|
||||
isEdit.value = false
|
||||
currentItem.value = null
|
||||
currentIndex.value = null
|
||||
}
|
||||
|
||||
function confirmClick() {
|
||||
const formEl = DynamicsFormConstructorRef.value
|
||||
formEl?.validate().then((valid) => {
|
||||
if (valid) {
|
||||
emit('refresh', formEl?.getData(), currentIndex.value)
|
||||
drawer.value = false
|
||||
isEdit.value = false
|
||||
currentItem.value = null
|
||||
currentIndex.value = null
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
|
|
@ -1,462 +0,0 @@
|
|||
<template>
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
width="600px"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
:destroy-on-close="true"
|
||||
:before-close="close"
|
||||
append-to-body
|
||||
>
|
||||
<template #header="{ close, titleId, titleClass }">
|
||||
<el-breadcrumb separator=">">
|
||||
<el-breadcrumb-item>
|
||||
<span @click="toSelectProvider" class="select-provider">
|
||||
{{ $t('views.model.providerPlaceholder') }}
|
||||
</span>
|
||||
</el-breadcrumb-item>
|
||||
<el-breadcrumb-item
|
||||
><span class="active-breadcrumb">{{
|
||||
`${$t('common.add')} ${providerValue?.name}`
|
||||
}}</span></el-breadcrumb-item
|
||||
>
|
||||
</el-breadcrumb>
|
||||
</template>
|
||||
<el-tabs v-model="activeName">
|
||||
<el-tab-pane :label="$t('views.model.modelForm.title.baseInfo')" name="base-info">
|
||||
<DynamicsForm
|
||||
v-model="form_data"
|
||||
:render_data="model_form_field"
|
||||
:model="form_data"
|
||||
ref="dynamicsFormRef"
|
||||
label-position="top"
|
||||
require-asterisk-position="right"
|
||||
class="mb-24"
|
||||
label-width="auto"
|
||||
>
|
||||
<template #default>
|
||||
<el-form-item prop="name" :rules="base_form_data_rule.name">
|
||||
<template #label>
|
||||
<div class="flex align-center" style="display: inline-flex">
|
||||
<div class="mr-4">
|
||||
<span> {{ $t('views.model.modelForm.modeName.label') }} </span>
|
||||
</div>
|
||||
<el-tooltip effect="dark" placement="right">
|
||||
<template #content>
|
||||
<p>{{ $t('views.model.modelForm.modeName.tooltip') }}</p>
|
||||
</template>
|
||||
<AppIcon iconName="app-warning" class="app-warning-icon"></AppIcon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<el-input
|
||||
v-model="base_form_data.name"
|
||||
maxlength="64"
|
||||
show-word-limit
|
||||
:placeholder="$t('views.model.modelForm.modeName.placeholder')"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="model_type" :rules="base_form_data_rule.model_type">
|
||||
<template #label>
|
||||
<div class="flex align-center" style="display: inline-flex">
|
||||
<span class="mr-4">{{ $t('views.model.modelForm.model_type.label') }} </span>
|
||||
<el-tooltip effect="dark" placement="right">
|
||||
<template #content>
|
||||
<p>{{ $t('views.model.modelForm.model_type.tooltip1') }}</p>
|
||||
<p>{{ $t('views.model.modelForm.model_type.tooltip2') }}</p>
|
||||
<p>{{ $t('views.model.modelForm.model_type.tooltip3') }}</p>
|
||||
<p>{{ $t('views.model.modelForm.model_type.tooltip4') }}</p>
|
||||
<p>{{ $t('views.model.modelForm.model_type.tooltip5') }}</p>
|
||||
<p>{{ $t('views.model.modelForm.model_type.tooltip6') }}</p>
|
||||
<p>{{ $t('views.model.modelForm.model_type.tooltip7') }}</p>
|
||||
</template>
|
||||
<AppIcon iconName="app-warning" class="app-warning-icon"></AppIcon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<el-select
|
||||
v-loading="model_type_loading"
|
||||
@change="list_base_model($event, true)"
|
||||
v-model="base_form_data.model_type"
|
||||
class="w-full m-2"
|
||||
:placeholder="$t('views.model.modelForm.model_type.placeholder')"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in model_type_list"
|
||||
:key="item.value"
|
||||
:label="item.key"
|
||||
:value="item.value"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="model_name" :rules="base_form_data_rule.model_name">
|
||||
<template #label>
|
||||
<div class="flex align-center" style="display: inline-flex">
|
||||
<div class="mr-4">
|
||||
<span>{{ $t('views.model.modelForm.base_model.label') }} </span>
|
||||
<span class="danger ml-4">{{
|
||||
$t('views.model.modelForm.base_model.tooltip')
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<el-select
|
||||
@change="getModelForm($event)"
|
||||
v-loading="base_model_loading"
|
||||
v-model="base_form_data.model_name"
|
||||
class="w-full m-2"
|
||||
:placeholder="$t('views.model.modelForm.base_model.placeholder')"
|
||||
filterable
|
||||
allow-create
|
||||
default-first-option
|
||||
>
|
||||
<el-option v-for="item in base_model_list" :key="item.name" :value="item.name">
|
||||
<template #default>
|
||||
<div class="flex align-center" style="display: inline-flex">
|
||||
<div class="flex-between mr-4">
|
||||
<span>{{ item.name }} </span>
|
||||
</div>
|
||||
<el-tooltip effect="dark" placement="right" v-if="item.desc">
|
||||
<template #content>
|
||||
<p class="w-280">{{ item.desc }}</p>
|
||||
</template>
|
||||
<AppIcon iconName="app-warning" class="app-warning-icon"></AppIcon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</DynamicsForm>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('views.model.modelForm.title.advancedInfo')" name="advanced-info">
|
||||
<el-empty
|
||||
v-if="!base_form_data.model_type || !base_form_data.model_name"
|
||||
:description="$t('views.model.tip.emptyMessage1')"
|
||||
/>
|
||||
<el-empty
|
||||
v-else-if="
|
||||
base_form_data.model_type === 'RERANKER' ||
|
||||
base_form_data.model_type === 'EMBEDDING' ||
|
||||
base_form_data.model_type === 'STT'
|
||||
"
|
||||
:description="$t('views.model.tip.emptyMessage2')"
|
||||
/>
|
||||
<div class="flex-between mb-8" v-else>
|
||||
<h5>{{ $t('views.model.modelForm.title.modelParams') }}</h5>
|
||||
<el-button
|
||||
type="text"
|
||||
@click.stop="openAddDrawer()"
|
||||
:disabled="
|
||||
base_form_data.model_type !== 'TTS' &&
|
||||
base_form_data.model_type !== 'LLM' &&
|
||||
base_form_data.model_type !== 'IMAGE' &&
|
||||
base_form_data.model_type !== 'TTI'
|
||||
"
|
||||
>
|
||||
<AppIcon iconName="Plus" class="add-icon" />{{ $t('common.add') }}
|
||||
</el-button>
|
||||
</div>
|
||||
<el-table
|
||||
:data="base_form_data.model_params_form"
|
||||
v-if="base_form_data.model_params_form?.length > 0"
|
||||
class="mb-16"
|
||||
>
|
||||
<el-table-column
|
||||
prop="label"
|
||||
:label="$t('dynamicsForm.paramForm.name.label')"
|
||||
show-overflow-tooltip
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.label && row.label.input_type === 'TooltipLabel'">{{
|
||||
row.label.label
|
||||
}}</span>
|
||||
<span v-else>{{ row.label }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="field"
|
||||
:label="$t('dynamicsForm.paramForm.field.label')"
|
||||
show-overflow-tooltip
|
||||
width="95px"
|
||||
/>
|
||||
<el-table-column :label="$t('dynamicsForm.paramForm.input_type.label')" width="110px">
|
||||
<template #default="{ row }">
|
||||
<el-tag type="info" class="info-tag">{{
|
||||
input_type_list.find((item) => item.value === row.input_type)?.label
|
||||
}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="default_value"
|
||||
:label="$t('dynamicsForm.default.label')"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column :label="$t('common.required')">
|
||||
<template #default="{ row }">
|
||||
<div @click.stop>
|
||||
<el-switch disabled size="small" v-model="row.required" />
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column :label="$t('common.operation')" align="left" width="90">
|
||||
<template #default="{ row, $index }">
|
||||
<span class="mr-4">
|
||||
<el-tooltip effect="dark" :content="$t('common.modify')" placement="top">
|
||||
<el-button type="primary" text @click.stop="openAddDrawer(row, $index)">
|
||||
<el-icon><EditPen /></el-icon>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
<el-tooltip effect="dark" :content="$t('common.delete')" placement="top">
|
||||
<el-button type="primary" text @click="deleteParam($index)">
|
||||
<el-icon>
|
||||
<Delete />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="close">{{ $t('common.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="submit" :loading="loading">
|
||||
{{ $t('common.save') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<AddParamDrawer ref="AddParamRef" @refresh="refresh" />
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import type { Provider, BaseModel } from '@/api/type/model'
|
||||
import type { Dict, KeyValue } from '@/api/type/common'
|
||||
import ModelApi from '@/api/system-shared/model'
|
||||
import ProviderApi from '@/api/model/provider'
|
||||
import type { FormField } from '@/components/dynamics-form/type'
|
||||
import DynamicsForm from '@/components/dynamics-form/index.vue'
|
||||
import type { FormRules } from 'element-plus'
|
||||
import { MsgError, MsgSuccess, MsgWarning } from '@/utils/message'
|
||||
import { PermissionType, PermissionDesc } from '@/enums/model'
|
||||
import { input_type_list } from '@/components/dynamics-form/constructor/data'
|
||||
import AddParamDrawer from '@/views/shared/model-shared/component/AddParamDrawer.vue'
|
||||
import { t } from '@/locales'
|
||||
|
||||
const providerValue = ref<Provider>()
|
||||
const dynamicsFormRef = ref<InstanceType<typeof DynamicsForm>>()
|
||||
const emit = defineEmits(['change', 'submit'])
|
||||
const loading = ref<boolean>(false)
|
||||
const model_type_loading = ref<boolean>(false)
|
||||
const base_model_loading = ref<boolean>(false)
|
||||
const model_type_list = ref<Array<KeyValue<string, string>>>([])
|
||||
|
||||
const base_model_list = ref<Array<BaseModel>>()
|
||||
const model_form_field = ref<Array<FormField>>([])
|
||||
const dialogVisible = ref<boolean>(false)
|
||||
const activeName = ref('base-info')
|
||||
const AddParamRef = ref()
|
||||
|
||||
const base_form_data_rule = ref<FormRules>({
|
||||
name: {
|
||||
required: true,
|
||||
trigger: 'blur',
|
||||
message: t('views.model.modelForm.modeName.requiredMessage'),
|
||||
},
|
||||
model_type: {
|
||||
required: true,
|
||||
trigger: 'change',
|
||||
message: t('views.model.modelForm.model_type.requiredMessage'),
|
||||
},
|
||||
model_name: {
|
||||
required: true,
|
||||
trigger: 'change',
|
||||
message: t('views.model.modelForm.base_model.requiredMessage'),
|
||||
},
|
||||
})
|
||||
|
||||
const base_form_data = ref<{
|
||||
name: string
|
||||
model_type: string
|
||||
model_name: string
|
||||
model_params_form: any
|
||||
}>({ name: '', model_type: '', model_name: '', model_params_form: [] })
|
||||
|
||||
const credential_form_data = ref<Dict<any>>({})
|
||||
|
||||
const form_data = computed({
|
||||
get: () => {
|
||||
return {
|
||||
...credential_form_data.value,
|
||||
name: base_form_data.value.name,
|
||||
model_type: base_form_data.value.model_type,
|
||||
model_name: base_form_data.value.model_name,
|
||||
model_params_form: base_form_data.value.model_params_form,
|
||||
}
|
||||
},
|
||||
set: (event: any) => {
|
||||
credential_form_data.value = event
|
||||
},
|
||||
})
|
||||
|
||||
const getModelForm = (model_name: string) => {
|
||||
if (!form_data.value.model_type) {
|
||||
MsgWarning(t('views.model.modelForm.model_type.requiredMessage'))
|
||||
base_form_data.value.model_name = ''
|
||||
return
|
||||
}
|
||||
if (providerValue.value) {
|
||||
ProviderApi.getModelCreateForm(
|
||||
providerValue.value.provider,
|
||||
form_data.value.model_type,
|
||||
model_name,
|
||||
).then((ok) => {
|
||||
model_form_field.value = ok.data
|
||||
// 渲染动态表单
|
||||
dynamicsFormRef.value?.render(model_form_field.value, undefined)
|
||||
})
|
||||
|
||||
ProviderApi.listBaseModelParamsForm(
|
||||
providerValue.value.provider,
|
||||
form_data.value.model_type,
|
||||
model_name,
|
||||
base_model_loading,
|
||||
).then((ok) => {
|
||||
base_form_data.value.model_params_form = ok.data
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const open = (provider: Provider, model_type?: string) => {
|
||||
ProviderApi.listModelType(provider.provider, model_type_loading).then((ok) => {
|
||||
model_type_list.value = ok.data
|
||||
})
|
||||
providerValue.value = provider
|
||||
dialogVisible.value = true
|
||||
base_form_data.value.model_type = model_type || ''
|
||||
activeName.value = 'base-info'
|
||||
if (model_type) {
|
||||
list_base_model(model_type)
|
||||
}
|
||||
}
|
||||
|
||||
const list_base_model = (model_type: any, change?: boolean) => {
|
||||
if (change) {
|
||||
base_form_data.value.model_name = ''
|
||||
base_form_data.value.model_params_form = []
|
||||
}
|
||||
if (providerValue.value) {
|
||||
ProviderApi.listBaseModel(providerValue.value.provider, model_type, base_model_loading).then(
|
||||
(ok) => {
|
||||
base_model_list.value = ok.data
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const close = () => {
|
||||
base_form_data.value = {
|
||||
name: '',
|
||||
model_type: '',
|
||||
model_name: '',
|
||||
model_params_form: [],
|
||||
}
|
||||
credential_form_data.value = {}
|
||||
model_form_field.value = []
|
||||
base_model_list.value = []
|
||||
loading.value = false
|
||||
dialogVisible.value = false
|
||||
}
|
||||
const submit = () => {
|
||||
dynamicsFormRef.value
|
||||
?.validate()
|
||||
.then(() => {
|
||||
if (providerValue.value) {
|
||||
ModelApi.createModel(
|
||||
{
|
||||
...base_form_data.value,
|
||||
credential: credential_form_data.value,
|
||||
provider: providerValue.value.provider,
|
||||
},
|
||||
loading,
|
||||
).then((ok) => {
|
||||
close()
|
||||
MsgSuccess(t('views.model.tip.createSuccessMessage'))
|
||||
emit('submit')
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
MsgError(t('views.model.tip.createErrorMessage'))
|
||||
})
|
||||
}
|
||||
|
||||
function openAddDrawer(data?: any, index?: any) {
|
||||
AddParamRef.value?.open(data, index)
|
||||
}
|
||||
|
||||
function deleteParam(index: any) {
|
||||
base_form_data.value.model_params_form.splice(index, 1)
|
||||
}
|
||||
|
||||
function refresh(data: any, index: any) {
|
||||
for (let i = 0; i < base_form_data.value.model_params_form.length; i++) {
|
||||
const field = base_form_data.value.model_params_form[i].field
|
||||
let label = base_form_data.value.model_params_form[i].label
|
||||
if (label && label.input_type === 'TooltipLabel') {
|
||||
label = label.label
|
||||
}
|
||||
let label2 = data.label
|
||||
if (label2 && label2.input_type === 'TooltipLabel') {
|
||||
label2 = label2.label
|
||||
}
|
||||
|
||||
if (field === data.field && index !== i) {
|
||||
MsgError(t('views.model.tip.errorMessage') + data.field)
|
||||
return
|
||||
}
|
||||
if (label === label2 && index !== i) {
|
||||
MsgError(t('views.model.tip.errorMessage') + label)
|
||||
return
|
||||
}
|
||||
}
|
||||
if (index !== null) {
|
||||
base_form_data.value.model_params_form.splice(index, 1, data)
|
||||
} else {
|
||||
base_form_data.value.model_params_form.push(data)
|
||||
}
|
||||
}
|
||||
|
||||
const toSelectProvider = () => {
|
||||
close()
|
||||
emit('change')
|
||||
}
|
||||
defineExpose({ open, close })
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.select-provider {
|
||||
font-size: 16px;
|
||||
color: rgba(100, 106, 115, 1);
|
||||
font-weight: 400;
|
||||
line-height: 24px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.active-breadcrumb {
|
||||
font-size: 16px;
|
||||
color: rgba(31, 35, 41, 1);
|
||||
font-weight: 500;
|
||||
line-height: 24px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,280 +0,0 @@
|
|||
<template>
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
width="600px"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
:destroy-on-close="true"
|
||||
:before-close="close"
|
||||
>
|
||||
<template #header="{ close, titleId, titleClass }">
|
||||
<el-breadcrumb separator=">">
|
||||
<el-breadcrumb-item
|
||||
><span class="active-breadcrumb">{{
|
||||
`${$t('common.edit')} ${providerValue?.name}`
|
||||
}}</span></el-breadcrumb-item
|
||||
>
|
||||
</el-breadcrumb>
|
||||
</template>
|
||||
|
||||
<DynamicsForm
|
||||
v-loading="formLoading"
|
||||
v-model="form_data"
|
||||
:render_data="model_form_field"
|
||||
:model="form_data"
|
||||
ref="dynamicsFormRef"
|
||||
label-position="top"
|
||||
require-asterisk-position="right"
|
||||
>
|
||||
<template #default>
|
||||
<el-form-item prop="name" :rules="base_form_data_rule.name">
|
||||
<template #label>
|
||||
<div class="flex align-center" style="display: inline-flex">
|
||||
<div class="mr-4">
|
||||
<span>{{ $t('views.model.modelForm.modeName.label') }} </span>
|
||||
</div>
|
||||
<el-tooltip effect="dark" placement="right">
|
||||
<template #content>
|
||||
<p>{{ $t('views.model.modelForm.modeName.tooltip') }}</p>
|
||||
</template>
|
||||
<AppIcon iconName="app-warning" class="app-warning-icon"></AppIcon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<el-input
|
||||
v-model="base_form_data.name"
|
||||
maxlength="64"
|
||||
show-word-limit
|
||||
:placeholder="$t('views.model.modelForm.modeName.placeholder')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item prop="model_type" :rules="base_form_data_rule.model_type">
|
||||
<template #label>
|
||||
<span>{{ $t('views.model.modelForm.model_type.label') }}</span>
|
||||
</template>
|
||||
<el-select
|
||||
disabled
|
||||
v-loading="model_type_loading"
|
||||
@change="list_base_model($event, true)"
|
||||
v-model="base_form_data.model_type"
|
||||
class="w-full m-2"
|
||||
:placeholder="$t('views.model.modelForm.model_type.placeholder')"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in model_type_list"
|
||||
:key="item.value"
|
||||
:label="item.key"
|
||||
:value="item.value"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item prop="model_name" :rules="base_form_data_rule.model_name">
|
||||
<template #label>
|
||||
<div class="flex align-center" style="display: inline-flex">
|
||||
<div class="mr-4">
|
||||
<span>{{ $t('views.model.modelForm.base_model.label') }} </span>
|
||||
<span class="danger ml-4">{{
|
||||
$t('views.model.modelForm.base_model.tooltip')
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<el-select
|
||||
@change="getModelForm($event)"
|
||||
v-loading="base_model_loading"
|
||||
v-model="base_form_data.model_name"
|
||||
class="w-full m-2"
|
||||
:placeholder="$t('views.model.modelForm.base_model.requiredMessage')"
|
||||
filterable
|
||||
allow-create
|
||||
default-first-option
|
||||
>
|
||||
<el-option v-for="item in base_model_list" :key="item.name" :value="item.name">
|
||||
<template #default>
|
||||
<div class="flex align-center" style="display: inline-flex">
|
||||
<div class="flex-between mr-4">
|
||||
<span>{{ item.name }} </span>
|
||||
</div>
|
||||
<el-tooltip effect="dark" placement="right" v-if="item.desc">
|
||||
<template #content>
|
||||
<p>{{ item.desc }}</p>
|
||||
</template>
|
||||
<AppIcon iconName="app-warning" class="app-warning-icon"></AppIcon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</DynamicsForm>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="close">{{ $t('common.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="submit" :loading="loading">
|
||||
{{ $t('common.modify') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import {ref, computed} from 'vue'
|
||||
import type {Provider, BaseModel, Model} from '@/api/type/model'
|
||||
import type {Dict, KeyValue} from '@/api/type/common'
|
||||
import ModelApi from '@/api/system-shared/model'
|
||||
import ProviderApi from '@/api/model/provider'
|
||||
import type {FormField} from '@/components/dynamics-form/type'
|
||||
import DynamicsForm from '@/components/dynamics-form/index.vue'
|
||||
import type {FormRules} from 'element-plus'
|
||||
import {MsgSuccess} from '@/utils/message'
|
||||
import {PermissionType, PermissionDesc} from '@/enums/model'
|
||||
import {t} from '@/locales'
|
||||
|
||||
const providerValue = ref<Provider>()
|
||||
const dynamicsFormRef = ref<InstanceType<typeof DynamicsForm>>()
|
||||
const emit = defineEmits(['change', 'submit'])
|
||||
const loading = ref<boolean>(false)
|
||||
const formLoading = ref<boolean>(false)
|
||||
const model_type_loading = ref<boolean>(false)
|
||||
const base_model_loading = ref<boolean>(false)
|
||||
const model_type_list = ref<Array<KeyValue<string, string>>>([])
|
||||
const modelValue = ref<Model>()
|
||||
const base_model_list = ref<Array<BaseModel>>([])
|
||||
const model_form_field = ref<Array<FormField>>([])
|
||||
const dialogVisible = ref<boolean>(false)
|
||||
|
||||
const base_form_data_rule = ref<FormRules>({
|
||||
name: {
|
||||
required: true,
|
||||
trigger: 'blur',
|
||||
message: t('views.model.modelForm.modeName.requiredMessage'),
|
||||
},
|
||||
model_type: {
|
||||
required: true,
|
||||
trigger: 'change',
|
||||
message: t('views.model.modelForm.model_type.requiredMessage'),
|
||||
},
|
||||
model_name: {
|
||||
required: true,
|
||||
trigger: 'change',
|
||||
message: t('views.model.modelForm.base_model.requiredMessage'),
|
||||
},
|
||||
})
|
||||
|
||||
const base_form_data = ref<{
|
||||
name: string
|
||||
model_type: string
|
||||
|
||||
model_name: string
|
||||
}>({name: '', model_type: '', model_name: ''})
|
||||
|
||||
const credential_form_data = ref<Dict<any>>({})
|
||||
|
||||
const form_data = computed({
|
||||
get: () => {
|
||||
return {...credential_form_data.value, ...base_form_data.value}
|
||||
},
|
||||
set: (event: any) => {
|
||||
credential_form_data.value = event
|
||||
},
|
||||
})
|
||||
|
||||
const getModelForm = (model_name: string) => {
|
||||
if (providerValue.value) {
|
||||
ProviderApi.getModelCreateForm(
|
||||
providerValue.value.provider,
|
||||
form_data.value.model_type,
|
||||
model_name,
|
||||
).then((ok) => {
|
||||
model_form_field.value = ok.data
|
||||
if (modelValue.value) {
|
||||
// 渲染动态表单
|
||||
dynamicsFormRef.value?.render(model_form_field.value, modelValue.value.credential)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
const list_base_model = (model_type: any, change?: boolean) => {
|
||||
if (change) {
|
||||
base_form_data.value.model_name = ''
|
||||
}
|
||||
if (providerValue.value) {
|
||||
ProviderApi.listBaseModel(providerValue.value.provider, model_type, base_model_loading).then(
|
||||
(ok) => {
|
||||
base_model_list.value = ok.data
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
const open = (provider: Provider, model: Model) => {
|
||||
modelValue.value = model
|
||||
ModelApi.getModelById(model.id, formLoading).then((ok) => {
|
||||
modelValue.value = ok.data
|
||||
ProviderApi.listModelType(model.provider, model_type_loading).then((ok) => {
|
||||
model_type_list.value = ok.data
|
||||
list_base_model(model.model_type)
|
||||
})
|
||||
providerValue.value = provider
|
||||
|
||||
base_form_data.value = {
|
||||
name: model.name,
|
||||
model_type: model.model_type,
|
||||
model_name: model.model_name,
|
||||
}
|
||||
form_data.value = model.credential
|
||||
getModelForm(model.model_name)
|
||||
})
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
const close = () => {
|
||||
base_form_data.value = {name: '', model_type: '', model_name: ''}
|
||||
dynamicsFormRef.value?.ruleFormRef?.resetFields()
|
||||
credential_form_data.value = {}
|
||||
model_form_field.value = []
|
||||
base_model_list.value = []
|
||||
dialogVisible.value = false
|
||||
}
|
||||
|
||||
const submit = () => {
|
||||
dynamicsFormRef.value?.validate().then(() => {
|
||||
if (modelValue.value) {
|
||||
ModelApi.updateModel(
|
||||
modelValue.value.id,
|
||||
{
|
||||
...base_form_data.value,
|
||||
credential: credential_form_data.value,
|
||||
},
|
||||
loading,
|
||||
).then((ok) => {
|
||||
MsgSuccess(t('views.model.tip.updateSuccessMessage'))
|
||||
close()
|
||||
emit('submit')
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({open, close})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.select-provider {
|
||||
font-size: 16px;
|
||||
color: rgba(100, 106, 115, 1);
|
||||
font-weight: 400;
|
||||
line-height: 24px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.active-breadcrumb {
|
||||
font-size: 16px;
|
||||
color: rgba(31, 35, 41, 1);
|
||||
font-weight: 500;
|
||||
line-height: 24px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,297 +0,0 @@
|
|||
<template>
|
||||
<card-box isShared :title="model.name" shadow="hover" class="model-card">
|
||||
<template #icon>
|
||||
<span style="height: 32px; width: 32px" :innerHTML="icon"></span>
|
||||
</template>
|
||||
<template #title>
|
||||
<div class="flex" style="height: 22px">
|
||||
{{ model.name }}
|
||||
<span v-if="currentModel.status === 'ERROR'">
|
||||
<el-tooltip effect="dark" :content="errMessage" placement="top">
|
||||
<el-icon class="danger ml-4" size="18"><Warning /></el-icon>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
<span v-if="currentModel.status === 'PAUSE_DOWNLOAD'">
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="`${$t('views.model.modelForm.base_model.label')}: ${props.model.model_name} ${$t('views.model.tip.downloadError')}`"
|
||||
placement="top"
|
||||
>
|
||||
<el-icon class="danger ml-4" size="18"><Warning /></el-icon>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<template #subTitle>
|
||||
<el-text class="color-secondary lighter" size="small">
|
||||
{{ $t('common.creator') }}: {{ model.username }}
|
||||
</el-text>
|
||||
</template>
|
||||
<ul>
|
||||
<li class="flex mb-4">
|
||||
<el-text type="info" class="color-secondary"
|
||||
>{{ $t('views.model.modelForm.model_type.label') }}
|
||||
</el-text>
|
||||
<span class="ellipsis ml-16">
|
||||
{{ $t(modelType[model.model_type as keyof typeof modelType]) }}</span
|
||||
>
|
||||
</li>
|
||||
<li class="flex">
|
||||
<el-text type="info" class="color-secondary"
|
||||
>{{ $t('views.model.modelForm.base_model.label') }}
|
||||
</el-text>
|
||||
<span class="ellipsis-1 ml-16" style="height: 20px; width: 70%">
|
||||
{{ model.model_name }}</span
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
<!-- progress -->
|
||||
<div class="progress-mask" v-if="currentModel.status === 'DOWNLOAD'">
|
||||
<!-- <DownloadLoading class="percentage" /> -->
|
||||
|
||||
<div class="percentage-label flex-center">
|
||||
{{ $t('views.model.download.downloading') }} <span class="dotting"></span>
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
class="ml-16"
|
||||
:disabled="!is_permisstion"
|
||||
@click.stop="cancelDownload"
|
||||
>{{ $t('views.model.download.cancelDownload') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #mouseEnter>
|
||||
<el-dropdown trigger="click">
|
||||
<el-button text @click.stop>
|
||||
<el-icon>
|
||||
<MoreFilled />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item
|
||||
icon="EditPen"
|
||||
:disabled="!is_permisstion"
|
||||
text
|
||||
@click.stop="openEditModel"
|
||||
v-hasPermission="[
|
||||
RoleConst.WORKSPACE_MANAGE.getWorkspaceRole,
|
||||
RoleConst.USER.getWorkspaceRole,
|
||||
PermissionConst.MODEL_EDIT.getWorkspacePermission,
|
||||
]"
|
||||
>
|
||||
{{ $t('common.modify') }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item icon="Lock" @click.stop="openAuthorizedWorkspaceDialog(model)">{{
|
||||
$t('views.system.shared.authorized_workspace')
|
||||
}}</el-dropdown-item>
|
||||
|
||||
<el-dropdown-item
|
||||
v-if="
|
||||
currentModel.model_type === 'TTS' ||
|
||||
currentModel.model_type === 'LLM' ||
|
||||
currentModel.model_type === 'IMAGE' ||
|
||||
currentModel.model_type === 'TTI'
|
||||
"
|
||||
:disabled="!is_permisstion"
|
||||
icon="Setting"
|
||||
@click.stop="openParamSetting"
|
||||
v-hasPermission="[
|
||||
RoleConst.WORKSPACE_MANAGE.getWorkspaceRole,
|
||||
RoleConst.USER.getWorkspaceRole,
|
||||
PermissionConst.MODEL_EDIT.getWorkspacePermission,
|
||||
]"
|
||||
>
|
||||
{{ $t('views.model.modelForm.title.paramSetting') }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item
|
||||
divided
|
||||
icon="Delete"
|
||||
:disabled="!is_permisstion"
|
||||
text
|
||||
@click.stop="deleteModel"
|
||||
v-hasPermission="[
|
||||
RoleConst.WORKSPACE_MANAGE.getWorkspaceRole,
|
||||
RoleConst.USER.getWorkspaceRole,
|
||||
PermissionConst.MODEL_DELETE.getWorkspacePermission,
|
||||
]"
|
||||
>
|
||||
{{ $t('common.delete') }}
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
<EditModel ref="editModelRef" @submit="emit('change')"></EditModel>
|
||||
<AuthorizedWorkspace ref="AuthorizedWorkspaceDialogRef"></AuthorizedWorkspace>
|
||||
<ParamSettingDialog ref="paramSettingRef" :model="model" />
|
||||
</card-box>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import type { Provider, Model } from '@/api/type/model'
|
||||
import ModelApi from '@/api/system-shared/model'
|
||||
import { computed, ref, onMounted, onBeforeUnmount } from 'vue'
|
||||
import EditModel from '@/views/shared/model-shared/component/EditModel.vue'
|
||||
// import DownloadLoading from '@/components/loading/DownloadLoading.vue'
|
||||
import { MsgConfirm } from '@/utils/message'
|
||||
import { modelType } from '@/enums/model'
|
||||
import useStore from '@/stores'
|
||||
import ParamSettingDialog from './ParamSettingDialog.vue'
|
||||
import { t } from '@/locales'
|
||||
import { PermissionConst, EditionConst, RoleConst } from '@/utils/permission/data'
|
||||
import AuthorizedWorkspace from '@/views/system-shared/AuthorizedWorkspaceDialog.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
model: Model
|
||||
provider_list: Array<Provider>
|
||||
updateModelById: (model_id: string, model: Model) => void
|
||||
}>()
|
||||
|
||||
const { user } = useStore()
|
||||
const downModel = ref<Model>()
|
||||
const AuthorizedWorkspaceDialogRef = ref()
|
||||
|
||||
const is_permisstion = computed(() => {
|
||||
return user.userInfo?.id == props.model.user_id
|
||||
})
|
||||
const currentModel = computed(() => {
|
||||
if (downModel.value) {
|
||||
return downModel.value
|
||||
} else {
|
||||
return props.model
|
||||
}
|
||||
})
|
||||
function openAuthorizedWorkspaceDialog(row: any) {
|
||||
if (AuthorizedWorkspaceDialogRef.value) {
|
||||
AuthorizedWorkspaceDialogRef.value.open(row, 'Model')
|
||||
}
|
||||
}
|
||||
const errMessage = computed(() => {
|
||||
if (currentModel.value.meta && currentModel.value.meta.message) {
|
||||
if (currentModel.value.meta.message === 'pull model manifest: file does not exist') {
|
||||
return `${currentModel.value.model_name} ${t('views.model.tip.noModel')}`
|
||||
}
|
||||
return currentModel.value.meta.message
|
||||
}
|
||||
return ''
|
||||
})
|
||||
const emit = defineEmits(['change', 'update:model'])
|
||||
const editModelRef = ref<InstanceType<typeof EditModel>>()
|
||||
let interval: any
|
||||
const deleteModel = () => {
|
||||
MsgConfirm(
|
||||
t('views.model.delete.confirmTitle'),
|
||||
`${t('views.model.delete.confirmMessage')}${props.model.name} ?`,
|
||||
{
|
||||
confirmButtonText: t('common.confirm'),
|
||||
confirmButtonClass: 'danger',
|
||||
},
|
||||
)
|
||||
.then(() => {
|
||||
ModelApi.deleteModel(props.model.id).then(() => {
|
||||
emit('change')
|
||||
})
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
|
||||
const cancelDownload = () => {
|
||||
ModelApi.pauseDownload(props.model.id).then(() => {
|
||||
downModel.value = undefined
|
||||
emit('change')
|
||||
})
|
||||
}
|
||||
const openEditModel = () => {
|
||||
const provider = props.provider_list.find((p) => p.provider === props.model.provider)
|
||||
if (provider) {
|
||||
editModelRef.value?.open(provider, props.model)
|
||||
}
|
||||
}
|
||||
const icon = computed(() => {
|
||||
return props.provider_list.find((p) => p.provider === props.model.provider)?.icon
|
||||
})
|
||||
|
||||
/**
|
||||
* 初始化轮询
|
||||
*/
|
||||
const initInterval = () => {
|
||||
interval = setInterval(() => {
|
||||
if (currentModel.value.status === 'DOWNLOAD') {
|
||||
ModelApi.getModelMetaById(props.model.id).then((ok) => {
|
||||
downModel.value = ok.data
|
||||
})
|
||||
} else {
|
||||
if (downModel.value) {
|
||||
props.updateModelById(props.model.id, downModel.value)
|
||||
downModel.value = undefined
|
||||
}
|
||||
}
|
||||
}, 6000)
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭轮询
|
||||
*/
|
||||
const closeInterval = () => {
|
||||
if (interval) {
|
||||
clearInterval(interval)
|
||||
}
|
||||
}
|
||||
|
||||
const paramSettingRef = ref<InstanceType<typeof ParamSettingDialog>>()
|
||||
const openParamSetting = () => {
|
||||
paramSettingRef.value?.open()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initInterval()
|
||||
})
|
||||
onBeforeUnmount(() => {
|
||||
// 清除定时任务
|
||||
closeInterval()
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.model-card {
|
||||
min-height: 135px;
|
||||
min-width: auto;
|
||||
|
||||
.operation-button {
|
||||
position: absolute;
|
||||
right: 12px;
|
||||
bottom: 12px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.progress-mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-color: rgba(255, 255, 255, 0.9);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 99;
|
||||
text-align: center;
|
||||
|
||||
.percentage {
|
||||
margin-top: 55px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
// .percentage-value {
|
||||
// display: flex;
|
||||
// font-size: 13px;
|
||||
// align-items: center;
|
||||
// color: var(--app-text-color-secondary);
|
||||
// }
|
||||
.percentage-label {
|
||||
margin-top: 50px;
|
||||
margin-left: 10px;
|
||||
font-size: 13px;
|
||||
color: var(--app-text-color-secondary);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,227 +0,0 @@
|
|||
<template>
|
||||
<card-box isShared :title="model.name" shadow="hover" class="model-card">
|
||||
<template #icon>
|
||||
<span style="height: 32px; width: 32px" :innerHTML="icon"></span>
|
||||
</template>
|
||||
<template #title>
|
||||
<div class="flex" style="height: 22px">
|
||||
{{ model.name }}
|
||||
<span v-if="currentModel.status === 'ERROR'">
|
||||
<el-tooltip effect="dark" :content="errMessage" placement="top">
|
||||
<el-icon class="danger ml-4" size="18"><Warning /></el-icon>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
<span v-if="currentModel.status === 'PAUSE_DOWNLOAD'">
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="`${$t('views.model.modelForm.base_model.label')}: ${props.model.model_name} ${$t('views.model.tip.downloadError')}`"
|
||||
placement="top"
|
||||
>
|
||||
<el-icon class="danger ml-4" size="18"><Warning /></el-icon>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<template #subTitle>
|
||||
<el-text class="color-secondary lighter" size="small">
|
||||
{{ $t('common.creator') }}: {{ model.username }}
|
||||
</el-text>
|
||||
</template>
|
||||
<ul>
|
||||
<li class="flex mb-4">
|
||||
<el-text type="info" class="color-secondary"
|
||||
>{{ $t('views.model.modelForm.model_type.label') }}
|
||||
</el-text>
|
||||
<span class="ellipsis ml-16">
|
||||
{{ $t(modelType[model.model_type as keyof typeof modelType]) }}</span
|
||||
>
|
||||
</li>
|
||||
<li class="flex">
|
||||
<el-text type="info" class="color-secondary"
|
||||
>{{ $t('views.model.modelForm.base_model.label') }}
|
||||
</el-text>
|
||||
<span class="ellipsis-1 ml-16" style="height: 20px; width: 70%">
|
||||
{{ model.model_name }}</span
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
<!-- progress -->
|
||||
<div class="progress-mask" v-if="currentModel.status === 'DOWNLOAD'">
|
||||
<!-- <DownloadLoading class="percentage" /> -->
|
||||
|
||||
<div class="percentage-label flex-center">
|
||||
{{ $t('views.model.download.downloading') }} <span class="dotting"></span>
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
class="ml-16"
|
||||
:disabled="!is_permisstion"
|
||||
@click.stop="cancelDownload"
|
||||
>{{ $t('views.model.download.cancelDownload') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<EditModel ref="editModelRef" @submit="emit('change')"></EditModel>
|
||||
<ParamSettingDialog ref="paramSettingRef" :model="model" />
|
||||
</card-box>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import type { Provider, Model } from '@/api/type/model'
|
||||
import ModelApi from '@/api/system-shared/model'
|
||||
import { computed, ref, onMounted, onBeforeUnmount } from 'vue'
|
||||
import EditModel from '@/views/shared/model-shared/component/EditModel.vue'
|
||||
// import DownloadLoading from '@/components/loading/DownloadLoading.vue'
|
||||
import { MsgConfirm } from '@/utils/message'
|
||||
import { modelType } from '@/enums/model'
|
||||
import useStore from '@/stores'
|
||||
import AuthorizedWorkspace from '@/views/system-shared/AuthorizedWorkspaceDialog.vue'
|
||||
import ParamSettingDialog from './ParamSettingDialog.vue'
|
||||
import { t } from '@/locales'
|
||||
|
||||
const props = defineProps<{
|
||||
model: Model
|
||||
provider_list: Array<Provider>
|
||||
updateModelById: (model_id: string, model: Model) => void
|
||||
}>()
|
||||
|
||||
const { user } = useStore()
|
||||
const downModel = ref<Model>()
|
||||
|
||||
const is_permisstion = computed(() => {
|
||||
return user.userInfo?.id == props.model.user_id
|
||||
})
|
||||
const currentModel = computed(() => {
|
||||
if (downModel.value) {
|
||||
return downModel.value
|
||||
} else {
|
||||
return props.model
|
||||
}
|
||||
})
|
||||
|
||||
const errMessage = computed(() => {
|
||||
if (currentModel.value.meta && currentModel.value.meta.message) {
|
||||
if (currentModel.value.meta.message === 'pull model manifest: file does not exist') {
|
||||
return `${currentModel.value.model_name} ${t('views.model.tip.noModel')}`
|
||||
}
|
||||
return currentModel.value.meta.message
|
||||
}
|
||||
return ''
|
||||
})
|
||||
const emit = defineEmits(['change', 'update:model'])
|
||||
const editModelRef = ref<InstanceType<typeof EditModel>>()
|
||||
let interval: any
|
||||
const deleteModel = () => {
|
||||
MsgConfirm(
|
||||
t('views.model.delete.confirmTitle'),
|
||||
`${t('views.model.delete.confirmMessage')}${props.model.name} ?`,
|
||||
{
|
||||
confirmButtonText: t('common.confirm'),
|
||||
confirmButtonClass: 'danger',
|
||||
},
|
||||
)
|
||||
.then(() => {
|
||||
ModelApi.deleteModel(props.model.id).then(() => {
|
||||
emit('change')
|
||||
})
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
|
||||
const cancelDownload = () => {
|
||||
ModelApi.pauseDownload(props.model.id).then(() => {
|
||||
downModel.value = undefined
|
||||
emit('change')
|
||||
})
|
||||
}
|
||||
const openEditModel = () => {
|
||||
const provider = props.provider_list.find((p) => p.provider === props.model.provider)
|
||||
if (provider) {
|
||||
editModelRef.value?.open(provider, props.model)
|
||||
}
|
||||
}
|
||||
const icon = computed(() => {
|
||||
return props.provider_list.find((p) => p.provider === props.model.provider)?.icon
|
||||
})
|
||||
|
||||
/**
|
||||
* 初始化轮询
|
||||
*/
|
||||
const initInterval = () => {
|
||||
interval = setInterval(() => {
|
||||
if (currentModel.value.status === 'DOWNLOAD') {
|
||||
ModelApi.getModelMetaById(props.model.id).then((ok) => {
|
||||
downModel.value = ok.data
|
||||
})
|
||||
} else {
|
||||
if (downModel.value) {
|
||||
props.updateModelById(props.model.id, downModel.value)
|
||||
downModel.value = undefined
|
||||
}
|
||||
}
|
||||
}, 6000)
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭轮询
|
||||
*/
|
||||
const closeInterval = () => {
|
||||
if (interval) {
|
||||
clearInterval(interval)
|
||||
}
|
||||
}
|
||||
|
||||
const paramSettingRef = ref<InstanceType<typeof ParamSettingDialog>>()
|
||||
const openParamSetting = () => {
|
||||
paramSettingRef.value?.open()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initInterval()
|
||||
})
|
||||
onBeforeUnmount(() => {
|
||||
// 清除定时任务
|
||||
closeInterval()
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.model-card {
|
||||
min-height: 135px;
|
||||
min-width: auto;
|
||||
|
||||
.operation-button {
|
||||
position: absolute;
|
||||
right: 12px;
|
||||
bottom: 12px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.progress-mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-color: rgba(255, 255, 255, 0.9);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 99;
|
||||
text-align: center;
|
||||
|
||||
.percentage {
|
||||
margin-top: 55px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
// .percentage-value {
|
||||
// display: flex;
|
||||
// font-size: 13px;
|
||||
// align-items: center;
|
||||
// color: var(--app-text-color-secondary);
|
||||
// }
|
||||
.percentage-label {
|
||||
margin-top: 50px;
|
||||
margin-left: 10px;
|
||||
font-size: 13px;
|
||||
color: var(--app-text-color-secondary);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,166 +0,0 @@
|
|||
<template>
|
||||
<el-dialog
|
||||
:title="$t('views.model.modelForm.title.paramSetting')"
|
||||
v-model="dialogVisible"
|
||||
width="800px"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
:destroy-on-close="true"
|
||||
:before-close="close"
|
||||
>
|
||||
<el-button type="primary" @click="openAddDrawer()" class="mb-12">
|
||||
{{ $t('views.model.modelForm.title.addParam') }}
|
||||
</el-button>
|
||||
<el-table :data="modelParamsForm" class="mb-16">
|
||||
<el-table-column
|
||||
prop="label"
|
||||
:label="$t('dynamicsForm.paramForm.name.label')"
|
||||
show-overflow-tooltip
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.label && row.label.input_type === 'TooltipLabel'">{{
|
||||
row.label.label
|
||||
}}</span>
|
||||
<span v-else>{{ row.label }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="field"
|
||||
:label="$t('dynamicsForm.paramForm.field.label')"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column :label="$t('dynamicsForm.paramForm.input_type.label')" width="110px">
|
||||
<template #default="{ row }">
|
||||
<el-tag type="info" class="info-tag">{{
|
||||
input_type_list.find((item) => item.value === row.input_type)?.label
|
||||
}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="default_value"
|
||||
:label="$t('dynamicsForm.default.label')"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column :label="$t('common.required')">
|
||||
<template #default="{ row }">
|
||||
<div @click.stop>
|
||||
<el-switch disabled size="small" v-model="row.required" />
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column :label="$t('common.operation')" align="left" width="90">
|
||||
<template #default="{ row, $index }">
|
||||
<span class="mr-4">
|
||||
<el-tooltip effect="dark" :content="$t('common.modify')" placement="top">
|
||||
<el-button type="primary" text @click.stop="openAddDrawer(row, $index)">
|
||||
<el-icon><EditPen /></el-icon>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
<el-tooltip effect="dark" :content="$t('common.delete')" placement="top">
|
||||
<el-button type="primary" text @click="deleteParam($index)">
|
||||
<el-icon>
|
||||
<Delete />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="close">{{ $t('common.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="submit" :loading="loading">
|
||||
{{ $t('common.save') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<AddParamDrawer ref="AddParamRef" @refresh="refresh" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Model } from '@/api/type/model'
|
||||
import { ref } from 'vue'
|
||||
import AddParamDrawer from './AddParamDrawer.vue'
|
||||
import { MsgError, MsgSuccess } from '@/utils/message'
|
||||
import ModelApi from '@/api/system-shared/model'
|
||||
import { input_type_list } from '@/components/dynamics-form/constructor/data'
|
||||
import { t } from '@/locales'
|
||||
const props = defineProps<{
|
||||
model: Model
|
||||
}>()
|
||||
|
||||
const loading = ref<boolean>(false)
|
||||
const dialogVisible = ref<boolean>(false)
|
||||
const modelParamsForm = ref<any[]>([])
|
||||
const AddParamRef = ref()
|
||||
|
||||
const open = () => {
|
||||
dialogVisible.value = true
|
||||
loading.value = true
|
||||
ModelApi.getModelParamsForm(props.model.id, loading)
|
||||
.then((ok) => {
|
||||
loading.value = false
|
||||
modelParamsForm.value = ok.data
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
const close = () => {
|
||||
dialogVisible.value = false
|
||||
}
|
||||
|
||||
function openAddDrawer(data?: any, index?: any) {
|
||||
AddParamRef.value?.open(data, index)
|
||||
}
|
||||
|
||||
function deleteParam(index: any) {
|
||||
modelParamsForm.value.splice(index, 1)
|
||||
}
|
||||
|
||||
function refresh(data: any, index: any) {
|
||||
for (let i = 0; i < modelParamsForm.value.length; i++) {
|
||||
const field = modelParamsForm.value[i].field
|
||||
let label = modelParamsForm.value[i].label
|
||||
if (label && label.input_type === 'TooltipLabel') {
|
||||
label = label.label
|
||||
}
|
||||
let label2 = data.label
|
||||
if (label2 && label2.input_type === 'TooltipLabel') {
|
||||
label2 = label2.label
|
||||
}
|
||||
|
||||
if (field === data.field && index !== i) {
|
||||
MsgError(t('views.model.tip.errorMessage') + data.field)
|
||||
return
|
||||
}
|
||||
if (label === label2 && index !== i) {
|
||||
MsgError(t('views.model.tip.errorMessage') + label)
|
||||
return
|
||||
}
|
||||
}
|
||||
if (index !== null) {
|
||||
modelParamsForm.value.splice(index, 1, data)
|
||||
} else {
|
||||
modelParamsForm.value.push(data)
|
||||
}
|
||||
}
|
||||
|
||||
function submit() {
|
||||
ModelApi.updateModelParamsForm(props.model.id, modelParamsForm.value, loading).then(
|
||||
(ok) => {
|
||||
MsgSuccess(t('views.model.tip.saveSuccessMessage'))
|
||||
close()
|
||||
// emit('submit')
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
defineExpose({ open, close })
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
|
|
@ -1,178 +0,0 @@
|
|||
<template>
|
||||
<div class="provider-list">
|
||||
<el-scrollbar>
|
||||
<div class="p-8">
|
||||
<div
|
||||
class="all-mode flex cursor"
|
||||
@click="clickListHandle(allObj as Provider)"
|
||||
:class="!active?.provider ? 'all-mode-active color-primary-1' : ''"
|
||||
>
|
||||
<AppIcon
|
||||
class="mr-8 color-primary"
|
||||
style="height: 20px; width: 20px"
|
||||
:iconName="'app-all-menu-active'"
|
||||
></AppIcon>
|
||||
<span>{{ $t('views.model.modelType.allModel') }}</span>
|
||||
</div>
|
||||
|
||||
<el-collapse class="model-collapse" expand-icon-position="left">
|
||||
<el-collapse-item
|
||||
:title="$t('views.model.modelType.publicModel')"
|
||||
name="1"
|
||||
icon="CaretRight"
|
||||
>
|
||||
<template #title>
|
||||
<div class="flex align-center">
|
||||
<AppIcon iconName="app-folder" style="font-size: 20px"></AppIcon>
|
||||
<span class="ml-8">
|
||||
{{ $t('views.model.modelType.publicModel') }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<common-list
|
||||
:data="online_provider_list"
|
||||
v-loading="loading"
|
||||
@click="clickListHandle"
|
||||
value-key="provider"
|
||||
default-active=""
|
||||
ref="commonList1"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<div class="flex align-center">
|
||||
<span
|
||||
:innerHTML="row.icon"
|
||||
alt=""
|
||||
style="height: 20px; width: 20px"
|
||||
class="mr-8"
|
||||
/>
|
||||
<span class="ellipsis-1" :title="row.name">{{ row.name }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</common-list>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item
|
||||
:title="$t('views.model.modelType.privateModel')"
|
||||
name="2"
|
||||
icon="CaretRight"
|
||||
>
|
||||
<template #title>
|
||||
<div class="flex align-center">
|
||||
<AppIcon iconName="app-folder" style="font-size: 20px"></AppIcon>
|
||||
<span class="ml-8">
|
||||
{{ $t('views.model.modelType.privateModel') }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<common-list
|
||||
:data="local_provider_list"
|
||||
v-loading="loading"
|
||||
@click="clickListHandle"
|
||||
value-key="provider"
|
||||
default-active=""
|
||||
ref="commonList2"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<div class="flex align-center">
|
||||
<span
|
||||
:innerHTML="row.icon"
|
||||
alt=""
|
||||
style="height: 20px; width: 20px"
|
||||
class="mr-8"
|
||||
/>
|
||||
<span class="ellipsis-1" :title="row.name">{{ row.name }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</common-list>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { watch, ref } from 'vue'
|
||||
import type { Provider, Model } from '@/api/type/model'
|
||||
import { modelTypeList, allObj } from '@/views/shared/model-shared/component/data'
|
||||
const props = defineProps<{
|
||||
data: Array<Provider>
|
||||
loading: boolean
|
||||
active?: Provider
|
||||
}>()
|
||||
const emit = defineEmits(['click'])
|
||||
|
||||
const online_provider_list = ref<Array<Provider>>([])
|
||||
const local_provider_list = ref<Array<Provider>>([])
|
||||
|
||||
watch(
|
||||
() => props.data,
|
||||
(list) => {
|
||||
const local_provider = [
|
||||
'model_ollama_provider',
|
||||
'model_local_provider',
|
||||
'model_xinference_provider',
|
||||
'model_vllm_provider',
|
||||
]
|
||||
list
|
||||
.filter((v) => v.provider)
|
||||
?.forEach((item) => {
|
||||
if (local_provider.indexOf(item.provider) > -1) {
|
||||
local_provider_list.value.push(item)
|
||||
} else {
|
||||
online_provider_list.value.push(item)
|
||||
}
|
||||
})
|
||||
online_provider_list.value.sort((a, b) => a.provider.localeCompare(b.provider))
|
||||
local_provider_list.value.sort((a, b) => a.provider.localeCompare(b.provider))
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
const clickListHandle = (item: Provider) => {
|
||||
emit('click', item)
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.provider-list {
|
||||
height: calc(var(--app-main-height));
|
||||
.all-mode {
|
||||
padding: 10px 8px;
|
||||
font-weight: 400;
|
||||
}
|
||||
.all-mode-active {
|
||||
border-radius: 4px;
|
||||
color: var(--el-color-primary);
|
||||
font-weight: 500 !important;
|
||||
}
|
||||
.model-collapse {
|
||||
border-top: none !important;
|
||||
border-bottom: none !important;
|
||||
:deep(.el-collapse-item__header) {
|
||||
border-bottom: none !important;
|
||||
padding-left: 8px;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
height: 40px;
|
||||
background: none;
|
||||
&:hover {
|
||||
background: var(--app-text-color-light-1);
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
:deep(.el-collapse-item) {
|
||||
margin-top: 2px;
|
||||
}
|
||||
:deep(.common-list) {
|
||||
li {
|
||||
padding-left: 50px !important;
|
||||
}
|
||||
}
|
||||
:deep(.el-collapse-item__wrap) {
|
||||
border-bottom: none !important;
|
||||
background: none !important;
|
||||
}
|
||||
:deep(.el-collapse-item__content) {
|
||||
padding-bottom: 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
<template>
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
width="600px"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
:destroy-on-close="true"
|
||||
:before-close="close"
|
||||
append-to-body
|
||||
>
|
||||
<template #header>
|
||||
<div class="flex-between">
|
||||
<h4>{{ $t('views.model.providerPlaceholder') }}</h4>
|
||||
<el-dropdown>
|
||||
<span class="cursor">
|
||||
{{ currentModelType || $t('views..model.modelType.allModel') }}
|
||||
<el-icon class="el-icon--right">
|
||||
<arrow-down />
|
||||
</el-icon>
|
||||
</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item
|
||||
v-for="item in modelTypeOptions"
|
||||
:key="item.value"
|
||||
@click="checkModelType(item.value)"
|
||||
>
|
||||
<span>{{ item.text }}</span>
|
||||
<el-icon v-if="currentModelType === item.text"><Check /></el-icon>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</template>
|
||||
<el-row :gutter="12" v-loading="loading">
|
||||
<el-col :span="12" class="mb-16" v-for="(data, index) in list_provider" :key="index">
|
||||
<el-card shadow="hover" @click="go_create(data)">
|
||||
<div class="flex align-center cursor">
|
||||
<span :innerHTML="data.icon" alt="" style="height: 24px; width: 24px" class="mr-8" />
|
||||
<span>{{ data.name }}</span>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import ProviderApi from '@/api/model/provider'
|
||||
import type { Provider } from '@/api/type/model'
|
||||
import { modelTypeList } from './data'
|
||||
import { t } from '@/locales'
|
||||
|
||||
const loading = ref<boolean>(false)
|
||||
const dialogVisible = ref<boolean>(false)
|
||||
const list_provider = ref<Array<Provider>>([])
|
||||
const currentModelType = ref('')
|
||||
const selectModelType = ref('')
|
||||
const modelTypeOptions = [{ text: t('views.model.modelType.allModel'), value: '' }, ...modelTypeList]
|
||||
|
||||
const open = (model_type?: string) => {
|
||||
dialogVisible.value = true
|
||||
const option = modelTypeOptions.find((item) => item.text === currentModelType.value)
|
||||
checkModelType(model_type ? model_type : option ? option.value : '')
|
||||
}
|
||||
|
||||
const close = () => {
|
||||
dialogVisible.value = false
|
||||
}
|
||||
|
||||
const checkModelType = (model_type: string) => {
|
||||
selectModelType.value = model_type
|
||||
currentModelType.value = modelTypeOptions.filter((item) => item.value === model_type)[0].text
|
||||
ProviderApi.getProviderByModelType(model_type, loading).then((ok) => {
|
||||
list_provider.value = ok.data
|
||||
list_provider.value.sort((a, b) => a.provider.localeCompare(b.provider))
|
||||
})
|
||||
}
|
||||
|
||||
const emit = defineEmits(['change'])
|
||||
const go_create = (provider: Provider) => {
|
||||
close()
|
||||
emit('change', provider, selectModelType.value)
|
||||
}
|
||||
defineExpose({ open, close })
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
import { modelType } from '@/enums/model'
|
||||
import { t } from '@/locales'
|
||||
export const modelTypeList = [
|
||||
{ text: t(modelType['LLM']), value: 'LLM' },
|
||||
{ text: t(modelType['EMBEDDING']), value: 'EMBEDDING' },
|
||||
{ text: t(modelType['RERANKER']), value: 'RERANKER' },
|
||||
{ text: t(modelType['STT']), value: 'STT' },
|
||||
{ text: t(modelType['TTS']), value: 'TTS' },
|
||||
{ text: t(modelType['IMAGE']), value: 'IMAGE' },
|
||||
{ text: t(modelType['TTI']), value: 'TTI' }
|
||||
]
|
||||
|
||||
|
||||
export const allObj = {
|
||||
icon: '',
|
||||
provider: '',
|
||||
name: t('views.model.modelType.allModel'),
|
||||
}
|
||||
|
|
@ -1,249 +0,0 @@
|
|||
<template>
|
||||
<div class="model-shared">
|
||||
<div class="shared-header">
|
||||
<span class="title">{{ t('views.system.shared.shared_resources') }}</span>
|
||||
<el-icon size="12">
|
||||
<rightOutlined></rightOutlined>
|
||||
</el-icon>
|
||||
<span class="sub-title">{{ t('views.model.title') }}</span>
|
||||
</div>
|
||||
<LayoutContainer>
|
||||
<template #left>
|
||||
<h4 class="p-16 mb-8 pb-0">{{ $t('views.model.provider') }}</h4>
|
||||
<ProviderComponent
|
||||
:data="provider_list"
|
||||
@click="clickListHandle"
|
||||
:loading="loading"
|
||||
:active="active_provider"
|
||||
/>
|
||||
</template>
|
||||
<ContentContainer
|
||||
:header="t('views.model.modelType.allModel')"
|
||||
v-loading="list_model_loading"
|
||||
>
|
||||
<template #search>
|
||||
<div class="flex">
|
||||
<div class="flex-between complex-search">
|
||||
<el-select
|
||||
class="complex-search__left"
|
||||
v-model="search_type"
|
||||
style="width: 120px"
|
||||
@change="search_type_change"
|
||||
>
|
||||
<el-option :label="$t('common.creator')" value="create_user" />
|
||||
|
||||
<el-option
|
||||
:label="$t('views.model.modelForm.model_type.label')"
|
||||
value="model_type"
|
||||
/>
|
||||
<el-option :label="$t('views.model.modelForm.modeName.label')" value="name" />
|
||||
</el-select>
|
||||
<el-input
|
||||
v-if="search_type === 'name'"
|
||||
v-model="model_search_form.name"
|
||||
@change="list_model"
|
||||
:placeholder="$t('common.searchBar.placeholder')"
|
||||
style="width: 220px"
|
||||
clearable
|
||||
/>
|
||||
<el-select
|
||||
v-else-if="search_type === 'create_user'"
|
||||
v-model="model_search_form.create_user"
|
||||
@change="list_model"
|
||||
clearable
|
||||
style="width: 220px"
|
||||
>
|
||||
<el-option
|
||||
v-for="u in user_options"
|
||||
:key="u.id"
|
||||
:value="u.id"
|
||||
:label="u.username"
|
||||
/>
|
||||
</el-select>
|
||||
|
||||
<el-select
|
||||
v-else-if="search_type === 'model_type'"
|
||||
v-model="model_search_form.model_type"
|
||||
clearable
|
||||
@change="list_model"
|
||||
style="width: 220px"
|
||||
>
|
||||
<template v-for="item in modelTypeList" :key="item.value">
|
||||
<el-option :label="item.text" :value="item.value" />
|
||||
</template>
|
||||
</el-select>
|
||||
</div>
|
||||
<el-button class="ml-16" type="primary" @click="openCreateModel(active_provider)">
|
||||
{{ $t('views.model.addModel') }}</el-button
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="model-list-height">
|
||||
<el-scrollbar>
|
||||
<el-row v-if="model_split_list.length > 0" :gutter="15" class="w-full">
|
||||
<template v-for="(row, index) in model_split_list" :key="index">
|
||||
<el-col
|
||||
:xs="24"
|
||||
:sm="12"
|
||||
:md="12"
|
||||
:lg="8"
|
||||
:xl="6"
|
||||
class="mb-16"
|
||||
v-for="(model, i) in row"
|
||||
:key="i"
|
||||
>
|
||||
<ModelCard
|
||||
@change="list_model"
|
||||
:updateModelById="updateModelById"
|
||||
:model="model"
|
||||
:provider_list="provider_list"
|
||||
>
|
||||
</ModelCard>
|
||||
</el-col>
|
||||
</template>
|
||||
</el-row>
|
||||
<el-empty :description="$t('common.noData')" v-else />
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</ContentContainer>
|
||||
|
||||
<CreateModelDialog
|
||||
ref="createModelRef"
|
||||
@submit="list_model"
|
||||
@change="openCreateModel($event)"
|
||||
></CreateModelDialog>
|
||||
|
||||
<SelectProviderDialog
|
||||
ref="selectProviderRef"
|
||||
@change="(provider, modelType) => openCreateModel(provider, modelType)"
|
||||
></SelectProviderDialog>
|
||||
</LayoutContainer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, computed } from 'vue'
|
||||
import ProviderApi from '@/api/model/provider'
|
||||
import type { Provider, Model } from '@/api/type/model'
|
||||
import ModelCard from '@/views/shared/model-shared/component/ModelCard.vue'
|
||||
import ProviderComponent from '@/views/shared/model-shared/component/Provider.vue'
|
||||
import { splitArray } from '@/utils/common'
|
||||
import { modelTypeList, allObj } from '@/views/shared/model-shared/component/data'
|
||||
import CreateModelDialog from '@/views/shared/model-shared/component/CreateModelDialog.vue'
|
||||
import iconMap from '@/components/app-icon/icons/common'
|
||||
import SelectProviderDialog from '@/views/shared/model-shared/component/SelectProviderDialog.vue'
|
||||
import useStore from '@/stores/modules-shared-system'
|
||||
import { t } from '@/locales'
|
||||
|
||||
const { model } = useStore()
|
||||
const rightOutlined = iconMap['right-outlined'].iconReader()
|
||||
|
||||
const commonList1 = ref()
|
||||
const commonList2 = ref()
|
||||
const loading = ref<boolean>(false)
|
||||
|
||||
const active_provider = ref<Provider>()
|
||||
const search_type = ref('name')
|
||||
const model_search_form = ref<{
|
||||
name: string
|
||||
create_user: string
|
||||
model_type: string
|
||||
}>({
|
||||
name: '',
|
||||
create_user: '',
|
||||
model_type: '',
|
||||
})
|
||||
const user_options = ref<any[]>([])
|
||||
const list_model_loading = ref<boolean>(false)
|
||||
const provider_list = ref<Array<Provider>>([])
|
||||
|
||||
const model_list = ref<Array<Model>>([])
|
||||
|
||||
const updateModelById = (model_id: string, model: Model) => {
|
||||
model_list.value
|
||||
.filter((m) => m.id == model_id)
|
||||
.forEach((m) => {
|
||||
m.status = model.status
|
||||
})
|
||||
}
|
||||
const model_split_list = computed(() => {
|
||||
return splitArray(model_list.value, 2)
|
||||
})
|
||||
const createModelRef = ref<InstanceType<typeof CreateModelDialog>>()
|
||||
const selectProviderRef = ref<InstanceType<typeof SelectProviderDialog>>()
|
||||
|
||||
const clickListHandle = (item: Provider) => {
|
||||
active_provider.value = item
|
||||
list_model()
|
||||
if (active_provider.value.provider === '') {
|
||||
commonList1.value.clearCurrent()
|
||||
commonList2.value.clearCurrent()
|
||||
}
|
||||
}
|
||||
|
||||
const openCreateModel = (provider?: Provider, model_type?: string) => {
|
||||
if (provider && provider.provider) {
|
||||
createModelRef.value?.open(provider, model_type)
|
||||
} else {
|
||||
selectProviderRef.value?.open()
|
||||
}
|
||||
}
|
||||
|
||||
const list_model = () => {
|
||||
const params = active_provider.value?.provider ? { provider: active_provider.value.provider } : {}
|
||||
model
|
||||
.asyncGetModel({ ...model_search_form.value, ...params }, list_model_loading)
|
||||
.then((ok: any) => {
|
||||
model_list.value = ok.data
|
||||
const v = model_list.value.map((m) => ({ id: m.user_id, username: m.username }))
|
||||
if (user_options.value.length === 0) {
|
||||
user_options.value = Array.from(new Map(v.map((item) => [item.id, item])).values())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const search_type_change = () => {
|
||||
model_search_form.value = { name: '', create_user: '', model_type: '' }
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
ProviderApi.getProvider(loading).then((ok) => {
|
||||
active_provider.value = allObj
|
||||
provider_list.value = [allObj, ...ok.data]
|
||||
|
||||
list_model()
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.model-shared {
|
||||
padding: 21px 14px 16px 24px;
|
||||
height: 100%;
|
||||
|
||||
.shared-header {
|
||||
color: #646a73;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 21px;
|
||||
|
||||
:deep(.el-icon i) {
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
.sub-title {
|
||||
color: #1f2329;
|
||||
}
|
||||
}
|
||||
|
||||
.h-full {
|
||||
border-radius: 8px;
|
||||
box-shadow: 0px 2px 4px 0px #1f23291f;
|
||||
background: #fff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,17 +1,19 @@
|
|||
<template>
|
||||
<ContentContainer>
|
||||
<template #header>
|
||||
<el-breadcrumb separator-icon="ArrowRight">
|
||||
<el-breadcrumb-item>{{ t('views.system.shared.shared_resources') }}</el-breadcrumb-item>
|
||||
<el-breadcrumb-item>
|
||||
<h5 class="ml-4 color-text-primary">{{ t('views.model.title') }}</h5>
|
||||
</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
</template>
|
||||
<el-card style="--el-card-padding: 0">
|
||||
<modelListContainer />
|
||||
</el-card>
|
||||
</ContentContainer>
|
||||
<div class="shared-model-manage">
|
||||
<ContentContainer>
|
||||
<template #header>
|
||||
<el-breadcrumb separator-icon="ArrowRight">
|
||||
<el-breadcrumb-item>{{ t('views.system.shared.shared_resources') }}</el-breadcrumb-item>
|
||||
<el-breadcrumb-item>
|
||||
<h5 class="ml-4 color-text-primary">{{ t('views.model.title') }}</h5>
|
||||
</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
</template>
|
||||
<el-card style="--el-card-padding: 0">
|
||||
<modelListContainer />
|
||||
</el-card>
|
||||
</ContentContainer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
|
@ -22,4 +24,15 @@ import modelListContainer from '@/views/model/index.vue'
|
|||
onMounted(() => {})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
<style lang="scss" scoped>
|
||||
.shared-model-manage {
|
||||
padding: 8px 12px 8px 4px;
|
||||
:deep(.model-list-height) {
|
||||
height: calc(var(--app-main-height) - 70px);
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
:deep(.provider-list) {
|
||||
height: calc(var(--app-main-height) - 70px);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Reference in New Issue