mirror of
https://github.com/memohai/Memoh.git
synced 2026-04-27 07:16:19 +09:00
feat: add setting
This commit is contained in:
@@ -63,3 +63,18 @@ export interface ChatModel extends BaseModel {
|
||||
}
|
||||
|
||||
export type Model = EmbeddingModel | ChatModel
|
||||
|
||||
|
||||
// 表格当中model的类型
|
||||
export interface ModelTable {
|
||||
apiKey: string,
|
||||
baseUrl: string,
|
||||
clientType: 'OpenAI' | 'Anthropic' | 'Google',
|
||||
modelId: string,
|
||||
name: string,
|
||||
type: 'chat' | 'embedding',
|
||||
id: string,
|
||||
defaultChatModel: boolean,
|
||||
defaultEmbeddingModel: boolean,
|
||||
defaultSummaryModel: boolean
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user