feat: knowledge base node

This commit is contained in:
zxhlyh 2025-05-07 15:08:13 +08:00
parent e86a3fc672
commit 3f52f491d7
15 changed files with 417 additions and 187 deletions

View File

@ -1,4 +1,5 @@
import type { ReactNode } from 'react'
import { memo } from 'react'
import cn from '@/utils/classnames'
export type BoxProps = {
@ -6,7 +7,7 @@ export type BoxProps = {
children?: ReactNode
withBorderBottom?: boolean
}
export const Box = ({
export const Box = memo(({
className,
children,
withBorderBottom,
@ -21,4 +22,4 @@ export const Box = ({
{children}
</div>
)
}
})

View File

@ -1,4 +1,5 @@
import type { ReactNode } from 'react'
import { memo } from 'react'
import Tooltip from '@/app/components/base/tooltip'
import cn from '@/utils/classnames'
@ -8,7 +9,7 @@ export type FieldTitleProps = {
subTitle?: string | ReactNode
tooltip?: string
}
export const FieldTitle = ({
export const FieldTitle = memo(({
title,
operation,
subTitle,
@ -35,4 +36,4 @@ export const FieldTitle = ({
}
</div>
)
}
})

View File

@ -1,4 +1,5 @@
import type { ReactNode } from 'react'
import { memo } from 'react'
import type { FieldTitleProps } from '.'
import { FieldTitle } from '.'
@ -6,7 +7,7 @@ export type FieldProps = {
fieldTitleProps: FieldTitleProps
children: ReactNode
}
export const Field = ({
export const Field = memo(({
fieldTitleProps,
children,
}: FieldProps) => {
@ -16,4 +17,4 @@ export const Field = ({
{children}
</div>
)
}
})

View File

@ -1,4 +1,5 @@
import type { ReactNode } from 'react'
import { memo } from 'react'
import {
Box,
Group,
@ -13,7 +14,7 @@ type GroupWithBoxProps = {
boxProps?: Omit<BoxProps, 'children'>
groupProps?: Omit<GroupProps, 'children'>
}
export const GroupWithBox = ({
export const GroupWithBox = memo(({
children,
boxProps,
groupProps,
@ -25,4 +26,4 @@ export const GroupWithBox = ({
</Group>
</Box>
)
}
})

View File

@ -1,4 +1,5 @@
import type { ReactNode } from 'react'
import { memo } from 'react'
import cn from '@/utils/classnames'
export type GroupProps = {
@ -6,7 +7,7 @@ export type GroupProps = {
children?: ReactNode
withBorderBottom?: boolean
}
export const Group = ({
export const Group = memo(({
className,
children,
withBorderBottom,
@ -21,4 +22,4 @@ export const Group = ({
{children}
</div>
)
}
})

View File

@ -1,13 +1,45 @@
import ModelParameterModal from '@/app/components/header/account-setting/model-provider-page/model-parameter-modal'
import {
memo,
useMemo,
} from 'react'
import { Field } from '@/app/components/workflow/nodes/_base/components/layout'
import ModelSelector from '@/app/components/header/account-setting/model-provider-page/model-selector'
import { useModelListAndDefaultModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
import type { DefaultModel } from '@/app/components/header/account-setting/model-provider-page/declarations'
import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
const EmbeddingModel = () => {
const handleModelChange = () => {
console.log('Model changed')
}
const handleCompletionParamsChange = () => {
console.log('Completion parameters changed')
type EmbeddingModelProps = {
embeddingModel?: string
embeddingModelProvider?: string
onEmbeddingModelChange?: (model: {
embeddingModel: string
embeddingModelProvider: string
}) => void
}
const EmbeddingModel = ({
embeddingModel,
embeddingModelProvider,
onEmbeddingModelChange,
}: EmbeddingModelProps) => {
const {
modelList: embeddingModelList,
} = useModelListAndDefaultModel(ModelTypeEnum.textEmbedding)
const embeddingModelConfig = useMemo(() => {
if (!embeddingModel || !embeddingModelProvider)
return undefined
return {
providerName: embeddingModelProvider,
modelName: embeddingModel,
}
}, [embeddingModel, embeddingModelProvider])
const handleRerankingModelChange = (model: DefaultModel) => {
onEmbeddingModelChange?.({
embeddingModelProvider: model.provider,
embeddingModel: model.model,
})
}
return (
<Field
@ -15,20 +47,12 @@ const EmbeddingModel = () => {
title: 'Embedding Model',
}}
>
<ModelParameterModal
popupClassName='!w-[387px]'
isInWorkflow
isAdvancedMode={true}
mode={'embedding'}
provider={'openai'}
completionParams={{}}
modelId={'text-embedding-ada-002'}
setModel={handleModelChange}
onCompletionParamsChange={handleCompletionParamsChange}
hideDebugWithMultipleModel
debugWithMultipleModel={false}
<ModelSelector
defaultModel={embeddingModelConfig && { provider: embeddingModelConfig.providerName, model: embeddingModelConfig.modelName }}
modelList={embeddingModelList}
onSelect={handleRerankingModelChange}
/>
</Field>
)
}
export default EmbeddingModel
export default memo(EmbeddingModel)

View File

@ -1,7 +1,8 @@
import { memo } from 'react'
import VarReferencePicker from '@/app/components/workflow/nodes/_base/components/variable/var-reference-picker'
import { Field } from '@/app/components/workflow/nodes/_base/components/layout'
const EmbeddingModel = () => {
const InputVariable = () => {
const handleChange = () => {
console.log('')
}
@ -23,4 +24,4 @@ const EmbeddingModel = () => {
</Field>
)
}
export default EmbeddingModel
export default memo(InputVariable)

View File

@ -1,3 +1,4 @@
import { useMemo } from 'react'
import {
FullTextSearch,
HybridSearch,
@ -13,53 +14,64 @@ import type {
} from './type'
export const useRetrievalSetting = () => {
const VectorSearchOption: Option = {
id: RetrievalSearchMethodEnum.semantic,
icon: VectorSearch as any,
title: 'Vector Search',
description: 'Generate query embeddings and search for the text chunk most similar to its vector representation.',
effectColor: 'purple',
}
const FullTextSearchOption: Option = {
id: RetrievalSearchMethodEnum.fullText,
icon: FullTextSearch as any,
title: 'Full-Text Search',
description: 'Execute full-text search and vector searches simultaneously, re-rank to select the best match for the user\'s query. Users can choose to set weights or configure to a Rerank model.',
effectColor: 'purple',
}
const HybridSearchOption: Option = {
id: RetrievalSearchMethodEnum.hybrid,
icon: HybridSearch as any,
title: 'Hybrid Search',
description: 'Execute full-text search and vector searches simultaneously, re-rank to select the best match for the user\'s query. Users can choose to set weights or configure to a Rerank model.',
effectColor: 'purple',
}
const VectorSearchOption: Option = useMemo(() => {
return {
id: RetrievalSearchMethodEnum.semantic,
icon: VectorSearch as any,
title: 'Vector Search',
description: 'Generate query embeddings and search for the text chunk most similar to its vector representation.',
effectColor: 'purple',
}
}, [])
const FullTextSearchOption: Option = useMemo(() => {
return {
id: RetrievalSearchMethodEnum.fullText,
icon: FullTextSearch as any,
title: 'Full-Text Search',
description: 'Execute full-text search and vector searches simultaneously, re-rank to select the best match for the user\'s query. Users can choose to set weights or configure to a Rerank model.',
effectColor: 'purple',
}
}, [])
const HybridSearchOption: Option = useMemo(() => {
return {
id: RetrievalSearchMethodEnum.hybrid,
icon: HybridSearch as any,
title: 'Hybrid Search',
description: 'Execute full-text search and vector searches simultaneously, re-rank to select the best match for the user\'s query. Users can choose to set weights or configure to a Rerank model.',
effectColor: 'purple',
}
}, [])
const options = [
const WeightedScoreModeOption: HybridSearchModeOption = useMemo(() => {
return {
id: HybridSearchModeEnum.WeightedScore,
title: 'Weighted Score',
description: 'By adjusting the weights assigned, this rerank strategy determines whether to prioritize semantic or keyword matching.',
}
}, [])
const RerankModelModeOption: HybridSearchModeOption = useMemo(() => {
return {
id: HybridSearchModeEnum.RerankingModel,
title: 'Rerank Model',
description: 'Rerank model will reorder the candidate document list based on the semantic match with user query, improving the results of semantic ranking.',
}
}, [])
return useMemo(() => ({
options: [
VectorSearchOption,
FullTextSearchOption,
HybridSearchOption,
],
hybridSearchModeOptions: [
WeightedScoreModeOption,
RerankModelModeOption,
],
}), [
VectorSearchOption,
FullTextSearchOption,
HybridSearchOption,
]
const WeightedScoreModeOption: HybridSearchModeOption = {
id: HybridSearchModeEnum.WeightedScore,
title: 'Weighted Score',
description: 'By adjusting the weights assigned, this rerank strategy determines whether to prioritize semantic or keyword matching.',
}
const RerankModelModeOption: HybridSearchModeOption = {
id: HybridSearchModeEnum.RerankingModel,
title: 'Rerank Model',
description: 'Rerank model will reorder the candidate document list based on the semantic match with user query, improving the results of semantic ranking.',
}
const hybridSearchModeOptions = [
WeightedScoreModeOption,
RerankModelModeOption,
]
return {
options,
hybridSearchModeOptions,
}
])
}

View File

@ -1,35 +1,28 @@
import {
memo,
useCallback,
} from 'react'
import { Field } from '@/app/components/workflow/nodes/_base/components/layout'
import cn from '@/utils/classnames'
import WeightedScoreComponent from '@/app/components/app/configuration/dataset-config/params-config/weighted-score'
import { DEFAULT_WEIGHTED_SCORE } from '@/models/datasets'
import {
import type {
HybridSearchModeEnum,
RetrievalSearchMethodEnum,
} from '../../types'
import type {
RerankingModel,
WeightedScore,
} from '../../types'
import OptionCard from '../option-card'
import { useRetrievalSetting } from './hooks'
import type { Option } from './type'
import TopKAndScoreThreshold from './top-k-and-score-threshold'
import RerankingModelSelector from './reranking-model-selector'
import type { TopKAndScoreThresholdProps } from './top-k-and-score-threshold'
import type { RerankingModelSelectorProps } from './reranking-model-selector'
import SearchMethodOption from './search-method-option'
type RetrievalSettingProps = {
searchMethod: RetrievalSearchMethodEnum
onRetrievalSearchMethodChange: (value: RetrievalSearchMethodEnum) => void
hybridSearchMode: HybridSearchModeEnum
onHybridSearchModeChange: (value: HybridSearchModeEnum) => void
rerankingModel?: RerankingModel
onRerankingModelChange: (model: RerankingModel) => void
weightedScore?: WeightedScore
onWeightedScoreChange: (value: { value: number[] }) => void
}
} & RerankingModelSelectorProps & TopKAndScoreThresholdProps
const RetrievalSetting = ({
searchMethod,
onRetrievalSearchMethodChange,
@ -39,101 +32,18 @@ const RetrievalSetting = ({
onWeightedScoreChange,
rerankingModel,
onRerankingModelChange,
topK,
onTopKChange,
scoreThreshold,
onScoreThresholdChange,
isScoreThresholdEnabled,
onScoreThresholdEnabledChange,
}: RetrievalSettingProps) => {
const {
options,
hybridSearchModeOptions,
} = useRetrievalSetting()
const renderOptionCard = useCallback((option: Option) => {
const Icon = option.icon
const isActive = searchMethod === option.id
const isHybridSearch = searchMethod === RetrievalSearchMethodEnum.hybrid
const isHybridSearchWeightedScoreMode = hybridSearchMode === HybridSearchModeEnum.WeightedScore
const weightedScoreValue = (() => {
const sematicWeightedScore = weightedScore?.vector_setting.vector_weight ?? DEFAULT_WEIGHTED_SCORE.other.semantic
const keywordWeightedScore = weightedScore?.keyword_setting.keyword_weight ?? DEFAULT_WEIGHTED_SCORE.other.keyword
const mergedValue = [sematicWeightedScore, keywordWeightedScore]
return {
value: mergedValue,
}
})()
return (
<OptionCard
key={option.id}
id={option.id}
icon={
<Icon
className={cn(
'h-[15px] w-[15px] text-text-tertiary',
isActive && 'text-util-colors-purple-purple-600',
)}
/>
}
title={option.title}
description={option.description}
effectColor={option.effectColor}
isRecommended={option.id === RetrievalSearchMethodEnum.hybrid}
onClick={onRetrievalSearchMethodChange}
showChildren={isActive}
showHighlightBorder={isActive}
showEffectColor={isActive}
>
<div className='space-y-3'>
{
isHybridSearch && (
<div className='space-y-1'>
{
hybridSearchModeOptions.map(hybridOption => (
<OptionCard
key={hybridOption.id}
id={hybridOption.id}
className='p-3'
title={hybridOption.title}
description={hybridOption.description}
showRadio
radioIsActive={hybridOption.id === hybridSearchMode}
onClick={onHybridSearchModeChange}
/>
))
}
</div>
)
}
{
isHybridSearch && isHybridSearchWeightedScoreMode && (
<WeightedScoreComponent
value={weightedScoreValue}
onChange={onWeightedScoreChange}
/>
)
}
{
!(isHybridSearch && hybridSearchMode === HybridSearchModeEnum.WeightedScore) && (
<RerankingModelSelector
rerankingModel={rerankingModel}
onRerankingModelChange={onRerankingModelChange}
/>
)
}
<TopKAndScoreThreshold />
</div>
</OptionCard>
)
}, [
searchMethod,
onRetrievalSearchMethodChange,
hybridSearchModeOptions,
hybridSearchMode,
onHybridSearchModeChange,
rerankingModel,
onRerankingModelChange,
weightedScore,
onWeightedScoreChange,
])
return (
<Field
fieldTitleProps={{
@ -154,7 +64,29 @@ const RetrievalSetting = ({
}}
>
<div className='space-y-1'>
{options.map(renderOptionCard)}
{
options.map(option => (
<SearchMethodOption
key={option.id}
option={option}
hybridSearchModeOptions={hybridSearchModeOptions}
searchMethod={searchMethod}
onRetrievalSearchMethodChange={onRetrievalSearchMethodChange}
hybridSearchMode={hybridSearchMode}
onHybridSearchModeChange={onHybridSearchModeChange}
weightedScore={weightedScore}
onWeightedScoreChange={onWeightedScoreChange}
topK={topK}
onTopKChange={onTopKChange}
scoreThreshold={scoreThreshold}
onScoreThresholdChange={onScoreThresholdChange}
isScoreThresholdEnabled={isScoreThresholdEnabled}
onScoreThresholdEnabledChange={onScoreThresholdEnabledChange}
rerankingModel={rerankingModel}
onRerankingModelChange={onRerankingModelChange}
/>
))
}
</div>
</Field>
)

View File

@ -8,7 +8,7 @@ import type { DefaultModel } from '@/app/components/header/account-setting/model
import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
import type { RerankingModel } from '../../types'
type RerankingModelSelectorProps = {
export type RerankingModelSelectorProps = {
rerankingModel?: RerankingModel
onRerankingModelChange?: (model: RerankingModel) => void
}
@ -24,8 +24,8 @@ const RerankingModelSelector = ({
return undefined
return {
provider_name: rerankingModel.reranking_provider_name,
model_name: rerankingModel.reranking_model_name,
providerName: rerankingModel.reranking_provider_name,
modelName: rerankingModel.reranking_model_name,
}
}, [rerankingModel])
@ -38,7 +38,7 @@ const RerankingModelSelector = ({
return (
<ModelSelector
defaultModel={rerankModel && { provider: rerankModel.provider_name, model: rerankModel.model_name }}
defaultModel={rerankModel && { provider: rerankModel.providerName, model: rerankModel.modelName }}
modelList={rerankModelList}
onSelect={handleRerankingModelChange}
/>

View File

@ -0,0 +1,143 @@
import {
memo,
useMemo,
} from 'react'
import cn from '@/utils/classnames'
import WeightedScoreComponent from '@/app/components/app/configuration/dataset-config/params-config/weighted-score'
import { DEFAULT_WEIGHTED_SCORE } from '@/models/datasets'
import {
HybridSearchModeEnum,
RetrievalSearchMethodEnum,
} from '../../types'
import type {
WeightedScore,
} from '../../types'
import OptionCard from '../option-card'
import type {
HybridSearchModeOption,
Option,
} from './type'
import type { TopKAndScoreThresholdProps } from './top-k-and-score-threshold'
import TopKAndScoreThreshold from './top-k-and-score-threshold'
import type { RerankingModelSelectorProps } from './reranking-model-selector'
import RerankingModelSelector from './reranking-model-selector'
type SearchMethodOptionProps = {
option: Option
hybridSearchModeOptions: HybridSearchModeOption[]
searchMethod: RetrievalSearchMethodEnum
onRetrievalSearchMethodChange: (value: RetrievalSearchMethodEnum) => void
hybridSearchMode: HybridSearchModeEnum
onHybridSearchModeChange: (value: HybridSearchModeEnum) => void
weightedScore?: WeightedScore
onWeightedScoreChange: (value: { value: number[] }) => void
} & RerankingModelSelectorProps & TopKAndScoreThresholdProps
const SearchMethodOption = ({
option,
hybridSearchModeOptions,
searchMethod,
onRetrievalSearchMethodChange,
hybridSearchMode,
onHybridSearchModeChange,
weightedScore,
onWeightedScoreChange,
rerankingModel,
onRerankingModelChange,
topK,
onTopKChange,
scoreThreshold,
onScoreThresholdChange,
isScoreThresholdEnabled,
onScoreThresholdEnabledChange,
}: SearchMethodOptionProps) => {
const Icon = option.icon
const isActive = searchMethod === option.id
const isHybridSearch = option.id === RetrievalSearchMethodEnum.hybrid
const isHybridSearchWeightedScoreMode = hybridSearchMode === HybridSearchModeEnum.WeightedScore
const weightedScoreValue = useMemo(() => {
const sematicWeightedScore = weightedScore?.vector_setting.vector_weight ?? DEFAULT_WEIGHTED_SCORE.other.semantic
const keywordWeightedScore = weightedScore?.keyword_setting.keyword_weight ?? DEFAULT_WEIGHTED_SCORE.other.keyword
const mergedValue = [sematicWeightedScore, keywordWeightedScore]
return {
value: mergedValue,
}
}, [weightedScore])
const icon = useMemo(() => {
return (
<Icon
className={cn(
'h-[15px] w-[15px] text-text-tertiary',
isActive && 'text-util-colors-purple-purple-600',
)}
/>
)
}, [isActive, Icon])
return (
<OptionCard
key={option.id}
id={option.id}
icon={icon}
title={option.title}
description={option.description}
effectColor={option.effectColor}
isRecommended={option.id === RetrievalSearchMethodEnum.hybrid}
onClick={onRetrievalSearchMethodChange}
showChildren={isActive}
showHighlightBorder={isActive}
showEffectColor={isActive}
>
<div className='space-y-3'>
{
isHybridSearch && (
<div className='space-y-1'>
{
hybridSearchModeOptions.map(hybridOption => (
<OptionCard
key={hybridOption.id}
id={hybridOption.id}
className='p-3'
title={hybridOption.title}
description={hybridOption.description}
showRadio
radioIsActive={hybridOption.id === hybridSearchMode}
onClick={onHybridSearchModeChange}
/>
))
}
</div>
)
}
{
isHybridSearch && isHybridSearchWeightedScoreMode && (
<WeightedScoreComponent
value={weightedScoreValue}
onChange={onWeightedScoreChange}
/>
)
}
{
!(isHybridSearch && hybridSearchMode === HybridSearchModeEnum.WeightedScore) && (
<RerankingModelSelector
rerankingModel={rerankingModel}
onRerankingModelChange={onRerankingModelChange}
/>
)
}
<TopKAndScoreThreshold
topK={topK}
onTopKChange={onTopKChange}
scoreThreshold={scoreThreshold}
onScoreThresholdChange={onScoreThresholdChange}
isScoreThresholdEnabled={isScoreThresholdEnabled}
onScoreThresholdEnabledChange={onScoreThresholdEnabledChange}
/>
</div>
</OptionCard>
)
}
export default memo(SearchMethodOption)

View File

@ -3,7 +3,36 @@ import Tooltip from '@/app/components/base/tooltip'
import Input from '@/app/components/base/input'
import Switch from '@/app/components/base/switch'
const TopKAndScoreThreshold = () => {
export type TopKAndScoreThresholdProps = {
topK: number
onTopKChange: (value: number) => void
scoreThreshold?: number
onScoreThresholdChange?: (value: number) => void
isScoreThresholdEnabled?: boolean
onScoreThresholdEnabledChange?: (value: boolean) => void
}
const TopKAndScoreThreshold = ({
topK,
onTopKChange,
scoreThreshold,
onScoreThresholdChange,
isScoreThresholdEnabled,
onScoreThresholdEnabledChange,
}: TopKAndScoreThresholdProps) => {
const handleTopKChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = Number(e.target.value)
if (Number.isNaN(value))
return
onTopKChange?.(value)
}
const handleScoreThresholdChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = Number(e.target.value)
if (Number.isNaN(value))
return
onScoreThresholdChange?.(value)
}
return (
<div className='grid grid-cols-2 gap-4'>
<div>
@ -16,12 +45,16 @@ const TopKAndScoreThreshold = () => {
</div>
<Input
type='number'
value={topK}
onChange={handleTopKChange}
/>
</div>
<div>
<div className='mb-0.5 flex h-6 items-center'>
<Switch
className='mr-2'
defaultValue={isScoreThresholdEnabled}
onChange={onScoreThresholdEnabledChange}
/>
<div className='system-sm-medium grow truncate text-text-secondary'>
Score Threshold
@ -33,6 +66,8 @@ const TopKAndScoreThreshold = () => {
</div>
<Input
type='number'
value={scoreThreshold}
onChange={handleScoreThresholdChange}
/>
</div>
</div>

View File

@ -42,6 +42,28 @@ export const useConfig = (id: string) => {
handleNodeDataUpdate({ keyword_number: keywordNumber })
}, [handleNodeDataUpdate])
const handleEmbeddingModelChange = useCallback(({
embeddingModel,
embeddingModelProvider,
}: {
embeddingModel: string
embeddingModelProvider: string
}) => {
const nodeData = getNodeData()
handleNodeDataUpdate({
embedding_model: embeddingModel,
embedding_model_provider: embeddingModelProvider,
retrieval_model: {
...nodeData?.data.retrieval_model,
vector_setting: {
...nodeData?.data.retrieval_model.vector_setting,
embedding_provider_name: embeddingModelProvider,
embedding_model_name: embeddingModel,
},
},
})
}, [getNodeData, handleNodeDataUpdate])
const handleRetrievalSearchMethodChange = useCallback((searchMethod: RetrievalSearchMethodEnum) => {
const nodeData = getNodeData()
handleNodeDataUpdate({
@ -95,13 +117,47 @@ export const useConfig = (id: string) => {
})
}, [getNodeData, handleNodeDataUpdate])
const handleTopKChange = useCallback((topK: number) => {
const nodeData = getNodeData()
handleNodeDataUpdate({
retrieval_model: {
...nodeData?.data.retrieval_model,
top_k: topK,
},
})
}, [getNodeData, handleNodeDataUpdate])
const handleScoreThresholdChange = useCallback((scoreThreshold: number) => {
const nodeData = getNodeData()
handleNodeDataUpdate({
retrieval_model: {
...nodeData?.data.retrieval_model,
score_threshold: scoreThreshold,
},
})
}, [getNodeData, handleNodeDataUpdate])
const handleScoreThresholdEnabledChange = useCallback((isEnabled: boolean) => {
const nodeData = getNodeData()
handleNodeDataUpdate({
retrieval_model: {
...nodeData?.data.retrieval_model,
score_threshold_enabled: isEnabled,
},
})
}, [getNodeData, handleNodeDataUpdate])
return {
handleChunkStructureChange,
handleIndexMethodChange,
handleKeywordNumberChange,
handleEmbeddingModelChange,
handleRetrievalSearchMethodChange,
handleHybridSearchModeChange,
handleWeighedScoreChange,
handleRerankingModelChange,
handleTopKChange,
handleScoreThresholdChange,
handleScoreThresholdEnabledChange,
}
}

View File

@ -2,10 +2,18 @@ import type { FC } from 'react'
import { memo } from 'react'
import type { KnowledgeBaseNodeType } from './types'
import type { NodeProps } from '@/app/components/workflow/types'
const Node: FC<NodeProps<KnowledgeBaseNodeType>> = () => {
const Node: FC<NodeProps<KnowledgeBaseNodeType>> = ({ data }) => {
return (
<div className='mb-1 px-3 py-1'>
KnowledgeBase
<div className='mb-1 space-y-0.5 px-3 py-1'>
<div className='flex h-6 items-center rounded-md bg-workflow-block-parma-bg px-1.5'>
<div className='system-xs-medium-uppercase mr-2 shrink-0 text-text-tertiary'>Index method</div>
<div className='system-xs-medium grow truncate text-right text-text-secondary' title={data.indexing_technique}>{data.indexing_technique}</div>
</div>
<div className='flex h-6 items-center rounded-md bg-workflow-block-parma-bg px-1.5'>
<div className='system-xs-medium-uppercase mr-2 shrink-0 text-text-tertiary'>Retrieval Method</div>
<div className='system-xs-medium grow truncate text-right text-text-secondary' title={data.retrieval_model.search_method}>{data.retrieval_model.search_method}</div>
</div>
</div>
)
}

View File

@ -27,10 +27,14 @@ const Panel: FC<NodePanelProps<KnowledgeBaseNodeType>> = ({
handleChunkStructureChange,
handleIndexMethodChange,
handleKeywordNumberChange,
handleEmbeddingModelChange,
handleRetrievalSearchMethodChange,
handleHybridSearchModeChange,
handleWeighedScoreChange,
handleRerankingModelChange,
handleTopKChange,
handleScoreThresholdChange,
handleScoreThresholdEnabledChange,
} = useConfig(id)
return (
@ -57,7 +61,11 @@ const Panel: FC<NodePanelProps<KnowledgeBaseNodeType>> = ({
/>
{
data.indexing_technique === IndexMethodEnum.QUALIFIED && (
<EmbeddingModel />
<EmbeddingModel
embeddingModel={data.embedding_model}
embeddingModelProvider={data.embedding_model_provider}
onEmbeddingModelChange={handleEmbeddingModelChange}
/>
)
}
<div className='pt-1'>
@ -72,6 +80,12 @@ const Panel: FC<NodePanelProps<KnowledgeBaseNodeType>> = ({
onWeightedScoreChange={handleWeighedScoreChange}
rerankingModel={data.retrieval_model.reranking_model}
onRerankingModelChange={handleRerankingModelChange}
topK={data.retrieval_model.top_k}
onTopKChange={handleTopKChange}
scoreThreshold={data.retrieval_model.score_threshold}
onScoreThresholdChange={handleScoreThresholdChange}
isScoreThresholdEnabled={data.retrieval_model.score_threshold_enabled}
onScoreThresholdEnabledChange={handleScoreThresholdEnabledChange}
/>
</div>
</GroupWithBox>