feat: add api-based extension & external data tool & moderation (#1459)

This commit is contained in:
zxhlyh
2023-11-06 19:36:32 +08:00
committed by GitHub
parent db43ed6f41
commit 32747641e4
84 changed files with 3327 additions and 167 deletions

View File

@@ -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

View File

@@ -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>

View File

@@ -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