feat: add external api

This commit is contained in:
Yi 2024-09-23 23:34:01 +08:00
parent 19c526120c
commit fbedd08292
15 changed files with 412 additions and 9 deletions

View File

@ -8,6 +8,7 @@ import { useDebounceFn } from 'ahooks'
import useSWR from 'swr'
// Components
import ExternalAPIPanel from '../../components/datasets/external-api/external-api-panel'
import Datasets from './Datasets'
import DatasetFooter from './DatasetFooter'
import ApiServer from './ApiServer'
@ -16,6 +17,8 @@ import TabSliderNew from '@/app/components/base/tab-slider-new'
import SearchInput from '@/app/components/base/search-input'
import TagManagementModal from '@/app/components/base/tag-management'
import TagFilter from '@/app/components/base/tag-management/filter'
import Button from '@/app/components/base/button'
import { ApiConnectionMod } from '@/app/components/base/icons/src/vender/solid/development'
// Services
import { fetchDatasetApiBaseUrl } from '@/service/datasets'
@ -30,6 +33,7 @@ const Container = () => {
const router = useRouter()
const { currentWorkspace } = useAppContext()
const showTagManagementModal = useTagStore(s => s.showTagManagementModal)
const [showExternalApiPanel, setShowExternalApiPanel] = useState(false)
const options = useMemo(() => {
return [
@ -80,6 +84,14 @@ const Container = () => {
<div className='flex items-center gap-2'>
<TagFilter type='knowledge' value={tagFilterValue} onChange={handleTagsChange} />
<SearchInput className='w-[200px]' value={keywords} onChange={handleKeywordsChange} />
<div className="w-[1px] h-4 bg-divider-regular" />
<Button
className='gap-0.5 shadows-shadow-xs'
onClick={() => setShowExternalApiPanel(true)}
>
<ApiConnectionMod className='w-4 h-4 text-components-button-secondary-text' />
<div className='flex px-0.5 justify-center items-center gap-1 text-components-button-secondary-text system-sm-medium'>{t('dataset.externalAPI')}</div>
</Button>
</div>
)}
{activeTab === 'api' && data && <ApiServer apiBaseUrl={data.api_base_url || ''} />}
@ -96,6 +108,8 @@ const Container = () => {
)}
{activeTab === 'api' && data && <Doc apiBaseUrl={data.api_base_url || ''} />}
{showExternalApiPanel && <ExternalAPIPanel onClose={() => setShowExternalApiPanel(false)} isShow={showExternalApiPanel} />}
</div>
)

View File

@ -4,21 +4,31 @@ import { forwardRef } from 'react'
import { useTranslation } from 'react-i18next'
import {
RiAddLine,
RiArrowRightLine,
} from '@remixicon/react'
const CreateAppCard = forwardRef<HTMLAnchorElement>((_, ref) => {
const { t } = useTranslation()
return (
<a ref={ref} className='group flex flex-col col-span-1 bg-gray-200 border-[0.5px] border-black/5 rounded-xl min-h-[160px] transition-all duration-200 ease-in-out cursor-pointer hover:bg-white hover:shadow-lg' href='/datasets/create'>
<div className='shrink-0 flex items-center p-4 pb-3'>
<div className='w-10 h-10 flex items-center justify-center border border-gray-200 bg-gray-100 rounded-lg'>
<RiAddLine className='w-4 h-4 text-gray-500'/>
<div className='flex flex-col bg-background-default-dimm border-[0.5px] border-components-panel-border rounded-xl
min-h-[160px] transition-all duration-200 ease-in-out'
>
<a ref={ref} className='group flex flex-grow items-start p-4 pb-2 cursor-pointer' href='/datasets/create'>
<div className='flex items-center gap-3'>
<div className='w-10 h-10 p-2 flex items-center justify-center border border-dashed border-divider-regular rounded-lg
bg-background-default-lighter group-hover:border-solid group-hover:border-effects-highlight group-hover:bg-background-default-dodge'
>
<RiAddLine className='w-4 h-4 text-text-tertiary group-hover:text-text-accent'/>
</div>
<div className='system-md-semibold text-text-secondary group-hover:text-text-accent'>{t('dataset.createDataset')}</div>
</div>
<div className='ml-3 text-sm font-semibold leading-5 text-gray-800 group-hover:text-primary-600'>{t('dataset.createDataset')}</div>
</div>
<div className='mb-1 px-4 text-xs leading-normal text-gray-500 line-clamp-4'>{t('dataset.createDatasetIntro')}</div>
</a>
</a>
<a className='group flex p-4 items-center gap-1 border-t-[0.5px] border-divider-subtle rounded-b-xl cursor-pointer' href='/datasets/connect'>
<div className='system-xs-medium text-text-tertiary group-hover:text-text-accent'>{t('dataset.connectDataset')}</div>
<RiArrowRightLine className='w-3.5 h-3.5 text-text-tertiary group-hover:text-text-accent' />
</a>
</div>
)
})

View File

@ -0,0 +1,5 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Icon L">
<path id="Vector" fill-rule="evenodd" clip-rule="evenodd" d="M7.99996 3.33333C5.42263 3.33333 3.33329 5.42267 3.33329 8C3.33329 10.5773 5.42263 12.6667 7.99996 12.6667C9.72643 12.6667 11.2348 11.7295 12.0427 10.3329C12.227 10.0141 12.6349 9.90523 12.9536 10.0896C13.2723 10.274 13.3812 10.6818 13.1968 11.0005C12.1604 12.7921 10.2216 14 7.99996 14C4.91159 14 2.36821 11.6666 2.03658 8.66667H1.33329C0.965103 8.66667 0.666626 8.36819 0.666626 8C0.666626 7.63181 0.965103 7.33333 1.33329 7.33333H2.03658C2.36821 4.33337 4.91159 2 7.99996 2C10.2216 2 12.1604 3.20785 13.1968 4.99952C13.3812 5.31823 13.2723 5.72605 12.9536 5.91041C12.6349 6.09477 12.227 5.98585 12.0427 5.66714C11.2348 4.27054 9.72643 3.33333 7.99996 3.33333ZM7.99996 6C6.89539 6 5.99996 6.89543 5.99996 8C5.99996 9.10455 6.89539 10 7.99996 10C9.1045 10 9.99996 9.10454 9.99996 8C9.99996 6.89543 9.10451 6 7.99996 6ZM4.66663 8C4.66663 6.15905 6.15901 4.66667 7.99996 4.66667C9.61257 4.66667 10.9578 5.81184 11.2666 7.33333H14.6666C15.0348 7.33333 15.3333 7.63181 15.3333 8C15.3333 8.36819 15.0348 8.66667 14.6666 8.66667H11.2666C10.9578 10.1881 9.61257 11.3333 7.99996 11.3333C6.159 11.3333 4.66663 9.84092 4.66663 8Z" fill="#354052"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,38 @@
{
"icon": {
"type": "element",
"isRootNode": true,
"name": "svg",
"attributes": {
"width": "16",
"height": "16",
"viewBox": "0 0 16 16",
"fill": "none",
"xmlns": "http://www.w3.org/2000/svg"
},
"children": [
{
"type": "element",
"name": "g",
"attributes": {
"id": "Icon L"
},
"children": [
{
"type": "element",
"name": "path",
"attributes": {
"id": "Vector",
"fill-rule": "evenodd",
"clip-rule": "evenodd",
"d": "M7.99996 3.33333C5.42263 3.33333 3.33329 5.42267 3.33329 8C3.33329 10.5773 5.42263 12.6667 7.99996 12.6667C9.72643 12.6667 11.2348 11.7295 12.0427 10.3329C12.227 10.0141 12.6349 9.90523 12.9536 10.0896C13.2723 10.274 13.3812 10.6818 13.1968 11.0005C12.1604 12.7921 10.2216 14 7.99996 14C4.91159 14 2.36821 11.6666 2.03658 8.66667H1.33329C0.965103 8.66667 0.666626 8.36819 0.666626 8C0.666626 7.63181 0.965103 7.33333 1.33329 7.33333H2.03658C2.36821 4.33337 4.91159 2 7.99996 2C10.2216 2 12.1604 3.20785 13.1968 4.99952C13.3812 5.31823 13.2723 5.72605 12.9536 5.91041C12.6349 6.09477 12.227 5.98585 12.0427 5.66714C11.2348 4.27054 9.72643 3.33333 7.99996 3.33333ZM7.99996 6C6.89539 6 5.99996 6.89543 5.99996 8C5.99996 9.10455 6.89539 10 7.99996 10C9.1045 10 9.99996 9.10454 9.99996 8C9.99996 6.89543 9.10451 6 7.99996 6ZM4.66663 8C4.66663 6.15905 6.15901 4.66667 7.99996 4.66667C9.61257 4.66667 10.9578 5.81184 11.2666 7.33333H14.6666C15.0348 7.33333 15.3333 7.63181 15.3333 8C15.3333 8.36819 15.0348 8.66667 14.6666 8.66667H11.2666C10.9578 10.1881 9.61257 11.3333 7.99996 11.3333C6.159 11.3333 4.66663 9.84092 4.66663 8Z",
"fill": "currentColor"
},
"children": []
}
]
}
]
},
"name": "ApiConnectionMod"
}

View File

@ -0,0 +1,16 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './ApiConnectionMod.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase'
const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>((
props,
ref,
) => <IconBase {...props} ref={ref} data={data as IconData} />)
Icon.displayName = 'ApiConnectionMod'
export default Icon

View File

@ -1,3 +1,4 @@
export { default as ApiConnectionMod } from './ApiConnectionMod'
export { default as ApiConnection } from './ApiConnection'
export { default as BarChartSquare02 } from './BarChartSquare02'
export { default as Container } from './Container'

View File

@ -3,5 +3,5 @@
}
.modal-panel {
@apply w-full max-w-md transform rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all;
@apply w-full max-w-[480px] transform rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all;
}

