feat: model

This commit is contained in:
wangdan-fit2cloud 2025-05-07 15:58:42 +08:00
parent ecc25796a6
commit fd7fd36626
9 changed files with 230 additions and 118 deletions

View File

@ -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,

View File

@ -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,
}

View File

@ -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

View File

@ -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)
// carddropdown
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>

View File

@ -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)
},
}

View File

@ -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>

View File

@ -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));

View File

@ -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(() => {

View File

@ -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;