feat: add knowledge base settings popup
This commit is contained in:
parent
d33714ad68
commit
44991edfbd
@ -629,7 +629,8 @@
|
|||||||
"source": "Source",
|
"source": "Source",
|
||||||
"chunk_size": "Chunk Size",
|
"chunk_size": "Chunk Size",
|
||||||
"chunk_overlap": "Chunk Overlap",
|
"chunk_overlap": "Chunk Overlap",
|
||||||
"not_set": "Not Set"
|
"not_set": "Not Set",
|
||||||
|
"settings": "Knowledge Base Settings"
|
||||||
},
|
},
|
||||||
"models": {
|
"models": {
|
||||||
"pinned": "Pinned",
|
"pinned": "Pinned",
|
||||||
|
|||||||
@ -613,7 +613,8 @@
|
|||||||
"source": "ソース",
|
"source": "ソース",
|
||||||
"chunk_size": "チャンクサイズ",
|
"chunk_size": "チャンクサイズ",
|
||||||
"chunk_overlap": "チャンクの重なり",
|
"chunk_overlap": "チャンクの重なり",
|
||||||
"not_set": "未設定"
|
"not_set": "未設定",
|
||||||
|
"settings": "ナレッジベース設定"
|
||||||
},
|
},
|
||||||
"models": {
|
"models": {
|
||||||
"pinned": "固定済み",
|
"pinned": "固定済み",
|
||||||
|
|||||||
@ -626,7 +626,8 @@
|
|||||||
"source": "Источник",
|
"source": "Источник",
|
||||||
"chunk_size": "Размер фрагмента",
|
"chunk_size": "Размер фрагмента",
|
||||||
"chunk_overlap": "Перекрытие фрагмента",
|
"chunk_overlap": "Перекрытие фрагмента",
|
||||||
"not_set": "Не установлено"
|
"not_set": "Не установлено",
|
||||||
|
"settings": "Настройки базы знаний"
|
||||||
},
|
},
|
||||||
"models": {
|
"models": {
|
||||||
"pinned": "Закреплено",
|
"pinned": "Закреплено",
|
||||||
|
|||||||
@ -615,7 +615,8 @@
|
|||||||
"source": "来源",
|
"source": "来源",
|
||||||
"chunk_size": "分段大小",
|
"chunk_size": "分段大小",
|
||||||
"chunk_overlap": "重叠大小",
|
"chunk_overlap": "重叠大小",
|
||||||
"not_set": "未设置"
|
"not_set": "未设置",
|
||||||
|
"settings": "知识库设置"
|
||||||
},
|
},
|
||||||
"models": {
|
"models": {
|
||||||
"pinned": "已固定",
|
"pinned": "已固定",
|
||||||
|
|||||||
@ -614,7 +614,8 @@
|
|||||||
"source": "來源",
|
"source": "來源",
|
||||||
"chunk_size": "分段大小",
|
"chunk_size": "分段大小",
|
||||||
"chunk_overlap": "重疊大小",
|
"chunk_overlap": "重疊大小",
|
||||||
"not_set": "未設置"
|
"not_set": "未設置",
|
||||||
|
"settings": "知識庫設定"
|
||||||
},
|
},
|
||||||
"models": {
|
"models": {
|
||||||
"pinned": "已固定",
|
"pinned": "已固定",
|
||||||
|
|||||||
@ -359,13 +359,7 @@ const KnowledgeContent: FC<KnowledgeContentProps> = ({ selectedBase }) => {
|
|||||||
<Tag color="blue">{base.model.name}</Tag>
|
<Tag color="blue">{base.model.name}</Tag>
|
||||||
<Tag color="cyan">{t('models.dimensions', { dimensions: base.dimensions || 0 })}</Tag>
|
<Tag color="cyan">{t('models.dimensions', { dimensions: base.dimensions || 0 })}</Tag>
|
||||||
{providerName && <Tag color="purple">{providerName}</Tag>}
|
{providerName && <Tag color="purple">{providerName}</Tag>}
|
||||||
</ModelInfo>
|
{/* <Button icon={<SettingOutlined />} onClick={() => KnowledgeSettingsPopup.show({ base })} size="small" /> */}
|
||||||
|
|
||||||
<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>
|
|
||||||
</ModelInfo>
|
</ModelInfo>
|
||||||
|
|
||||||
<IndexSection>
|
<IndexSection>
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import AiProvider from '@renderer/providers/AiProvider'
|
|||||||
import { getKnowledgeBaseParams } from '@renderer/services/KnowledgeService'
|
import { getKnowledgeBaseParams } from '@renderer/services/KnowledgeService'
|
||||||
import { getModelUniqId } from '@renderer/services/ModelService'
|
import { getModelUniqId } from '@renderer/services/ModelService'
|
||||||
import { Model } from '@renderer/types'
|
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 { find, sortBy } from 'lodash'
|
||||||
import { nanoid } from 'nanoid'
|
import { nanoid } from 'nanoid'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
@ -19,8 +19,6 @@ interface ShowParams {
|
|||||||
interface FormData {
|
interface FormData {
|
||||||
name: string
|
name: string
|
||||||
model: string
|
model: string
|
||||||
chunkSize?: number
|
|
||||||
chunkOverlap?: number
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props extends ShowParams {
|
interface Props extends ShowParams {
|
||||||
@ -83,8 +81,6 @@ const PopupContainer: React.FC<Props> = ({ title, resolve }) => {
|
|||||||
name: values.name,
|
name: values.name,
|
||||||
model: selectedModel,
|
model: selectedModel,
|
||||||
dimensions,
|
dimensions,
|
||||||
chunkSize: values.chunkSize,
|
|
||||||
chunkOverlap: values.chunkOverlap,
|
|
||||||
items: [],
|
items: [],
|
||||||
created_at: Date.now(),
|
created_at: Date.now(),
|
||||||
updated_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') }]}>
|
rules={[{ required: true, message: t('message.error.enter.model') }]}>
|
||||||
<Select style={{ width: '100%' }} options={selectOptions} placeholder={t('settings.models.empty')} />
|
<Select style={{ width: '100%' }} options={selectOptions} placeholder={t('settings.models.empty')} />
|
||||||
</Form.Item>
|
</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>
|
</Form>
|
||||||
</Modal>
|
</Modal>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -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
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user