mirror of
https://github.com/1Panel-dev/MaxKB.git
synced 2025-12-26 10:12:51 +00:00
feat: model
This commit is contained in:
parent
ecc25796a6
commit
fd7fd36626
|
|
@ -1,28 +1,26 @@
|
|||
|
||||
import { Result } from '@/request/Result'
|
||||
import { get, post, del, put } from '@/request/index'
|
||||
import { type Ref } from 'vue'
|
||||
import type {
|
||||
ListModelRequest,
|
||||
Model,
|
||||
BaseModel,
|
||||
CreateModelRequest,
|
||||
EditModelRequest,
|
||||
} from '@/api/type/model'
|
||||
import type { FormField } from '@/components/dynamics-form/type'
|
||||
import type { KeyValue } from '../type/common'
|
||||
const prefix = '/model'
|
||||
const prefix_provider = '/provider'
|
||||
|
||||
const prefix = '/workspace'
|
||||
|
||||
/**
|
||||
* 获得模型列表
|
||||
* @params 参数 name, model_type, model_name
|
||||
*/
|
||||
const getModel: (
|
||||
wordspace_id: string,
|
||||
request?: ListModelRequest,
|
||||
loading?: Ref<boolean>,
|
||||
) => Promise<Result<Array<Model>>> = (data, loading) => {
|
||||
return get(`${prefix}`, data, loading)
|
||||
) => Promise<Result<Array<Model>>> = (wordspace_id, data, loading) => {
|
||||
return get(`${prefix}/${wordspace_id}/model`, data, loading)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -37,42 +35,6 @@ const getModelParamsForm: (
|
|||
) => Promise<Result<Array<FormField>>> = (model_id, loading) => {
|
||||
return get(`model/${model_id}/model_params_form`, {}, loading)
|
||||
}
|
||||
/**
|
||||
* 获取模型类型列表
|
||||
* @param provider 供应商
|
||||
* @param loading 加载器
|
||||
* @returns 模型类型列表
|
||||
*/
|
||||
const listModelType: (
|
||||
provider: string,
|
||||
loading?: Ref<boolean>,
|
||||
) => Promise<Result<Array<KeyValue<string, string>>>> = (provider, loading?: Ref<boolean>) => {
|
||||
return get(`${prefix_provider}/model_type_list`, { provider }, loading)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取基础模型列表
|
||||
* @param provider
|
||||
* @param model_type
|
||||
* @param loading
|
||||
* @returns
|
||||
*/
|
||||
const listBaseModel: (
|
||||
provider: string,
|
||||
model_type: string,
|
||||
loading?: Ref<boolean>,
|
||||
) => Promise<Result<Array<BaseModel>>> = (provider, model_type, loading) => {
|
||||
return get(`${prefix_provider}/model_list`, { provider, model_type }, loading)
|
||||
}
|
||||
|
||||
const listBaseModelParamsForm: (
|
||||
provider: string,
|
||||
model_type: string,
|
||||
model_name: string,
|
||||
loading?: Ref<boolean>,
|
||||
) => Promise<Result<Array<BaseModel>>> = (provider, model_type, model_name, loading) => {
|
||||
return get(`${prefix_provider}/model_params_form`, { provider, model_type, model_name }, loading)
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建模型
|
||||
|
|
@ -159,9 +121,6 @@ const deleteModel: (model_id: string, loading?: Ref<boolean>) => Promise<Result<
|
|||
}
|
||||
export default {
|
||||
getModel,
|
||||
listModelType,
|
||||
listBaseModel,
|
||||
listBaseModelParamsForm,
|
||||
createModel,
|
||||
updateModel,
|
||||
deleteModel,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import { Result } from '@/request/Result'
|
||||
import { get, post } from '@/request/index'
|
||||
import type { Ref } from 'vue'
|
||||
import type { Provider } from '@/api/type/model'
|
||||
import type { Provider, BaseModel } from '@/api/type/model'
|
||||
import type { FormField } from '@/components/dynamics-form/type'
|
||||
import type { KeyValue } from '../type/common'
|
||||
const prefix_provider = '/provider'
|
||||
/**
|
||||
* 获得供应商列表
|
||||
|
|
@ -37,8 +38,48 @@ const getModelCreateForm: (
|
|||
) => Promise<Result<Array<FormField>>> = (provider, model_type, model_name, loading) => {
|
||||
return get(`${prefix_provider}/model_form`, { provider, model_type, model_name }, loading)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模型类型列表
|
||||
* @param provider 供应商
|
||||
* @param loading 加载器
|
||||
* @returns 模型类型列表
|
||||
*/
|
||||
const listModelType: (
|
||||
provider: string,
|
||||
loading?: Ref<boolean>,
|
||||
) => Promise<Result<Array<KeyValue<string, string>>>> = (provider, loading?: Ref<boolean>) => {
|
||||
return get(`${prefix_provider}/model_type_list`, { provider }, loading)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取基础模型列表
|
||||
* @param provider
|
||||
* @param model_type
|
||||
* @param loading
|
||||
* @returns
|
||||
*/
|
||||
const listBaseModel: (
|
||||
provider: string,
|
||||
model_type: string,
|
||||
loading?: Ref<boolean>,
|
||||
) => Promise<Result<Array<BaseModel>>> = (provider, model_type, loading) => {
|
||||
return get(`${prefix_provider}/model_list`, { provider, model_type }, loading)
|
||||
}
|
||||
|
||||
const listBaseModelParamsForm: (
|
||||
provider: string,
|
||||
model_type: string,
|
||||
model_name: string,
|
||||
loading?: Ref<boolean>,
|
||||
) => Promise<Result<Array<BaseModel>>> = (provider, model_type, model_name, loading) => {
|
||||
return get(`${prefix_provider}/model_params_form`, { provider, model_type, model_name }, loading)
|
||||
}
|
||||
export default {
|
||||
getProvider,
|
||||
getModelCreateForm,
|
||||
getProviderByModelType,
|
||||
listModelType,
|
||||
listBaseModel,
|
||||
listBaseModelParamsForm,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_332_3845)">
|
||||
<path opacity="0.5" d="M11.5903 10.7326C11.5903 8.64041 13.2864 6.9444 15.3785 6.9444C17.4706 6.9444 19.1667 8.64042 19.1667 10.7326V15.3784C19.1667 17.4705 17.4706 19.1666 15.3785 19.1666C13.2864 19.1666 11.5903 17.4705 11.5903 15.3784V10.7326Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.6212 0.833374H14.6211V2.36113H13.1059V0.833374H2.83347C1.72892 0.833374 0.833495 1.72878 0.833474 2.83333L0.833313 11.1665C0.833228 15.5848 4.41497 19.1666 8.83331 19.1666H15.1666C15.5076 19.1666 15.8387 19.1239 16.1547 19.0436C15.2624 18.7368 14.6212 17.8902 14.6212 16.8937V0.833374ZM4.51881 6.35876C4.51881 5.89468 4.89501 5.51848 5.35909 5.51848H10.3457C10.8098 5.51848 11.186 5.89468 11.186 6.35876C11.186 6.82283 10.8098 7.19904 10.3457 7.19904H5.35909C4.89501 7.19904 4.51881 6.82283 4.51881 6.35876ZM5.35909 9.4398C4.89501 9.4398 4.51881 9.816 4.51881 10.2801C4.51881 10.7441 4.89501 11.1204 5.35909 11.1204H10.3457C10.8098 11.1204 11.186 10.7441 11.186 10.2801C11.186 9.816 10.8098 9.4398 10.3457 9.4398H5.35909Z" fill="white"/>
|
||||
<ellipse cx="13.1058" cy="2.36108" rx="1.51527" ry="1.52776" fill="white"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_332_3845">
|
||||
<rect width="20" height="20" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
|
|
@ -0,0 +1,110 @@
|
|||
<template>
|
||||
<el-card shadow="hover" class="card-box" @mouseenter="cardEnter()" @mouseleave="cardLeave()">
|
||||
<div class="card-header">
|
||||
<slot name="header">
|
||||
<div class="title flex align-center" :class="$slots.subTitle ? 'mt-4' : ''">
|
||||
<slot name="icon">
|
||||
<el-avatar v-if="showIcon" class="mr-12 avatar-blue" shape="square" :size="32">
|
||||
<img src="@/assets/icon_document.svg" style="width: 58%" alt="" />
|
||||
</el-avatar>
|
||||
</slot>
|
||||
<div style="width: 90%">
|
||||
<slot name="title">
|
||||
<auto-tooltip :content="title" style="width: 65%; height: 22px">
|
||||
{{ title }}
|
||||
</auto-tooltip>
|
||||
</slot>
|
||||
<slot name="subTitle"> </slot>
|
||||
</div>
|
||||
</div>
|
||||
</slot>
|
||||
</div>
|
||||
<div class="description break-all mt-12">
|
||||
<slot>
|
||||
<div class="content">
|
||||
{{ description }}
|
||||
</div>
|
||||
</slot>
|
||||
</div>
|
||||
<div @mouseenter="subHoveredEnter">
|
||||
<slot name="mouseEnter" v-if="$slots.mouseEnter && show" />
|
||||
</div>
|
||||
<div class="card-footer" v-if="$slots.footer">
|
||||
<slot name="footer" />
|
||||
</div>
|
||||
</el-card>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, useSlots } from 'vue'
|
||||
import { t } from '@/locales'
|
||||
defineOptions({ name: 'CardBox' })
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
title?: string
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
description?: string
|
||||
/**
|
||||
* 是否展示icon
|
||||
*/
|
||||
showIcon?: boolean
|
||||
}>(),
|
||||
{ title: t('common.title'), description: '', showIcon: true, border: true },
|
||||
)
|
||||
|
||||
const show = ref(false)
|
||||
// card上面存在dropdown菜单
|
||||
const subHovered = ref(false)
|
||||
function cardEnter() {
|
||||
show.value = true
|
||||
subHovered.value = false
|
||||
}
|
||||
|
||||
function cardLeave() {
|
||||
show.value = subHovered.value
|
||||
}
|
||||
|
||||
function subHoveredEnter() {
|
||||
subHovered.value = true
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.card-box {
|
||||
font-size: 14px;
|
||||
position: relative;
|
||||
min-height: var(--card-min-height);
|
||||
min-width: var(--card-min-width);
|
||||
border-radius: 8px;
|
||||
.card-header {
|
||||
margin-top: -10px;
|
||||
}
|
||||
.description {
|
||||
color: var(--app-text-color-secondary);
|
||||
line-height: 22px;
|
||||
font-weight: 400;
|
||||
.content {
|
||||
display: -webkit-box;
|
||||
height: var(--app-card-box-description-height, 40px);
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
position: absolute;
|
||||
bottom: 8px;
|
||||
left: 0;
|
||||
min-height: 30px;
|
||||
color: var(--app-text-color-secondary);
|
||||
font-weight: 400;
|
||||
padding: 0 16px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -6,6 +6,7 @@ import dynamicsForm from './dynamics-form'
|
|||
import AppIcon from './app-icon/AppIcon.vue'
|
||||
import LayoutContainer from './layout-container/index.vue'
|
||||
import ContentContainer from './layout-container/ContentContainer.vue'
|
||||
import CardBox from './card-box/index.vue'
|
||||
export default {
|
||||
install(app: App) {
|
||||
app.component('LogoFull', LogoFull)
|
||||
|
|
@ -15,5 +16,6 @@ export default {
|
|||
app.component('AppIcon', AppIcon)
|
||||
app.component('LayoutContainer', LayoutContainer)
|
||||
app.component('ContentContainer', ContentContainer)
|
||||
app.component('CardBox', CardBox)
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ const showBack = computed(() => {
|
|||
.content-container__main {
|
||||
// background-color: var(--app-view-bg-color);
|
||||
box-sizing: border-box;
|
||||
min-width: 847px;
|
||||
min-width: 447px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div class="layout-container flex h-full">
|
||||
<div class="layout-container__left">
|
||||
<div class="layout-container__left border-r">
|
||||
<slot name="left"></slot>
|
||||
</div>
|
||||
<div class="layout-container__right">
|
||||
|
|
@ -30,7 +30,6 @@ const showBack = computed(() => {
|
|||
transition: width 0.28s;
|
||||
width: var(--sidebar-width);
|
||||
min-width: var(--sidebar-width);
|
||||
background-color: var(--sidebar-bg-color);
|
||||
}
|
||||
&__right {
|
||||
width: calc(100% - var(--sidebar-width));
|
||||
|
|
|
|||
|
|
@ -1,64 +1,50 @@
|
|||
<template>
|
||||
<card-box :title="model.name" shadow="hover" class="model-card">
|
||||
<template #header>
|
||||
<div class="flex">
|
||||
<span style="height: 32px; width: 32px" :innerHTML="icon" class="mr-12"></span>
|
||||
<div style="width: calc(100% - 32px - 4px - var(--app-base-px))">
|
||||
<div class="flex" style="height: 22px">
|
||||
<auto-tooltip :content="model.name" style="max-width: 40%">
|
||||
{{ model.name }}
|
||||
</auto-tooltip>
|
||||
<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.form.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>
|
||||
<div class="mt-4">
|
||||
<el-tag v-if="model.permission_type === 'PRIVATE'" type="danger" class="danger-tag">{{
|
||||
$t('common.private')
|
||||
}}</el-tag>
|
||||
<el-tag v-else type="info" class="info-tag"> {{ $t('common.public') }}</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
<template #icon>
|
||||
<span style="height: 32px; width: 32px" :innerHTML="icon" class="mr-12"></span>
|
||||
</template>
|
||||
<template #title>
|
||||
<div class="flex" style="height: 22px">
|
||||
<auto-tooltip :content="model.name" style="max-width: 40%">
|
||||
{{ model.name }}
|
||||
</auto-tooltip>
|
||||
<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.form.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>
|
||||
|
||||
<div class="mt-16">
|
||||
<ul>
|
||||
<li class="flex mt-16">
|
||||
<el-text type="info">{{
|
||||
$t('views.model.modelForm.form.model_type.label')
|
||||
}}</el-text>
|
||||
<span class="ellipsis ml-16">
|
||||
{{ $t(modelType[model.model_type as keyof typeof modelType]) }}</span
|
||||
>
|
||||
</li>
|
||||
<li class="flex mt-12">
|
||||
<el-text type="info">{{
|
||||
$t('views.model.modelForm.form.base_model.label')
|
||||
}}</el-text>
|
||||
<span class="ellipsis-1 ml-16" style="height: 20px; width: 70%">
|
||||
{{ model.model_name }}</span
|
||||
>
|
||||
</li>
|
||||
<li class="flex mt-12">
|
||||
<el-text type="info">{{ $t('common.creator') }}</el-text>
|
||||
<span class="ellipsis-1 ml-16" style="height: 20px; width: 70%">
|
||||
{{ model.username }}</span
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<template #subTitle>
|
||||
<el-text class="color-secondary" size="small">
|
||||
<auto-tooltip :content="model.username">
|
||||
{{ $t('common.creator') }}: {{ model.username }}
|
||||
</auto-tooltip>
|
||||
</el-text>
|
||||
</template>
|
||||
<ul>
|
||||
<li class="flex">
|
||||
<el-text type="info">{{ $t('views.model.modelForm.form.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">{{ $t('views.model.modelForm.form.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" /> -->
|
||||
|
|
@ -170,8 +156,8 @@ const deleteModel = () => {
|
|||
`${t('views.model.delete.confirmMessage')}${props.model.name} ?`,
|
||||
{
|
||||
confirmButtonText: t('common.confirm'),
|
||||
confirmButtonClass: 'danger'
|
||||
}
|
||||
confirmButtonClass: 'danger',
|
||||
},
|
||||
)
|
||||
.then(() => {
|
||||
ModelApi.deleteModel(props.model.id).then(() => {
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@
|
|||
|
||||
<div class="model-list-height">
|
||||
<el-scrollbar>
|
||||
<div class="p-24 pt-0">
|
||||
<div>
|
||||
<el-row v-if="model_split_list.length > 0" :gutter="15">
|
||||
<template v-for="(row, index) in model_split_list" :key="index">
|
||||
<el-col
|
||||
|
|
@ -262,13 +262,15 @@ const openCreateModel = (provider?: Provider, model_type?: string) => {
|
|||
|
||||
const list_model = () => {
|
||||
const params = active_provider.value?.provider ? { provider: active_provider.value.provider } : {}
|
||||
ModelApi.getModel({ ...model_search_form.value, ...params }, list_model_loading).then((ok) => {
|
||||
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())
|
||||
}
|
||||
})
|
||||
ModelApi.getModel('default', { ...model_search_form.value, ...params }, list_model_loading).then(
|
||||
(ok) => {
|
||||
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 = () => {
|
||||
|
|
@ -324,7 +326,7 @@ onMounted(() => {
|
|||
color: var(--el-color-primary);
|
||||
font-weight: 500;
|
||||
}
|
||||
.template-collapse {
|
||||
.model-collapse {
|
||||
border-top: none !important;
|
||||
border-bottom: none !important;
|
||||
:deep(.el-collapse-item__header) {
|
||||
|
|
@ -332,6 +334,7 @@ onMounted(() => {
|
|||
padding-left: 16px;
|
||||
font-size: 14px;
|
||||
height: 40px;
|
||||
background: none;
|
||||
&:hover {
|
||||
background: var(--app-text-color-light-1);
|
||||
border-radius: 4px;
|
||||
|
|
|
|||
Loading…
Reference in New Issue