feat: add knowledge base settings popup

This commit is contained in:
kangfenmao 2025-02-03 09:22:59 +08:00
parent d33714ad68
commit 44991edfbd
8 changed files with 166 additions and 38 deletions

View File

@ -629,7 +629,8 @@
"source": "Source",
"chunk_size": "Chunk Size",
"chunk_overlap": "Chunk Overlap",
"not_set": "Not Set"
"not_set": "Not Set",
"settings": "Knowledge Base Settings"
},
"models": {
"pinned": "Pinned",

View File

@ -613,7 +613,8 @@
"source": "ソース",
"chunk_size": "チャンクサイズ",
"chunk_overlap": "チャンクの重なり",
"not_set": "未設定"
"not_set": "未設定",
"settings": "ナレッジベース設定"
},
"models": {
"pinned": "固定済み",

View File

@ -626,7 +626,8 @@
"source": "Источник",
"chunk_size": "Размер фрагмента",
"chunk_overlap": "Перекрытие фрагмента",
"not_set": "Не установлено"
"not_set": "Не установлено",
"settings": "Настройки базы знаний"
},
"models": {
"pinned": "Закреплено",

View File

@ -615,7 +615,8 @@
"source": "来源",
"chunk_size": "分段大小",
"chunk_overlap": "重叠大小",
"not_set": "未设置"
"not_set": "未设置",
"settings": "知识库设置"
},
"models": {
"pinned": "已固定",

View File

@ -614,7 +614,8 @@
"source": "來源",
"chunk_size": "分段大小",
"chunk_overlap": "重疊大小",
"not_set": "未設置"
"not_set": "未設置",
"settings": "知識庫設定"
},
"models": {
"pinned": "已固定",

View File

@ -359,13 +359,7 @@ const KnowledgeContent: FC<KnowledgeContentProps> = ({ selectedBase }) => {
<Tag color="blue">{base.model.name}</Tag>
<Tag color="cyan">{t('models.dimensions', { dimensions: base.dimensions || 0 })}</Tag>
{providerName && <Tag color="purple">{providerName}</Tag>}
</ModelInfo>
<ModelInfo>
<label htmlFor="model-info">{t('knowledge.chunk_size')}</label>
<Tag color="green">{base.chunkSize || t('knowledge.not_set')}</Tag>
<label htmlFor="model-info">{t('knowledge.chunk_overlap')}</label>
<Tag color="orange">{base.chunkOverlap || t('knowledge.not_set')}</Tag>
{/* <Button icon={<SettingOutlined />} onClick={() => KnowledgeSettingsPopup.show({ base })} size="small" /> */}
</ModelInfo>
<IndexSection>

View File

@ -6,7 +6,7 @@ import AiProvider from '@renderer/providers/AiProvider'
import { getKnowledgeBaseParams } from '@renderer/services/KnowledgeService'
import { getModelUniqId } from '@renderer/services/ModelService'
import { Model } from '@renderer/types'
import { Form, Input, InputNumber, Modal, Select } from 'antd'
import { Form, Input, Modal, Select } from 'antd'
import { find, sortBy } from 'lodash'
import { nanoid } from 'nanoid'
import { useState } from 'react'
@ -19,8 +19,6 @@ interface ShowParams {
interface FormData {
name: string
model: string
chunkSize?: number
chunkOverlap?: number
}
interface Props extends ShowParams {
@ -83,8 +81,6 @@ const PopupContainer: React.FC<Props> = ({ title, resolve }) => {
name: values.name,
model: selectedModel,
dimensions,
chunkSize: values.chunkSize,
chunkOverlap: values.chunkOverlap,
items: [],
created_at: Date.now(),
updated_at: Date.now(),
@ -135,27 +131,6 @@ const PopupContainer: React.FC<Props> = ({ title, resolve }) => {
rules={[{ required: true, message: t('message.error.enter.model') }]}>
<Select style={{ width: '100%' }} options={selectOptions} placeholder={t('settings.models.empty')} />
</Form.Item>
<Form.Item name="chunkSize" label={t('knowledge.chunk_size')}>
<InputNumber style={{ width: '100%' }} min={1} />
</Form.Item>
<Form.Item
name="chunkOverlap"
label={t('knowledge.chunk_overlap')}
rules={[
({ getFieldValue }) => ({
validator(_, value) {
if (!value || getFieldValue('chunkSize') > value) {
return Promise.resolve()
}
return Promise.reject(new Error(t('message.error.chunk_overlap_too_large')))
}
})
]}
dependencies={['chunkSize']}>
<InputNumber style={{ width: '100%' }} min={0} />
</Form.Item>
</Form>
</Modal>
)

View File

@ -0,0 +1,154 @@
import { TopView } from '@renderer/components/TopView'
import { isEmbeddingModel } from '@renderer/config/models'
import { useKnowledge } from '@renderer/hooks/useKnowledge'
import { useProviders } from '@renderer/hooks/useProvider'
import { getModelUniqId } from '@renderer/services/ModelService'
import { KnowledgeBase } from '@renderer/types'
import { Form, Input, InputNumber, Modal, Select } from 'antd'
import { sortBy } from 'lodash'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
interface ShowParams {
base: KnowledgeBase
}
interface FormData {
name: string
model: string
chunkSize?: number
chunkOverlap?: number
}
interface Props extends ShowParams {
resolve: (data: any) => void
}
const PopupContainer: React.FC<Props> = ({ base: _base, resolve }) => {
const [open, setOpen] = useState(true)
const [form] = Form.useForm<FormData>()
const { t } = useTranslation()
const { providers } = useProviders()
const { base, updateKnowledgeBase } = useKnowledge(_base.id)
if (!base) {
resolve(null)
return null
}
const selectOptions = providers
.filter((p) => p.models.length > 0)
.map((p) => ({
label: p.isSystem ? t(`provider.${p.id}`) : p.name,
title: p.name,
options: sortBy(p.models, 'name')
.filter((model) => isEmbeddingModel(model))
.map((m) => ({
label: m.name,
value: getModelUniqId(m)
}))
}))
.filter((group) => group.options.length > 0)
const onOk = async () => {
try {
const values = await form.validateFields()
const newBase = {
...base,
name: values.name,
chunkSize: values.chunkSize,
chunkOverlap: values.chunkOverlap
}
updateKnowledgeBase(newBase)
setOpen(false)
resolve(newBase)
} catch (error) {
console.error('Validation failed:', error)
}
}
const onCancel = () => {
setOpen(false)
}
const onClose = () => {
resolve(null)
}
KnowledgeSettingsPopup.hide = onCancel
return (
<Modal
title={t('knowledge.settings')}
open={open}
onOk={onOk}
onCancel={onCancel}
afterClose={onClose}
destroyOnClose
centered>
<Form form={form} layout="vertical">
<Form.Item
name="name"
label={t('common.name')}
initialValue={base.name}
rules={[{ required: true, message: t('message.error.enter.name') }]}>
<Input placeholder={t('common.name')} />
</Form.Item>
<Form.Item
name="model"
label={t('models.embedding_model')}
initialValue={getModelUniqId(base.model)}
tooltip={{ title: t('models.embedding_model_tooltip'), placement: 'right' }}
rules={[{ required: true, message: t('message.error.enter.model') }]}>
<Select style={{ width: '100%' }} options={selectOptions} placeholder={t('settings.models.empty')} disabled />
</Form.Item>
<Form.Item name="chunkSize" label={t('knowledge.chunk_size')}>
<InputNumber style={{ width: '100%' }} min={1} defaultValue={base.chunkSize} />
</Form.Item>
<Form.Item
name="chunkOverlap"
label={t('knowledge.chunk_overlap')}
initialValue={base.chunkOverlap}
rules={[
({ getFieldValue }) => ({
validator(_, value) {
if (!value || getFieldValue('chunkSize') > value) {
return Promise.resolve()
}
return Promise.reject(new Error(t('message.error.chunk_overlap_too_large')))
}
})
]}
dependencies={['chunkSize']}>
<InputNumber style={{ width: '100%' }} min={0} />
</Form.Item>
</Form>
</Modal>
)
}
const TopViewKey = 'KnowledgeSettingsPopup'
export default class KnowledgeSettingsPopup {
static hide() {
TopView.hide(TopViewKey)
}
static show(props: ShowParams) {
return new Promise<any>((resolve) => {
TopView.show(
<PopupContainer
{...props}
resolve={(v) => {
resolve(v)
TopView.hide(TopViewKey)
}}
/>,
TopViewKey
)
})
}
}