feat: add api-based extension & external data tool & moderation (#1459)
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import SettingsModal from '../settings-modal'
|
||||
import type { DataSet } from '@/models/datasets'
|
||||
import { DataSourceType } from '@/models/datasets'
|
||||
import { formatNumber } from '@/utils/format'
|
||||
import FileIcon from '@/app/components/base/file-icon'
|
||||
import { Settings01, Trash03 } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import { Folder } from '@/app/components/base/icons/src/vender/solid/files'
|
||||
|
||||
type ItemProps = {
|
||||
className?: string
|
||||
config: DataSet
|
||||
onRemove: (id: string) => void
|
||||
readonly?: boolean
|
||||
onSave: (newDataset: DataSet) => void
|
||||
}
|
||||
|
||||
const Item: FC<ItemProps> = ({
|
||||
config,
|
||||
onSave,
|
||||
onRemove,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const [showSettingsModal, setShowSettingsModal] = useState(false)
|
||||
|
||||
const handleSave = (newDataset: DataSet) => {
|
||||
onSave(newDataset)
|
||||
setShowSettingsModal(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='group relative flex items-center mb-1 last-of-type:mb-0 pl-2.5 py-2 pr-3 w-full bg-white rounded-lg border-[0.5px] border-gray-200 shadow-xs'>
|
||||
{
|
||||
config.data_source_type === DataSourceType.FILE && (
|
||||
<div className='shrink-0 flex items-center justify-center mr-2 w-6 h-6 bg-[#F5F8FF] rounded-md border-[0.5px] border-[#E0EAFF]'>
|
||||
<Folder className='w-4 h-4 text-[#444CE7]' />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
{
|
||||
config.data_source_type === DataSourceType.NOTION && (
|
||||
<div className='shrink-0 flex items-center justify-center mr-2 w-6 h-6 rounded-md border-[0.5px] border-[#EAECF5]'>
|
||||
<FileIcon type='notion' className='w-4 h-4' />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
<div className='grow'>
|
||||
<div className='flex items-center h-[18px]'>
|
||||
<div className='grow text-[13px] font-medium text-gray-800 truncate' title={config.name}>{config.name}</div>
|
||||
<div className='shrink-0 text-xs text-gray-500'>
|
||||
{formatNumber(config.word_count)} {t('appDebug.feature.dataSet.words')} · {formatNumber(config.document_count)} {t('appDebug.feature.dataSet.textBlocks')}
|
||||
</div>
|
||||
</div>
|
||||
{/* {
|
||||
config.description && (
|
||||
<div className='text-xs text-gray-500'>{config.description}</div>
|
||||
)
|
||||
} */}
|
||||
</div>
|
||||
<div className='hidden group-hover:flex items-center justify-end absolute right-0 top-0 bottom-0 pr-2 w-[124px] bg-gradient-to-r from-white/50 to-white to-50%'>
|
||||
<div
|
||||
className='flex items-center justify-center mr-1 w-6 h-6 hover:bg-black/5 rounded-md cursor-pointer'
|
||||
onClick={() => setShowSettingsModal(true)}
|
||||
>
|
||||
<Settings01 className='w-4 h-4 text-gray-500' />
|
||||
</div>
|
||||
<div
|
||||
className='group/action flex items-center justify-center w-6 h-6 hover:bg-[#FEE4E2] rounded-md cursor-pointer'
|
||||
onClick={() => onRemove(config.id)}
|
||||
>
|
||||
<Trash03 className='w-4 h-4 text-gray-500 group-hover/action:text-[#D92D20]' />
|
||||
</div>
|
||||
</div>
|
||||
{
|
||||
showSettingsModal && (
|
||||
<SettingsModal
|
||||
currentDataset={config}
|
||||
onCancel={() => setShowSettingsModal(false)}
|
||||
onSave={handleSave}
|
||||
/>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Item
|
||||
@@ -6,11 +6,12 @@ import { useContext } from 'use-context-selector'
|
||||
import produce from 'immer'
|
||||
import FeaturePanel from '../base/feature-panel'
|
||||
import OperationBtn from '../base/operation-btn'
|
||||
import CardItem from './card-item'
|
||||
import CardItem from './card-item/item'
|
||||
import ParamsConfig from './params-config'
|
||||
import ContextVar from './context-var'
|
||||
import ConfigContext from '@/context/debug-configuration'
|
||||
import { AppType } from '@/types/app'
|
||||
import type { DataSet } from '@/models/datasets'
|
||||
|
||||
const Icon = (
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
@@ -30,7 +31,6 @@ const DatasetConfig: FC = () => {
|
||||
setModelConfig,
|
||||
showSelectDataSet,
|
||||
} = useContext(ConfigContext)
|
||||
const selectedIds = dataSet.map(item => item.id)
|
||||
|
||||
const hasData = dataSet.length > 0
|
||||
|
||||
@@ -39,6 +39,13 @@ const DatasetConfig: FC = () => {
|
||||
setFormattingChanged(true)
|
||||
}
|
||||
|
||||
const handleSave = (newDataset: DataSet) => {
|
||||
const index = dataSet.findIndex(item => item.id === newDataset.id)
|
||||
|
||||
setDataSet([...dataSet.slice(0, index), newDataset, ...dataSet.slice(index + 1)])
|
||||
setFormattingChanged(true)
|
||||
}
|
||||
|
||||
const promptVariables = modelConfig.configs.prompt_variables
|
||||
const promptVariablesToSelect = promptVariables.map(item => ({
|
||||
name: item.name,
|
||||
@@ -77,10 +84,10 @@ const DatasetConfig: FC = () => {
|
||||
<div className='flex flex-wrap mt-1 px-3 justify-between'>
|
||||
{dataSet.map(item => (
|
||||
<CardItem
|
||||
className="mb-2"
|
||||
key={item.id}
|
||||
config={item}
|
||||
onRemove={onRemove}
|
||||
onSave={handleSave}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
import type { FC } from 'react'
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import IndexMethodRadio from '@/app/components/datasets/settings/index-method-radio'
|
||||
import Modal from '@/app/components/base/modal'
|
||||
import Button from '@/app/components/base/button'
|
||||
import ModelSelector from '@/app/components/header/account-setting/model-page/model-selector'
|
||||
import type { ProviderEnum } from '@/app/components/header/account-setting/model-page/declarations'
|
||||
import { ModelType } from '@/app/components/header/account-setting/model-page/declarations'
|
||||
import type { DataSet } from '@/models/datasets'
|
||||
import { useToastContext } from '@/app/components/base/toast'
|
||||
import { updateDatasetSetting } from '@/service/datasets'
|
||||
import { useModalContext } from '@/context/modal-context'
|
||||
|
||||
type SettingsModalProps = {
|
||||
currentDataset: DataSet
|
||||
onCancel: () => void
|
||||
onSave: (newDataset: DataSet) => void
|
||||
}
|
||||
const SettingsModal: FC<SettingsModalProps> = ({
|
||||
currentDataset,
|
||||
onCancel,
|
||||
onSave,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const { notify } = useToastContext()
|
||||
const { setShowAccountSettingModal } = useModalContext()
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [localeCurrentDataset, setLocaleCurrentDataset] = useState({ ...currentDataset })
|
||||
|
||||
const handleValueChange = (type: string, value: string) => {
|
||||
setLocaleCurrentDataset({ ...localeCurrentDataset, [type]: value })
|
||||
}
|
||||
|
||||
const handleSave = async () => {
|
||||
if (loading)
|
||||
return
|
||||
if (!localeCurrentDataset.name?.trim()) {
|
||||
notify({ type: 'error', message: t('datasetSettings.form.nameError') })
|
||||
return
|
||||
}
|
||||
try {
|
||||
setLoading(true)
|
||||
const { id, name, description, indexing_technique } = localeCurrentDataset
|
||||
await updateDatasetSetting({
|
||||
datasetId: id,
|
||||
body: {
|
||||
name,
|
||||
description,
|
||||
indexing_technique,
|
||||
},
|
||||
})
|
||||
notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
|
||||
onSave(localeCurrentDataset)
|
||||
}
|
||||
catch (e) {
|
||||
notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') })
|
||||
}
|
||||
finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isShow
|
||||
onClose={() => {}}
|
||||
className='!p-8 !pb-6 !max-w-none !w-[640px]'
|
||||
>
|
||||
<div className='mb-2 text-xl font-semibold text-gray-900'>
|
||||
{t('datasetSettings.title')}
|
||||
</div>
|
||||
<div className='py-2'>
|
||||
<div className='leading-9 text-sm font-medium text-gray-900'>
|
||||
{t('datasetSettings.form.name')}
|
||||
</div>
|
||||
<input
|
||||
value={localeCurrentDataset.name}
|
||||
onChange={e => handleValueChange('name', e.target.value)}
|
||||
className='block px-3 w-full h-9 bg-gray-100 rounded-lg text-sm text-gray-900 outline-none appearance-none'
|
||||
placeholder={t('datasetSettings.form.namePlaceholder') || ''}
|
||||
/>
|
||||
</div>
|
||||
<div className='py-2'>
|
||||
<div className='flex justify-between items-center mb-1 h-5 text-sm font-medium text-gray-900'>
|
||||
{t('datasetSettings.form.desc')}
|
||||
</div>
|
||||
<div className='mb-2 text-xs text-gray-500'>
|
||||
{t('datasetSettings.form.descInfo')}<a href='/' className='text-primary-600'>{t('common.operation.learnMore')}</a>
|
||||
</div>
|
||||
<textarea
|
||||
value={localeCurrentDataset.description || ''}
|
||||
onChange={e => handleValueChange('description', e.target.value)}
|
||||
className='block px-3 py-2 w-full h-[88px] rounded-lg bg-gray-100 text-sm outline-none appearance-none resize-none'
|
||||
placeholder={t('datasetSettings.form.descPlaceholder') || ''}
|
||||
/>
|
||||
</div>
|
||||
<div className='py-2'>
|
||||
<div className='leading-9 text-sm font-medium text-gray-900'>
|
||||
{t('datasetSettings.form.indexMethod')}
|
||||
</div>
|
||||
<div>
|
||||
<IndexMethodRadio
|
||||
disable={!localeCurrentDataset?.embedding_available}
|
||||
value={localeCurrentDataset.indexing_technique}
|
||||
onChange={v => handleValueChange('indexing_technique', v!)}
|
||||
itemClassName='!w-[282px]'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className='py-2'>
|
||||
<div className='leading-9 text-sm font-medium text-gray-900'>
|
||||
{t('datasetSettings.form.embeddingModel')}
|
||||
</div>
|
||||
<div className='w-full h-9 rounded-lg bg-gray-100 opacity-60'>
|
||||
<ModelSelector
|
||||
readonly
|
||||
value={{
|
||||
providerName: localeCurrentDataset.embedding_model_provider as ProviderEnum,
|
||||
modelName: localeCurrentDataset.embedding_model,
|
||||
}}
|
||||
modelType={ModelType.embeddings}
|
||||
onChange={() => {}}
|
||||
/>
|
||||
</div>
|
||||
<div className='mt-2 w-full text-xs leading-6 text-gray-500'>
|
||||
{t('datasetSettings.form.embeddingModelTip')}
|
||||
<span className='text-[#155eef] cursor-pointer' onClick={() => setShowAccountSettingModal({ payload: 'provider' })}>{t('datasetSettings.form.embeddingModelTipLink')}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
<div className='flex items-center justify-end mt-6'>
|
||||
<Button
|
||||
onClick={onCancel}
|
||||
className='mr-2 text-sm font-medium'
|
||||
>
|
||||
{t('common.operation.cancel')}
|
||||
</Button>
|
||||
<Button
|
||||
type='primary'
|
||||
className='text-sm font-medium'
|
||||
disabled={loading}
|
||||
onClick={handleSave}
|
||||
>
|
||||
{t('common.operation.save')}
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default SettingsModal
|
||||
Reference in New Issue
Block a user