feat: add setting

This commit is contained in:
Quicy
2026-01-21 12:07:38 +08:00
parent f1711c43f7
commit 9980fed90b
3 changed files with 301 additions and 50 deletions
+16 -27
View File
@@ -16,21 +16,9 @@ import {
import DataTable from '@/components/DataTable/index.vue'
import request from '@/utils/request'
import { type ColumnDef } from '@tanstack/vue-table'
import {type ModelTable as ModelType} from '@memoh/shared'
interface ModelType {
apiKey: string,
baseUrl: string,
clientType: 'OpenAI' | 'Anthropic' | 'Google',
modelId: string,
name: string,
type: 'chat' | 'embedding',
id: string,
defaultChatModel: boolean,
defaultEmbeddingModel: boolean,
defaultSummaryModel: boolean
}
const openDialogModel = ref(false)
const editModelInfo = ref<ModelType & { id: string } | null>(null)
provide('open', openDialogModel)
@@ -85,22 +73,23 @@ const renderCheckDefault = () => {
accessorKey: `${modelSetting.key}`,
header: () => h('div', { class: 'text-left' }, modelSetting.title),
cell({ row }) {
return h(Checkbox, {
state: row.original[modelSetting.type as 'defaultChatModel' | 'defaultSummaryModel' | 'defaultEmbeddingModel'],
disabled: row.original[modelSetting.type as 'defaultChatModel' | 'defaultSummaryModel' | 'defaultEmbeddingModel'] ? true : false,
const type = modelSetting.type as 'defaultChatModel' | 'defaultSummaryModel' | 'defaultEmbeddingModel'
return row.original.type === modelSetting.key ? h(Checkbox, {
state: row.original[type],
disabled: row.original[type] ? true : false,
'onUpdate:modelValue'(val) {
row.original[modelSetting.type as 'defaultChatModel' | 'defaultSummaryModel' | 'defaultEmbeddingModel'] = val as boolean
row.original[type] = val as boolean
setDefaultModel({
id: row.original.id,
type: modelSetting.key
})
}
})
}) : h('div')
}
} as ColumnDef<ModelType>
))]
}
const checkDefaultModel=ref(renderCheckDefault())
const checkDefaultModel = ref(renderCheckDefault())
const columns: ComputedRef<ColumnDef<ModelType>[]> = computed(() => [
{
@@ -131,7 +120,7 @@ const columns: ComputedRef<ColumnDef<ModelType>[]> = computed(() => [
header: () => h('div', { class: 'text-left' }, 'Type'),
},
...checkDefaultModel.value
,
{
@@ -171,13 +160,13 @@ const { data: modelData } = useQuery({
}
}))
return fetchModeData
}
})
watch(modelData, () => {
checkDefaultModel.value=renderCheckDefault()
checkDefaultModel.value = renderCheckDefault()
})
@@ -202,7 +191,7 @@ const pagination = computed(() => {
:data="displayFormat"
/>
</div>
<div class="flex flex-col mt-4">
<!-- <div class="flex flex-col mt-4">
<Pagination
v-slot="{ page }"
:total="pagination.value?.total ?? 0"
@@ -233,9 +222,9 @@ const pagination = computed(() => {
</PaginationEllipsis>
</template>
<PaginationNext />
</PaginationContent>
</Pagination>
</div>
<PaginationNext />
</PaginationContent>
</Pagination>
</div> -->
</div>
</template>
+270 -23
View File
@@ -2,45 +2,292 @@
<section>
<section class="max-w-187 m-auto">
<Card>
<CardHeader>
<CardTitle class="text-2xl font-semibold tracking-tight">
Settings
</CardTitle>
<CardDescription>
Model Settings
</CardDescription>
</CardHeader>
<!-- <CardHeader>
<CardTitle>
Setting
</CardTitle>
</CardHeader> -->
<form @submit="changeSetting">
<CardHeader>
<CardTitle class="text-2xl font-semibold tracking-tight">
Settings
</CardTitle>
<CardDescription>
Model Settings
</CardDescription>
</CardHeader>
<CardContent>
<FormField
v-slot="{ componentField }"
name="defaultChatModel"
>
<FormItem>
<FormLabel class="mb-2">
Chat Model
</FormLabel>
<FormControl>
<Select v-bind="componentField">
<SelectTrigger class="w-full">
<SelectValue placeholder="请选择Client Type" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem
v-for="(modelItem, index) in modelType.chat"
:key="modelItem.id"
:value="(modelItem.model.apiKey + index)"
>
{{ modelItem.model.name }}
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</FormControl>
<blockquote class="h-5">
<FormMessage />
</blockquote>
</FormItem>
</FormField>
<FormField
v-slot="{ componentField }"
name="defaultEmbeddingModel"
>
<FormItem>
<FormLabel class="mb-2">
Embedding Model
</FormLabel>
<FormControl>
<Select v-bind="componentField">
<SelectTrigger class="w-full">
<SelectValue placeholder="请选择Embedding Type" />
</SelectTrigger>
<SelectContent v-if="modelType.embedding.length > 0">
<SelectGroup>
<SelectItem
v-for="(modelItem, index) in modelType.embedding"
:key="modelItem.id"
:value="(modelItem.model.apiKey + index)"
>
{{ modelItem.model.name }}
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<blockquote class="h-5">
<FormMessage />
</blockquote>
</formcontrol>
</FormItem>
</FormField>
<FormField
v-slot="{ componentField }"
name="defaultSummaryModel"
>
<FormItem>
<FormLabel class="mb-2">
<!-- defaultSummaryModel -->
Summary Model
</FormLabel>
<FormControl>
<Select v-bind="componentField">
<SelectTrigger class="w-full">
<SelectValue placeholder="请选择Summary Type" />
</SelectTrigger>
<SelectContent v-if="modelType.embedding.length > 0">
<SelectGroup>
<SelectItem
v-for="(modelItem, index) in modelType.summary"
:key="modelItem.id"
:value="(modelItem.model.apiKey + index)"
>
{{ modelItem.model.name }}
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</FormControl>
<blockquote class="h-5">
<FormMessage />
</blockquote>
</FormItem>
</FormField>
<FormField
v-slot="{ componentField }"
name="language"
>
<FormItem>
<FormLabel class="mb-2">
Language
</FormLabel>
<FormControl>
<Select v-bind="componentField">
<SelectTrigger class="w-full">
<SelectValue placeholder="请选择Language" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="ch">
中文
</SelectItem>
<SelectItem value="en">
English
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</FormControl>
<blockquote class="h-5">
<FormMessage />
</blockquote>
</FormItem>
</FormField>
<FormField
v-slot="{ componentField }"
name="maxContextLoadTime"
>
<FormItem>
<FormLabel class="mb-2">
<!-- defaultSummaryModel -->
Timeout
</FormLabel>
<FormControl>
<Input
placeholder="请输入超时时间"
v-bind="componentField"
/>
</FormControl>
<blockquote class="h-5">
<FormMessage />
</blockquote>
</FormItem>
</FormField>
</CardContent>
<CardFooter class="flex">
<Button
class="ml-auto"
type="submit"
:disabled="diabeld"
>
Change
</Button>
</CardFooter>
</form>
</Card>
</section>
</section>
</template>
<script setup lang="ts">
import { useQuery } from '@pinia/colada'
import { useMutation, useQuery, useQueryCache } from '@pinia/colada'
import request from '@/utils/request'
import { watch } from 'vue'
import { watch, reactive, computed } from 'vue'
import { type ModelTable } from '@memoh/shared'
import { toTypedSchema } from '@vee-validate/zod'
import z from 'zod'
import { useForm, useFormValues } from 'vee-validate'
import {
Input,
Card,
CardDescription,
CardHeader,
CardTitle
CardTitle,
CardContent,
FormField,
FormItem,
FormLabel,
FormControl,
Button,
FormMessage,
Select,
SelectTrigger,
SelectContent,
SelectValue,
SelectGroup,
SelectItem,
CardFooter
} from '@memoh/ui'
type ModelList = {
id: ModelTable['id'],
model: Omit<ModelTable, 'id' | 'defaultChatModel' | 'defaultEmbeddingModel' | 'defaultSummaryModel'>
};
const modelType = reactive<{
chat: ModelList[],
embedding: ModelList[],
summary: ModelList[]
}>({
chat: [],
embedding: [],
summary: []
})
const { data: settingData } = useQuery({
key: ['Setting'],
query: () => request({
url: '/settings/',
method: 'get'
})
query: async () => {
const modelData = await request({
url: '/model/',
method: 'get'
})
for (const modelItems of modelData.data.items) {
let type = modelItems.model.type as keyof typeof modelType
modelType[type].push(modelItems)
}
return await request({
url: '/settings/',
method: 'get'
})
}
})
watch(settingData, () => {
console.log(settingData.value?.data)
const formSchema = toTypedSchema(z.object({
defaultChatModel: z.any(),
defaultEmbeddingModel: z.any(),
defaultSummaryModel: z.any(),
maxContextLoadTime: z.coerce.number().min(1500),
language: z.literal(['ch', 'en'])
}))
const form = useForm({
validationSchema: formSchema
})
const currentSetting = useFormValues()
const diabeld = computed(() => {
return Object.keys(currentSetting.value).every((property) => {
const curKey = currentSetting.value[property]
const cacheKey = settingData.value?.data?.data?.[property]
if (curKey === cacheKey || Number(curKey) === Number(cacheKey)) {
return true
}
})
})
watch(settingData, () => {
form.setValues({
...(settingData.value?.data.data ?? {})
})
}, {
immediate: true
})
const cacheQuery=useQueryCache()
const { mutate: fetchSetting } = useMutation({
mutation: (data:typeof currentSetting.value) => request({
url: '/settings/',
data
}),
onSettled: () => {
cacheQuery.invalidateQueries({
key:['Setting']
})
}
})
const changeSetting = form.handleSubmit(async (value) => {
try {
await fetchSetting(value)
} catch {
return
}
})
</script>