View File

@ -0,0 +1,141 @@
import type { FC } from 'react'
import {
memo,
useState,
} from 'react'
import { useTranslation } from 'react-i18next'
import {
RiCloseLine,
RiInformation2Line,
RiLock2Fill,
} from '@remixicon/react'
import { useToastContext } from '@/app/components/base/toast'
import {
PortalToFollowElem,
PortalToFollowElemContent,
} from '@/app/components/base/portal-to-follow-elem'
import ActionButton from '@/app/components/base/action-button'
import Input from '@/app/components/base/input'
import Button from '@/app/components/base/button'
import Tooltip from '@/app/components/base/tooltip'
type AddExternalAPIModalProps = {
show: boolean
onHide: () => void
}
const AddExternalAPIModal: FC<AddExternalAPIModalProps> = ({ show, onHide }) => {
const { t } = useTranslation()
const { notify } = useToastContext()
const [showConfirm, setShowConfirm] = useState(false)
const [formData, setFormData] = useState({ name: '', endpoint: '', apiKey: '' })
const isEditMode = true
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target
setFormData({ ...formData, [name]: value })
}
const handleFormSubmit = (e: React.FormEvent) => {
e.preventDefault()
// Handle form submission logic here
console.log('Form Data:', formData)
onHide()
}
return (
<PortalToFollowElem open>
<PortalToFollowElemContent className='w-full h-full z-[60]'>
<div className='fixed inset-0 flex items-center justify-center bg-black/[.25]'>
<div className='flex relative w-[480px] flex-col items-start bg-components-panel-bg rounded-2xl border-[0.5px] border-components-panel-border shadows-shadow-xl'>
<div className='flex flex-col pt-6 pl-6 pb-3 pr-14 items-start gap-2 self-stretch'>
<div className='self-stretch text-text-primary title-2xl-semi-bold flex-grow'>
{
isEditMode ? t('dataset.editExternalAPIFormTitle') : t('dataset.createExternalAPIFormTitle')
}
</div>
{isEditMode && (
<div className='text-text-tertiary system-xs-regular flex items-center'>
{t('dataset.editExternalAPIFormWarning.front')}
<span className='text-text-accent cursor-pointer flex items-center'>
&nbsp;3 {t('dataset.editExternalAPIFormWarning.end')}&nbsp;<Tooltip popupContent={'3 LINKED KNOWLEDGE --- needs to be modified'} asChild={false} position='bottom'><RiInformation2Line className='w-3.5 h-3.5' /></Tooltip>
</span>
</div>
)}
</div>
<ActionButton className='absolute top-5 right-5' onClick={onHide}>
<RiCloseLine className='w-[18px] h-[18px] text-text-tertiary flex-shrink-0' />
</ActionButton>
<form onSubmit={handleFormSubmit} className='flex px-6 py-3 flex-col justify-center items-start gap-4 self-stretch'>
<div className='flex flex-col justify-center items-start gap-4 self-stretch'>
<div className='flex flex-col items-start gap-1 self-stretch'>
<label className='text-text-secondary system-sm-semibold' htmlFor='name'>
{t('dataset.externalAPIForm.name')}
</label>
<Input
type='text'
id='name'
name='name'
value={formData.name}
onChange={handleInputChange}
required
/>
</div>
<div className='flex flex-col items-start gap-1 self-stretch'>
<label className='text-text-secondary system-sm-semibold' htmlFor='endpoint'>
{t('dataset.externalAPIForm.endpoint')}
</label>
<Input
type='text'
id='endpoint'
name='endpoint'
value={formData.endpoint}
onChange={handleInputChange}
required
/>
</div>
<div className='flex flex-col items-start gap-1 self-stretch'>
<label className='text-text-secondary system-sm-semibold' htmlFor='apiKey'>
{t('dataset.externalAPIForm.apiKey')}
</label>
<Input
type='text'
id='apiKey'
name='apiKey'
value={formData.apiKey}
onChange={handleInputChange}
required
/>
</div>
</div>
</form>
<div className='flex p-6 pt-5 justify-end items-center gap-2 self-stretch'>
<Button type='button' variant='secondary' onClick={onHide}>
{t('dataset.externalAPIForm.cancel')}
</Button>
<Button type='submit' variant='primary'>
{t('dataset.externalAPIForm.save')}
</Button>
</div>
<div className='flex px-2 py-3 justify-center items-center gap-1 self-stretch rounded-b-2xl
border-t-[0.5px] border-divider-subtle bg-background-soft text-text-tertiary system-xs-regular'
>
<RiLock2Fill className='w-3 h-3 text-text-quaternary' />
{t('dataset.externalAPIForm.encrypted.front')}
<a
className='text-text-accent'
target='_blank' rel='noopener noreferrer'
href='https://pycryptodome.readthedocs.io/en/latest/src/cipher/oaep.html'
>
PKCS1_OAEP
</a>
{t('dataset.externalAPIForm.encrypted.end')}
</div>
</div>
</div>
</PortalToFollowElemContent>
</PortalToFollowElem>
)
}
export default memo(AddExternalAPIModal)

