diff --git a/web/app/(commonLayout)/datasets/DatasetCard.tsx b/web/app/(commonLayout)/datasets/DatasetCard.tsx
index e3014f08d0..fa0625a528 100644
--- a/web/app/(commonLayout)/datasets/DatasetCard.tsx
+++ b/web/app/(commonLayout)/datasets/DatasetCard.tsx
@@ -111,7 +111,7 @@ const DatasetCard = ({
return (
<>
{
e.preventDefault()
@@ -144,11 +144,18 @@ const DatasetCard = ({
className={cn('truncate', (!dataset.embedding_available || !dataset.document_count) && 'opacity-50')}
title={`${dataset.document_count}${t('dataset.documentCount')} · ${Math.round(dataset.word_count / 1000)}${t('dataset.wordCount')} · ${dataset.app_count}${t('dataset.appCount')}`}
>
- {dataset.document_count}{t('dataset.documentCount')}
- ·
- {Math.round(dataset.word_count / 1000)}{t('dataset.wordCount')}
- ·
- {dataset.app_count}{t('dataset.appCount')}
+ {dataset.provider === 'external'
+ ? <>
+ {dataset.app_count}{t('dataset.appCount')}
+ >
+ : <>
+ {dataset.document_count}{t('dataset.documentCount')}
+ ·
+ {Math.round(dataset.word_count / 1000)}{t('dataset.wordCount')}
+ ·
+ {dataset.app_count}{t('dataset.appCount')}
+ >
+ }
diff --git a/web/app/components/app-sidebar/basic.tsx b/web/app/components/app-sidebar/basic.tsx
index ef88a1971d..51fc10721e 100644
--- a/web/app/components/app-sidebar/basic.tsx
+++ b/web/app/components/app-sidebar/basic.tsx
@@ -1,4 +1,5 @@
import React from 'react'
+import { useTranslation } from 'react-i18next'
import AppIcon from '../base/app-icon'
import Tooltip from '@/app/components/base/tooltip'
@@ -54,6 +55,8 @@ const ICON_MAP = {
}
export default function AppBasic({ icon, icon_background, name, isExternal, type, hoverTip, textStyle, mode = 'expand', iconType = 'app' }: IAppBasicProps) {
+ const { t } = useTranslation()
+
return (
{icon && icon_background && iconType === 'app' && (
@@ -84,7 +87,7 @@ export default function AppBasic({ icon, icon_background, name, isExternal, type
}
{type}
- {isExternal ? 'External' : ''}
+ {isExternal ? t('dataset.externalTag') : ''}
}
)
diff --git a/web/app/components/app/configuration/dataset-config/params-config/config-content.tsx b/web/app/components/app/configuration/dataset-config/params-config/config-content.tsx
index 91cae54bb8..f99496b14f 100644
--- a/web/app/components/app/configuration/dataset-config/params-config/config-content.tsx
+++ b/web/app/components/app/configuration/dataset-config/params-config/config-content.tsx
@@ -174,6 +174,20 @@ const ConfigContent: FC = ({
)
}
+ {
+ selectedDatasetsMode.mixtureInternalAndExternal && (
+
+ {t('dataset.mixtureInternalAndExternalTip')}
+
+ )
+ }
+ {
+ selectedDatasetsMode.allExternal && (
+
+ {t('dataset.allExternalTip')}
+
+ )
+ }
{
selectedDatasetsMode.mixtureHighQualityAndEconomic
&& (
@@ -229,15 +243,15 @@ const ConfigContent: FC = ({
/>
)
}
- {t('common.modelProvider.rerankModel.key')}
+ {t('common.modelProvider.rerankModel.key')}
{t('common.modelProvider.rerankModel.tip')}
}
- popupClassName='ml-0.5'
- triggerClassName='ml-0.5 w-3.5 h-3.5'
+ popupClassName='ml-1'
+ triggerClassName='ml-1 w-4 h-4'
/>
diff --git a/web/app/components/app/configuration/dataset-config/select-dataset/index.tsx b/web/app/components/app/configuration/dataset-config/select-dataset/index.tsx
index 4493755ba0..0d94e599b4 100644
--- a/web/app/components/app/configuration/dataset-config/select-dataset/index.tsx
+++ b/web/app/components/app/configuration/dataset-config/select-dataset/index.tsx
@@ -47,7 +47,7 @@ const SelectDataSet: FC = ({
const { data, has_more } = await fetchDatasets({ url: '/datasets', params: { page } })
setPage(getPage() + 1)
setIsNoMore(!has_more)
- const newList = [...(datasets || []), ...data.filter(item => item.indexing_technique)]
+ const newList = [...(datasets || []), ...data.filter(item => item.indexing_technique || item.provider === 'external')]
setDataSets(newList)
setLoaded(true)
if (!selected.find(item => !item.name))
@@ -145,6 +145,11 @@ const SelectDataSet: FC = ({
/>
)
}
+ {
+ item.provider === 'external' && (
+
+ )
+ }
))}
diff --git a/web/app/components/app/configuration/dataset-config/settings-modal/index.tsx b/web/app/components/app/configuration/dataset-config/settings-modal/index.tsx
index e538c347d9..05e7b46ced 100644
--- a/web/app/components/app/configuration/dataset-config/settings-modal/index.tsx
+++ b/web/app/components/app/configuration/dataset-config/settings-modal/index.tsx
@@ -5,8 +5,10 @@ import { useTranslation } from 'react-i18next'
import { isEqual } from 'lodash-es'
import { RiCloseLine } from '@remixicon/react'
import { BookOpenIcon } from '@heroicons/react/24/outline'
+import { ApiConnectionMod } from '@/app/components/base/icons/src/vender/solid/development'
import cn from '@/utils/classnames'
import IndexMethodRadio from '@/app/components/datasets/settings/index-method-radio'
+import Divider from '@/app/components/base/divider'
import Button from '@/app/components/base/button'
import type { DataSet } from '@/models/datasets'
import { useToastContext } from '@/app/components/base/toast'
@@ -14,6 +16,7 @@ import { updateDatasetSetting } from '@/service/datasets'
import { useAppContext } from '@/context/app-context'
import { useModalContext } from '@/context/modal-context'
import type { RetrievalConfig } from '@/types/app'
+import RetrievalSettings from '@/app/components/datasets/external-knowledge-base/create/RetrievalSettings'
import RetrievalMethodConfig from '@/app/components/datasets/common/retrieval-method-config'
import EconomicalRetrievalMethodConfig from '@/app/components/datasets/common/economical-retrieval-method-config'
import { ensureRerankModelSelected, isReRankModelSelected } from '@/app/components/datasets/common/check-rerank-model'
@@ -56,6 +59,8 @@ const SettingsModal: FC = ({
const { t } = useTranslation()
const { notify } = useToastContext()
const ref = useRef(null)
+ const [topK, setTopK] = useState(currentDataset?.external_retrieval_model.top_k ?? 2)
+ const [scoreThreshold, setScoreThreshold] = useState(currentDataset?.external_retrieval_model.score_threshold ?? 0.5)
const { setShowAccountSettingModal } = useModalContext()
const [loading, setLoading] = useState(false)
@@ -73,6 +78,13 @@ const SettingsModal: FC = ({
const [isHideChangedTip, setIsHideChangedTip] = useState(false)
const isRetrievalChanged = !isEqual(retrievalConfig, localeCurrentDataset?.retrieval_model_dict) || indexMethod !== localeCurrentDataset?.indexing_technique
+ const handleSettingsChange = (data: { top_k?: number; score_threshold?: number }) => {
+ if (data.top_k !== undefined)
+ setTopK(data.top_k)
+ if (data.score_threshold !== undefined)
+ setScoreThreshold(data.score_threshold)
+ }
+
const handleSave = async () => {
if (loading)
return
@@ -107,10 +119,16 @@ const SettingsModal: FC = ({
description,
permission,
indexing_technique: indexMethod,
+ external_retrieval_model: {
+ top_k: topK,
+ score_threshold: scoreThreshold,
+ },
retrieval_model: {
...postRetrievalConfig,
score_threshold: postRetrievalConfig.score_threshold_enabled ? postRetrievalConfig.score_threshold : 0,
},
+ external_knowledge_id: currentDataset!.external_knowledge_info.external_knowledge_id,
+ external_knowledge_api_id: currentDataset!.external_knowledge_info.external_knowledge_api_id,
embedding_model: localeCurrentDataset.embedding_model,
embedding_model_provider: localeCurrentDataset.embedding_model_provider,
},
@@ -178,7 +196,7 @@ const SettingsModal: FC = ({
}}>
- {t('datasetSettings.form.name')}
+
{t('datasetSettings.form.name')}
= ({
- {t('datasetSettings.form.desc')}
+
{t('datasetSettings.form.desc')}
-
{t('datasetSettings.form.permissions')}
+
{t('datasetSettings.form.permissions')}
-
-
-
- {t('datasetSettings.form.indexMethod')}
+ {currentDataset && currentDataset.indexing_technique && (
+
+
+
{t('datasetSettings.form.indexMethod')}
+
+
+ setIndexMethod(v!)}
+ itemClassName='sm:!w-[280px]'
+ />
+
-
- setIndexMethod(v!)}
- itemClassName='sm:!w-[280px]'
- />
-
-
+ )}
{indexMethod === 'high_quality' && (
- {t('datasetSettings.form.embeddingModel')}
+
{t('datasetSettings.form.embeddingModel')}
@@ -258,32 +277,74 @@ const SettingsModal: FC
= ({
)}
{/* Retrieval Method Config */}
-
-
-
-
{t('datasetSettings.form.retrievalSetting.title')}
-
-
{t('datasetSettings.form.retrievalSetting.learnMore')}
- {t('datasetSettings.form.retrievalSetting.description')}
+ {currentDataset?.provider === 'external'
+ ? <>
+
+
+
+
{t('datasetSettings.form.retrievalSetting.title')}
+
+
+
+
+
+
+
{t('datasetSettings.form.externalKnowledgeAPI')}
+
+
+
+
+
+ {currentDataset?.external_knowledge_info.external_knowledge_api_name}
+
+
·
+
{currentDataset?.external_knowledge_info.external_knowledge_api_endpoint}
+
-
-
- {indexMethod === 'high_quality'
- ? (
-
- )
- : (
-
- )}
-
-
+
+
+
{t('datasetSettings.form.externalKnowledgeID')}
+
+
+
+
{currentDataset?.external_knowledge_info.external_knowledge_id}
+
+
+
+
+ >
+ :
+
+
+
{t('datasetSettings.form.retrievalSetting.title')}
+
+
+
+
+ {indexMethod === 'high_quality'
+ ? (
+
+ )
+ : (
+
+ )}
+
+
}
{isRetrievalChanged && !isHideChangedTip && (
diff --git a/web/app/components/datasets/external-api/endpoint-validator/declarations.ts b/web/app/components/datasets/external-api/endpoint-validator/declarations.ts
deleted file mode 100644
index 77655c4c8e..0000000000
--- a/web/app/components/datasets/external-api/endpoint-validator/declarations.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-import type { Dispatch, SetStateAction } from 'react'
-
-export enum ValidatedEndpointStatus {
- Success = 'success',
- Error = 'error',
-}
-
-export type ValidatedStatusState = {
- status?: ValidatedEndpointStatus
- message?: string
-}
-
-export type Status = 'add' | 'fail' | 'success'
-
-export type ValidateValue = string
-
-export type ValidateCallback = {
- before: (v?: ValidateValue) => boolean | undefined
- run?: (v?: ValidateValue) => Promise
-}
-
-export type Form = {
- key: string
- title: string
- placeholder: string
- value?: string
- validate?: ValidateCallback
- handleFocus?: (v: ValidateValue, dispatch: Dispatch>) => void
-}
-
-export type KeyFrom = {
- text: string
- link: string
-}
-
-export type KeyValidatorProps = {
- type: string
- title: React.ReactNode
- status: Status
- forms: Form[]
- keyFrom: KeyFrom
-}
diff --git a/web/app/components/datasets/external-api/endpoint-validator/hooks.ts b/web/app/components/datasets/external-api/endpoint-validator/hooks.ts
deleted file mode 100644
index fe1b490320..0000000000
--- a/web/app/components/datasets/external-api/endpoint-validator/hooks.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import { useState } from 'react'
-import { useDebounceFn } from 'ahooks'
-import type { DebouncedFunc } from 'lodash-es'
-import { ValidatedEndpointStatus } from './declarations'
-import type { ValidateCallback, ValidateValue, ValidatedStatusState } from './declarations'
-
-export const useValidateEndpoint: (value: ValidateValue) => [DebouncedFunc<(validateCallback: ValidateCallback) => Promise>, boolean, ValidatedStatusState] = (value) => {
- const [validating, setValidating] = useState(false)
- const [validatedStatus, setValidatedStatus] = useState({})
-
- const { run } = useDebounceFn(async (validateCallback: ValidateCallback) => {
- if (!validateCallback.before(value)) {
- setValidating(false)
- setValidatedStatus({})
- return
- }
- setValidating(true)
-
- if (validateCallback.run) {
- const res = await validateCallback?.run(value)
- setValidatedStatus(
- res.status === 'success'
- ? { status: ValidatedEndpointStatus.Success }
- : { status: ValidatedEndpointStatus.Error, message: res.message })
-
- setValidating(false)
- }
- }, { wait: 1000 })
-
- return [run, validating, validatedStatus]
-}
diff --git a/web/app/components/datasets/external-api/external-api-modal/Form.tsx b/web/app/components/datasets/external-api/external-api-modal/Form.tsx
index 3a9ea2bc02..ada01493fe 100644
--- a/web/app/components/datasets/external-api/external-api-modal/Form.tsx
+++ b/web/app/components/datasets/external-api/external-api-modal/Form.tsx
@@ -1,6 +1,7 @@
import React, { useState } from 'react'
import type { FC } from 'react'
import { useTranslation } from 'react-i18next'
+import { RiBookOpenLine } from '@remixicon/react'
import type { CreateExternalAPIReq, FormSchema } from '../declarations'
import Input from '@/app/components/base/input'
import cn from '@/utils/classnames'
@@ -11,10 +12,6 @@ type FormProps = {
fieldLabelClassName?: string
value: CreateExternalAPIReq
onChange: (val: CreateExternalAPIReq) => void
- validatingEndpoint: boolean
- validatedApiKeySuccess?: boolean
- validatingApiKey: boolean
- validatedEndpointSuccess?: boolean
formSchemas: FormSchema[]
inputClassName?: string
}
@@ -26,10 +23,6 @@ const Form: FC = React.memo(({
value,
onChange,
formSchemas,
- validatingEndpoint,
- validatingApiKey,
- validatedApiKeySuccess,
- validatedEndpointSuccess,
inputClassName,
}) => {
const { t, i18n } = useTranslation()
@@ -57,10 +50,23 @@ const Form: FC = React.memo(({
return (
-
+
= ({ data, onSave, onCan
setFormData(data)
}, [isEditMode, data])
- const [, validatingApiKey, validatedApiKeyStatusState] = useValidateApiKey(formData.settings.api_key)
- const [, validatingEndpoint, validatedEndpointStatusState] = useValidateEndpoint(formData.settings.endpoint)
- const hasEmptyInputs = Object.values(formData).includes('')
+ const hasEmptyInputs = Object.values(formData).some(value =>
+ typeof value === 'string' ? value.trim() === '' : Object.values(value).some(v => v.trim() === ''),
+ )
const handleDataChange = (val: CreateExternalAPIReq) => {
setFormData(val)
}
const handleSave = async () => {
+ if (formData && formData.settings.api_key && formData.settings.api_key?.length < 5) {
+ notify({ type: 'error', message: t('common.apiBasedExtension.modal.apiKey.lengthError') })
+ setLoading(false)
+ return
+ }
try {
setLoading(true)
if (isEditMode && onEdit) {
- await onEdit(formData)
+ await onEdit(
+ {
+ ...formData,
+ settings: { ...formData.settings, api_key: formData.settings.api_key ? '[__HIDDEN__]' : formData.settings.api_key },
+ },
+ )
notify({ type: 'success', message: 'External API updated successfully' })
}
else {
@@ -154,10 +160,6 @@ const AddExternalAPIModal: FC
= ({ data, onSave, onCan
diff --git a/web/app/components/datasets/external-api/external-api-panel/index.tsx b/web/app/components/datasets/external-api/external-api-panel/index.tsx
index 5eb3218a8d..20d0768867 100644
--- a/web/app/components/datasets/external-api/external-api-panel/index.tsx
+++ b/web/app/components/datasets/external-api/external-api-panel/index.tsx
@@ -52,7 +52,7 @@ const ExternalAPIPanel: React.FC = ({ onClose, isShow, da
{t('dataset.externalAPIPanelTitle')}
{t('dataset.externalAPIPanelDescription')}
-
+
{t('dataset.externalAPIPanelDocumentation')}
diff --git a/web/app/components/datasets/external-api/key-validator/declarations.ts b/web/app/components/datasets/external-api/key-validator/declarations.ts
deleted file mode 100644
index 865bc6a23b..0000000000
--- a/web/app/components/datasets/external-api/key-validator/declarations.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-import type { Dispatch, SetStateAction } from 'react'
-
-export enum ValidatedApiKeyStatus {
- Success = 'success',
- Error = 'error',
-}
-
-export type ValidatedStatusState = {
- status?: ValidatedApiKeyStatus
- message?: string
-}
-
-export type Status = 'add' | 'fail' | 'success'
-
-export type ValidateValue = string
-
-export type ValidateCallback = {
- before: (v?: ValidateValue) => boolean | undefined
- run?: (v?: ValidateValue) => Promise
-}
-
-export type Form = {
- key: string
- title: string
- placeholder: string
- value?: string
- validate?: ValidateCallback
- handleFocus?: (v: ValidateValue, dispatch: Dispatch>) => void
-}
-
-export type KeyFrom = {
- text: string
- link: string
-}
-
-export type KeyValidatorProps = {
- type: string
- title: React.ReactNode
- status: Status
- forms: Form[]
- keyFrom: KeyFrom
-}
diff --git a/web/app/components/datasets/external-api/key-validator/hooks.ts b/web/app/components/datasets/external-api/key-validator/hooks.ts
deleted file mode 100644
index 324ef033ae..0000000000
--- a/web/app/components/datasets/external-api/key-validator/hooks.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import { useState } from 'react'
-import { useDebounceFn } from 'ahooks'
-import type { DebouncedFunc } from 'lodash-es'
-import { ValidatedApiKeyStatus } from './declarations'
-import type { ValidateCallback, ValidateValue, ValidatedStatusState } from './declarations'
-
-export const useValidateApiKey: (value: ValidateValue) => [DebouncedFunc<(validateCallback: ValidateCallback) => Promise>, boolean, ValidatedStatusState] = (value) => {
- const [validating, setValidating] = useState(false)
- const [validatedStatus, setValidatedStatus] = useState({})
-
- const { run } = useDebounceFn(async (validateCallback: ValidateCallback) => {
- if (!validateCallback.before(value)) {
- setValidating(false)
- setValidatedStatus({})
- return
- }
- setValidating(true)
-
- if (validateCallback.run) {
- const res = await validateCallback?.run(value)
- setValidatedStatus(
- res.status === 'success'
- ? { status: ValidatedApiKeyStatus.Success }
- : { status: ValidatedApiKeyStatus.Error, message: res.message })
-
- setValidating(false)
- }
- }, { wait: 1000 })
-
- return [run, validating, validatedStatus]
-}
diff --git a/web/app/components/datasets/external-knowledge-base/connector/index.tsx b/web/app/components/datasets/external-knowledge-base/connector/index.tsx
index 5d9ee263f3..b1a1ab9b3f 100644
--- a/web/app/components/datasets/external-knowledge-base/connector/index.tsx
+++ b/web/app/components/datasets/external-knowledge-base/connector/index.tsx
@@ -1,6 +1,7 @@
'use client'
import React, { useState } from 'react'
+import { useRouter } from 'next/navigation'
import { useToastContext } from '@/app/components/base/toast'
import ExternalKnowledgeBaseCreate from '@/app/components/datasets/external-knowledge-base/create'
import type { CreateKnowledgeBaseReq } from '@/app/components/datasets/external-knowledge-base/create/declarations'
@@ -9,18 +10,21 @@ import { createExternalKnowledgeBase } from '@/service/datasets'
const ExternalKnowledgeBaseConnector = () => {
const { notify } = useToastContext()
const [loading, setLoading] = useState(false)
+ const router = useRouter()
const handleConnect = async (formValue: CreateKnowledgeBaseReq) => {
try {
setLoading(true)
const result = await createExternalKnowledgeBase({ body: formValue })
- if (result && result.id)
+ if (result && result.id) {
notify({ type: 'success', message: 'External Knowledge Base Connected Successfully' })
- else
- throw new Error('Failed to create external knowledge base')
+ router.back()
+ }
+ else { throw new Error('Failed to create external knowledge base') }
}
catch (error) {
console.error('Error creating external knowledge base:', error)
+ notify({ type: 'error', message: 'Failed to connect External Knowledge Base' })
}
setLoading(false)
}
diff --git a/web/app/components/datasets/external-knowledge-base/create/InfoPanel.tsx b/web/app/components/datasets/external-knowledge-base/create/InfoPanel.tsx
index 8cd09aebab..bd32683c85 100644
--- a/web/app/components/datasets/external-knowledge-base/create/InfoPanel.tsx
+++ b/web/app/components/datasets/external-knowledge-base/create/InfoPanel.tsx
@@ -6,18 +6,22 @@ const InfoPanel = () => {
return (
-
-
+
+
{t('dataset.connectDatasetIntro.title')}
-
- {t('dataset.connectDatasetIntro.content')}
+
+ {t('dataset.connectDatasetIntro.content.front')}
+
+ {t('dataset.connectDatasetIntro.content.link')}
+
+ {t('dataset.connectDatasetIntro.content.end')}
-
+
{t('dataset.connectDatasetIntro.learnMore')}
diff --git a/web/app/components/datasets/external-knowledge-base/create/KnowledgeBaseInfo.tsx b/web/app/components/datasets/external-knowledge-base/create/KnowledgeBaseInfo.tsx
index 42ddebdfa3..ca2f93d7a6 100644
--- a/web/app/components/datasets/external-knowledge-base/create/KnowledgeBaseInfo.tsx
+++ b/web/app/components/datasets/external-knowledge-base/create/KnowledgeBaseInfo.tsx
@@ -42,14 +42,19 @@ const KnowledgeBaseInfo: React.FC
= ({ name, description
value={description}
onChange={ e => handleDescriptionChange(e)}
placeholder={t('dataset.externalKnowledgeDescriptionPlaceholder') ?? ''}
- className='flex h-20 p-2 self-stretch items-start rounded-lg bg-components-input-bg-normal text-components-input-text-placeholder system-sm-regular'
+ className={`flex h-20 p-2 self-stretch items-start rounded-lg bg-components-input-bg-normal ${description ? 'text-components-input-text-filled' : 'text-components-input-text-placeholder'} system-sm-regular`}
/>
-
+
diff --git a/web/app/components/datasets/external-knowledge-base/create/index.tsx b/web/app/components/datasets/external-knowledge-base/create/index.tsx
index 2952a098fb..e4b72e8d79 100644
--- a/web/app/components/datasets/external-knowledge-base/create/index.tsx
+++ b/web/app/components/datasets/external-knowledge-base/create/index.tsx
@@ -41,7 +41,7 @@ const ExternalKnowledgeBaseCreate: React.FC
=
setFormData(newData)
}
- const isFormValid = formData.name !== ''
+ const isFormValid = formData.name.trim() !== ''
&& formData.external_knowledge_api_id !== ''
&& formData.external_knowledge_id !== ''
&& formData.external_retrieval_model.top_k !== undefined
@@ -98,7 +98,6 @@ const ExternalKnowledgeBaseCreate: React.FC =
variant='primary'
onClick={() => {
onConnect(formData)
- navBackHandle()
}}
disabled={!isFormValid}
loading={loading}
diff --git a/web/app/components/datasets/hit-testing/hit-detail.tsx b/web/app/components/datasets/hit-testing/hit-detail.tsx
index a1c6b10e53..9d12ff4494 100644
--- a/web/app/components/datasets/hit-testing/hit-detail.tsx
+++ b/web/app/components/datasets/hit-testing/hit-detail.tsx
@@ -26,12 +26,12 @@ const HitDetail: FC = ({ segInfo }) => {
)
}
- return segInfo?.content
+ return {segInfo?.content}
}
return (
segInfo?.id === 'external'
- ?
+ ?
:
diff --git a/web/app/components/datasets/hit-testing/index.tsx b/web/app/components/datasets/hit-testing/index.tsx
index cb345f4fc2..33cf824b59 100644
--- a/web/app/components/datasets/hit-testing/index.tsx
+++ b/web/app/components/datasets/hit-testing/index.tsx
@@ -216,7 +216,7 @@ const HitTesting: FC
= ({ datasetId }: Props) => {
{
setCurrParagraph({ showModal: false })
diff --git a/web/app/components/workflow/nodes/knowledge-retrieval/components/dataset-item.tsx b/web/app/components/workflow/nodes/knowledge-retrieval/components/dataset-item.tsx
index 0369322783..f999240c0c 100644
--- a/web/app/components/workflow/nodes/knowledge-retrieval/components/dataset-item.tsx
+++ b/web/app/components/workflow/nodes/knowledge-retrieval/components/dataset-item.tsx
@@ -1,13 +1,15 @@
'use client'
import type { FC } from 'react'
-import React, { useCallback } from 'react'
+import React, { useCallback, useState } from 'react'
import { useBoolean } from 'ahooks'
import {
RiDeleteBinLine,
RiEditLine,
} from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
import type { DataSet } from '@/models/datasets'
import { DataSourceType } from '@/models/datasets'
+import ActionButton, { ActionButtonState } from '@/app/components/base/action-button'
import FileIcon from '@/app/components/base/file-icon'
import { Folder } from '@/app/components/base/icons/src/vender/solid/files'
import SettingsModal from '@/app/components/app/configuration/dataset-config/settings-modal'
@@ -30,8 +32,10 @@ const DatasetItem: FC = ({
readonly,
}) => {
const media = useBreakpoints()
+ const { t } = useTranslation()
const isMobile = media === MediaType.mobile
const { formatIndexingTechniqueAndMethod } = useKnowledge()
+ const [isDeleteHovered, setIsDeleteHovered] = useState(false)
const [isShowSettingsModal, {
setTrue: showSettingsModal,
@@ -44,7 +48,12 @@ const DatasetItem: FC = ({
}, [hideSettingsModal, onChange])
return (
-
+
{
payload.data_source_type === DataSourceType.NOTION
@@ -61,24 +70,33 @@ const DatasetItem: FC
= ({
{!readonly && (
-
-
-
-
+
+
setIsDeleteHovered(true)}
+ onMouseLeave={() => setIsDeleteHovered(false)}
>
-
-
+
+
)}
-
+ {
+ payload.indexing_technique &&
+ }
+ {
+ payload.provider === 'external' &&
+ }
{isShowSettingsModal && (
diff --git a/web/app/components/workflow/nodes/knowledge-retrieval/utils.ts b/web/app/components/workflow/nodes/knowledge-retrieval/utils.ts
index 89ae9b4764..85ae6c4c96 100644
--- a/web/app/components/workflow/nodes/knowledge-retrieval/utils.ts
+++ b/web/app/components/workflow/nodes/knowledge-retrieval/utils.ts
@@ -21,6 +21,9 @@ export const getSelectedDatasetsMode = (datasets: DataSet[]) => {
let allHighQualityFullTextSearch = true
let allEconomic = true
let mixtureHighQualityAndEconomic = true
+ let allExternal = true
+ let allInternal = true
+ let mixtureInternalAndExternal = true
let inconsistentEmbeddingModel = false
if (!datasets.length) {
allHighQuality = false
@@ -29,6 +32,9 @@ export const getSelectedDatasetsMode = (datasets: DataSet[]) => {
allEconomic = false
mixtureHighQualityAndEconomic = false
inconsistentEmbeddingModel = false
+ allExternal = false
+ allInternal = false
+ mixtureInternalAndExternal = false
}
datasets.forEach((dataset) => {
if (dataset.indexing_technique === 'economy') {
@@ -45,8 +51,21 @@ export const getSelectedDatasetsMode = (datasets: DataSet[]) => {
if (dataset.retrieval_model_dict.search_method !== RETRIEVE_METHOD.fullText)
allHighQualityFullTextSearch = false
}
+ if (dataset.provider !== 'external') {
+ allExternal = false
+ }
+ else {
+ allInternal = false
+ allHighQuality = false
+ allHighQualityVectorSearch = false
+ allHighQualityFullTextSearch = false
+ mixtureHighQualityAndEconomic = false
+ }
})
+ if (allExternal || allInternal)
+ mixtureInternalAndExternal = false
+
if (allHighQuality || allEconomic)
mixtureHighQualityAndEconomic = false
@@ -59,6 +78,9 @@ export const getSelectedDatasetsMode = (datasets: DataSet[]) => {
allHighQualityFullTextSearch,
allEconomic,
mixtureHighQualityAndEconomic,
+ allInternal,
+ allExternal,
+ mixtureInternalAndExternal,
inconsistentEmbeddingModel,
} as SelectedDatasetsMode
}
@@ -70,6 +92,9 @@ export const getMultipleRetrievalConfig = (multipleRetrievalConfig: MultipleRetr
allHighQualityFullTextSearch,
allEconomic,
mixtureHighQualityAndEconomic,
+ allInternal,
+ allExternal,
+ mixtureInternalAndExternal,
inconsistentEmbeddingModel,
} = getSelectedDatasetsMode(selectedDatasets)
@@ -91,13 +116,13 @@ export const getMultipleRetrievalConfig = (multipleRetrievalConfig: MultipleRetr
reranking_enable: allEconomic ? reranking_enable : true,
}
- if (allEconomic || mixtureHighQualityAndEconomic || inconsistentEmbeddingModel)
+ if (allEconomic || mixtureHighQualityAndEconomic || inconsistentEmbeddingModel || allExternal || mixtureInternalAndExternal)
result.reranking_mode = RerankingModeEnum.RerankingModel
- if (allHighQuality && !inconsistentEmbeddingModel && reranking_mode === undefined)
+ if (allHighQuality && !inconsistentEmbeddingModel && reranking_mode === undefined && allInternal)
result.reranking_mode = RerankingModeEnum.WeightedScore
- if (allHighQuality && !inconsistentEmbeddingModel && (reranking_mode === RerankingModeEnum.WeightedScore || reranking_mode === undefined) && !weights) {
+ if (allHighQuality && !inconsistentEmbeddingModel && (reranking_mode === RerankingModeEnum.WeightedScore || reranking_mode === undefined) && allInternal && !weights) {
result.weights = {
vector_setting: {
vector_weight: allHighQualityVectorSearch
diff --git a/web/i18n/en-US/dataset.ts b/web/i18n/en-US/dataset.ts
index f471cf23c1..6ad68ff8e5 100644
--- a/web/i18n/en-US/dataset.ts
+++ b/web/i18n/en-US/dataset.ts
@@ -1,5 +1,6 @@
const translation = {
knowledge: 'Knowledge',
+ externalTag: 'External',
externalAPI: 'External API',
externalAPIPanelTitle: 'External Knowledge API',
externalKnowledgeId: 'External Knowledge ID',
@@ -10,7 +11,7 @@ const translation = {
externalKnowledgeDescriptionPlaceholder: 'Describe what\'s in this Knowledge Base (optional)',
learnHowToWriteGoodKnowledgeDescription: 'Learn how to write a good knowledge description',
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',
+ externalAPIPanelDocumentation: 'Learn how to create an External Knowledge API',
documentCount: ' docs',
wordCount: ' k words',
appCount: ' linked apps',
@@ -40,7 +41,11 @@ const translation = {
connectDataset: 'Connect to an External Knowledge Base',
connectDatasetIntro: {
title: 'How to Connect to an External Knowledge Base',
- content: 'To connect to an external knowledge base, you need to create an external API first. Please read carefully and refer to learn how to create an external API. Then find the corresponding knowledge ID and fill it in the form on the left. If all the information is correct, it will automatically jump to the retrieval test in the knowledge base after clicking the connect button.',
+ content: {
+ front: 'To connect to an external knowledge base, you need to create an external API first. Please read carefully and refer to',
+ link: 'Learn how to create an external API',
+ end: '. Then find the corresponding knowledge ID and fill it in the form on the left. If all the information is correct, it will automatically jump to the retrieval test in the knowledge base after clicking the connect button.',
+ },
learnMore: 'Learn More',
},
createDatasetIntro: 'Import your own text data or write data in real-time via Webhook for LLM context enhancement.',
@@ -113,6 +118,8 @@ const translation = {
defaultRetrievalTip: 'Multi-path retrieval is used by default. Knowledge is retrieved from multiple knowledge bases and then re-ranked.',
mixtureHighQualityAndEconomicTip: 'The Rerank model is required for mixture of high quality and economical knowledge bases.',
inconsistentEmbeddingModelTip: 'The Rerank model is required if the Embedding models of the selected knowledge bases are inconsistent.',
+ mixtureInternalAndExternalTip: 'The Rerank model is required for mixture of internal and external knowledge.',
+ allExternalTip: 'When using external knowledge only, the user can choose whether to enable the Rerank model. If not enabled, retrieved chunks will be sorted based on scores. When the retrieval strategies of different knowledge bases are inconsistent, it will be inaccurate.',
retrievalSettings: 'Retrieval Setting',
rerankSettings: 'Rerank Setting',
weightedScore: {
diff --git a/web/i18n/zh-Hans/dataset.ts b/web/i18n/zh-Hans/dataset.ts
index 3df97e9cf0..5b8616c402 100644
--- a/web/i18n/zh-Hans/dataset.ts
+++ b/web/i18n/zh-Hans/dataset.ts
@@ -1,5 +1,6 @@
const translation = {
knowledge: '知识库',
+ externalTag: '外部',
externalAPI: '外部 API',
externalAPIPanelTitle: '外部知识库 API',
externalKnowledgeId: '外部知识库 ID',
@@ -10,7 +11,7 @@ const translation = {
externalKnowledgeDescriptionPlaceholder: '描述知识库内容(可选)',
learnHowToWriteGoodKnowledgeDescription: '了解如何编写良好的知识库描述',
externalAPIPanelDescription: '外部知识库 API 用于连接到 Dify 之外的知识库并从中检索知识。',
- externalAPIPanelDocumentation: '了解如何创建外部 API',
+ externalAPIPanelDocumentation: '了解如何创建外部知识库 API',
documentCount: ' 文档',
wordCount: ' 千字符',
appCount: ' 关联应用',
@@ -39,7 +40,11 @@ const translation = {
},
connectDatasetIntro: {
title: '如何连接到外部知识库',
- content: '要连接到外部知识库,您需要先创建一个外部 API。请仔细阅读并参考如何创建外部 API。然后找到相应的知识 ID 并将其填写在左侧表单中。如果所有信息都正确,点击连接按钮后会自动跳转到知识库的检索测试。',
+ content: {
+ front: '要连接到外部知识库,您需要先创建一个外部 API。请仔细阅读并参考',
+ link: '了解如何创建外部 API',
+ end: '。然后找到相应的知识库 ID 并填写在左侧表单中。如果所有信息正确,点击连接按钮后将自动跳转到知识库中的检索测试。',
+ },
learnMore: '了解更多',
},
connectDataset: '连接外部知识库',
@@ -113,6 +118,8 @@ const translation = {
defaultRetrievalTip: '默认情况下使用多路召回。从多个知识库中检索知识,然后重新排序。',
mixtureHighQualityAndEconomicTip: '混合使用高质量和经济型知识库需要配置 Rerank 模型。',
inconsistentEmbeddingModelTip: '当所选知识库配置的 Embedding 模型不一致时,需要配置 Rerank 模型。',
+ mixtureInternalAndExternalTip: '混合使用内部和外部知识时需要配置 Rerank 模型。',
+ allExternalTip: '仅使用外部知识时,用户可以选择是否启用 Rerank 模型。如果不启用,检索到的文本块将根据分数排序。当不同知识库的检索策略不一致时,结果可能不准确。',
retrievalSettings: '召回设置',
rerankSettings: 'Rerank 设置',
weightedScore: {
diff --git a/web/models/datasets.ts b/web/models/datasets.ts
index 5edf2e7e69..9930728df9 100644
--- a/web/models/datasets.ts
+++ b/web/models/datasets.ts
@@ -538,6 +538,9 @@ export type SelectedDatasetsMode = {
allHighQualityFullTextSearch: boolean
allEconomic: boolean
mixtureHighQualityAndEconomic: boolean
+ allInternal: boolean
+ allExternal: boolean
+ mixtureInternalAndExternal: boolean
inconsistentEmbeddingModel: boolean
}