feat: add knowledge base settings popup
This commit is contained in:
parent
d33714ad68
commit
44991edfbd
@ -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",
|
||||
|
||||
@ -613,7 +613,8 @@
|
||||
"source": "ソース",
|
||||
"chunk_size": "チャンクサイズ",
|
||||
"chunk_overlap": "チャンクの重なり",
|
||||
"not_set": "未設定"
|
||||
"not_set": "未設定",
|
||||
"settings": "ナレッジベース設定"
|
||||
},
|
||||
"models": {
|
||||
"pinned": "固定済み",
|
||||
|
||||
@ -626,7 +626,8 @@
|
||||
"source": "Источник",
|
||||
"chunk_size": "Размер фрагмента",
|
||||
"chunk_overlap": "Перекрытие фрагмента",
|
||||
"not_set": "Не установлено"
|
||||
"not_set": "Не установлено",
|
||||
"settings": "Настройки базы знаний"
|
||||
},
|
||||
"models": {
|
||||
"pinned": "Закреплено",
|
||||
|
||||
@ -615,7 +615,8 @@
|
||||
"source": "来源",
|
||||
"chunk_size": "分段大小",
|
||||
"chunk_overlap": "重叠大小",
|
||||
"not_set": "未设置"
|
||||
"not_set": "未设置",
|
||||
"settings": "知识库设置"
|
||||
},
|
||||
"models": {
|
||||
"pinned": "已固定",
|
||||
|
||||
@ -614,7 +614,8 @@
|
||||
"source": "來源",
|
||||
"chunk_size": "分段大小",
|
||||
"chunk_overlap": "重疊大小",
|
||||
"not_set": "未設置"
|
||||
"not_set": "未設置",
|
||||
"settings": "知識庫設定"
|
||||
},
|
||||
"models": {
|
||||
"pinned": "已固定",
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
)
|
||||
|
||||
@ -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