View File

@ -0,0 +1,70 @@
import React from 'react'
import {
RiAddLine,
RiBookOpenLine,
RiCloseLine,
} from '@remixicon/react'
import { useTranslation } from 'react-i18next'
import cn from '@/utils/classnames'
// import AddExternalAPIForm from '../create/add-external-api'
import ActionButton from '@/app/components/base/action-button'
import Button from '@/app/components/base/button'
import { useModalContext } from '@/context/modal-context'
type ExternalAPIPanelProps = {
onClose: () => void
isShow: boolean
}
const ExternalAPIPanel: React.FC<ExternalAPIPanelProps> = ({ onClose, isShow }) => {
const { t } = useTranslation()
const { setShowExternalAPIModal } = useModalContext()
const handleOpenExternalAPIModal = () => {
setShowExternalAPIModal()
}
return (
<div
tabIndex={-1}
className={cn('absolute top-14 right-0 bottom-2 flex z-10 outline-none')}
>
<div
className={cn(
'relative flex flex-col w-[420px] bg-components-panel-bg-alt rounded-l-2xl h-full border border-components-panel-border',
)}
>
<div className='flex items-start self-stretch p-4 pb-0'>
<div className='flex flex-col items-start gap-1 flex-grow'>
<div className='self-stretch text-text-primary system-xl-semibold'>{t('dataset.externalAPIPanelTitle')}</div>
<div className='self-stretch text-text-tertiary body-xs-regular'>{t('dataset.externalAPIPanelDescription')}</div>
<a className='flex justify-center items-center gap-1 self-stretch cursor-pointer' href='https://docs.dify.ai/docs/external-api' target='_blank'>
<RiBookOpenLine className='w-3 h-3 text-text-accent' />
<div className='flex-grow text-text-accent body-xs-regular'>{t('dataset.externalAPIPanelDocumentation')}</div>
</a>
</div>
<div className='flex items-center'>
<ActionButton onClick={() => onClose()}>
<RiCloseLine className='w-4 h-4 text-text-tertiary' />
</ActionButton>
</div>
</div>
<div className='flex px-4 py-3 flex-col justify-center items-start gap-2 self-stretch'>
<Button
variant={'primary'}
className='flex justify-center items-center px-3 py-2 gap-0.5'
onClick={handleOpenExternalAPIModal}
>
<RiAddLine className='w-4 h-4 text-components-button-primary-text' />
<div className='text-components-button-primary-text system-sm-medium'>{t('dataset.createExternalAPI')}</div>
</Button>
</div>
<div className='flex py-0 px-4 flex-col items-start gap-1 flex-grow self-stretch'>
</div>
</div>
</div>
)
}
export default ExternalAPIPanel

View File

@ -10,6 +10,7 @@ import ModerationSettingModal from '@/app/components/app/configuration/toolbox/m
import ExternalDataToolModal from '@/app/components/app/configuration/tools/external-data-tool-modal'
import AnnotationFullModal from '@/app/components/billing/annotation-full/modal'
import ModelModal from '@/app/components/header/account-setting/model-provider-page/model-modal'
import ExternalAPIModal from '@/app/components/datasets/external-api/external-api-modal'
import type {
ConfigurationMethodEnum,
CustomConfigurationModelFixedFields,
@ -52,6 +53,7 @@ export type ModalContextState = {
setShowPricingModal: () => void
setShowAnnotationFullModal: () => void
setShowModelModal: Dispatch<SetStateAction<ModalState<ModelModalType> | null>>
setShowExternalAPIModal: () => void
setShowModelLoadBalancingModal: Dispatch<SetStateAction<ModelLoadBalancingModalProps | null>>
setShowModelLoadBalancingEntryModal: Dispatch<SetStateAction<ModalState<LoadBalancingEntryModalType> | null>>
}
@ -63,6 +65,7 @@ const ModalContext = createContext<ModalContextState>({
setShowPricingModal: () => { },
setShowAnnotationFullModal: () => { },
setShowModelModal: () => { },
setShowExternalAPIModal: () => { },
setShowModelLoadBalancingModal: () => { },
setShowModelLoadBalancingEntryModal: () => { },
})
@ -86,6 +89,7 @@ export const ModalContextProvider = ({
const [showModerationSettingModal, setShowModerationSettingModal] = useState<ModalState<ModerationConfig> | null>(null)
const [showExternalDataToolModal, setShowExternalDataToolModal] = useState<ModalState<ExternalDataTool> | null>(null)
const [showModelModal, setShowModelModal] = useState<ModalState<ModelModalType> | null>(null)
const [showExternalAPIModal, setShowExternalAPIModal] = useState(false)
const [showModelLoadBalancingModal, setShowModelLoadBalancingModal] = useState<ModelLoadBalancingModalProps | null>(null)
const [showModelLoadBalancingEntryModal, setShowModelLoadBalancingEntryModal] = useState<ModalState<LoadBalancingEntryModalType> | null>(null)
const searchParams = useSearchParams()
@ -122,6 +126,18 @@ export const ModalContextProvider = ({
setShowModelModal(null)
}, [showModelModal])
// const handleCancelExternalApiModal = useCallback(() => {
// setShowExternalAPIModal(null)
// if (showExternalAPIModal?.onCancelCallback)
// showExternalAPIModal.onCancelCallback()
// }, [showExternalAPIModal])
// const handleSaveExternalApiModal = useCallback(() => {
// if (showExternalAPIModal?.onSaveCallback)
// showExternalAPIModal.onSaveCallback(null)
// setShowExternalAPIModal(null)
// }, [showExternalAPIModal])
const handleCancelModelLoadBalancingEntryModal = useCallback(() => {
showModelLoadBalancingEntryModal?.onCancelCallback?.()
setShowModelLoadBalancingEntryModal(null)
@ -173,6 +189,7 @@ export const ModalContextProvider = ({
setShowPricingModal: () => setShowPricingModal(true),
setShowAnnotationFullModal: () => setShowAnnotationFullModal(true),
setShowModelModal,
setShowExternalAPIModal: () => setShowExternalAPIModal(true),
setShowModelLoadBalancingModal,
setShowModelLoadBalancingEntryModal,
}}>
@ -245,6 +262,14 @@ export const ModalContextProvider = ({
/>
)
}
{
!!showExternalAPIModal && (
<ExternalAPIModal
show={showExternalAPIModal}
onHide={() => setShowExternalAPIModal(false)}
/>
)
}
{
Boolean(showModelLoadBalancingModal) && (
<ModelLoadBalancingModal {...showModelLoadBalancingModal!} />

View File

@ -1,9 +1,21 @@
const translation = {
knowledge: 'Knowledge',
externalAPI: 'External API',
externalAPIPanelTitle: 'External Knowledge API',
externalAPIPanelDescription: 'The external knowledge API is used to connect to a knowledge base outside of Dify and retrieve knowledge from that knowledge base.',
externalAPIPanelDocumentation: 'Learn how to create an external API',
documentCount: ' docs',
wordCount: ' k words',
appCount: ' linked apps',
createDataset: 'Create Knowledge',
createExternalAPI: 'Add an External API',
createExternalAPIFormTitle: 'Add an External Knowledge API',
editExternalAPIFormTitle: 'Edit the External Knowledge API',
editExternalAPIFormWarning: {
front: 'This External API is linked to',
end: 'external knowledge',
},
connectDataset: 'Connect to an external knowledge base',
createDatasetIntro: 'Import your own text data or write data in real-time via Webhook for LLM context enhancement.',
deleteDatasetConfirmTitle: 'Delete this Knowledge?',
deleteDatasetConfirmContent:
@ -22,6 +34,18 @@ const translation = {
unavailableTip: 'Embedding model is not available, the default embedding model needs to be configured',
datasets: 'KNOWLEDGE',
datasetsApi: 'API ACCESS',
externalAPIForm: {
name: 'Name',
endpoint: 'API Endpoint',
apiKey: 'API Key',
save: 'Save',
cancel: 'Cancel',
edit: 'Edit',
encrypted: {
front: 'Your API Token will be encrypted and stored using',
end: 'technology.',
},
},
retrieval: {
semantic_search: {
title: 'Vector Search',

View File

@ -1,9 +1,21 @@
const translation = {
knowledge: '知识库',
externalAPI: '外部 API',
externalAPIPanelTitle: '外部知识库 API',
externalAPIPanelDescription: '外部知识库 API 用于连接到 Dify 之外的知识库并从中检索知识。',
externalAPIPanelDocumentation: '了解如何创建外部 API',
documentCount: ' 文档',
wordCount: ' 千字符',
appCount: ' 关联应用',
createDataset: '创建知识库',
createExternalAPI: '添加外部 API',
createExternalAPIFormTitle: '添加外部知识库 API',
editExternalAPIFormTitle: '编辑外部知识库 API',
editExternalAPIFormWarning: {
front: '此外部 API 已链接到',
end: '外部知识库',
},
connectDataset: '连接外部知识库',
createDatasetIntro: '导入您自己的文本数据或通过 Webhook 实时写入数据以增强 LLM 的上下文。',
deleteDatasetConfirmTitle: '要删除知识库吗?',
deleteDatasetConfirmContent:
@ -22,6 +34,18 @@ const translation = {
unavailableTip: '由于 embedding 模型不可用,需要配置默认 embedding 模型',
datasets: '知识库',
datasetsApi: 'API',
externalAPIForm: {
name: '名称',
endpoint: 'API 端点',
apiKey: 'API 密钥',
save: '保存',
cancel: '取消',
edit: '编辑',
encrypted: {
front: '您的 API Token 将使用',
end: '加密并存储。',
},
},
retrieval: {
semantic_search: {
title: '向量检索',

View File

@ -34,6 +34,23 @@ export type DataSet = {
partial_member_list?: any[]
}
export type ExternalAPIItem = {
id: string
tenant_id: string
name: string
description: string
settings: {
endpoint: string
api_key: string
document_retrieval_setting: {
top_k: number
score_threshold: number
}
}
created_by: string
created_at: string
}
export type CustomFile = File & {
id?: string
extension?: string
@ -72,6 +89,14 @@ export type DataSetListResponse = {
total: number
}
export type ExternalAPIListResponse = {
data: ExternalAPIItem[]
has_more: boolean
limit: number
page: number
total: number
}
export type QA = {
question: string
answer: string

View File

@ -8,6 +8,8 @@ import type {
DocumentDetailResponse,
DocumentListResponse,
ErrorDocsResponse,
ExternalAPIItem,
ExternalAPIListResponse,
FileIndexingEstimateResponse,
HitTestingRecordsResponse,
HitTestingResponse,
@ -82,6 +84,14 @@ export const deleteDataset: Fetcher<DataSet, string> = (datasetID) => {
return del<DataSet>(`/datasets/${datasetID}`)
}
export const fetchExternalAPIList: Fetcher<ExternalAPIListResponse, { url: string; params: { page: number; limit: number } }> = ({ url, params }) => {
return get<ExternalAPIListResponse>(url, { params })
}
export const createExternalAPI: Fetcher<ExternalAPIItem, { body: ExternalAPIItem }> = ({ body }) => {
return post<ExternalAPIItem>('/datasets/api-template', { body })
}
export const fetchDefaultProcessRule: Fetcher<ProcessRuleResponse, { url: string }> = ({ url }) => {
return get<ProcessRuleResponse>(url)
}