Merge branch 'feat/rag-pipeline' of https://github.com/langgenius/dify into feat/rag-pipeline

This commit is contained in:
twwu 2025-05-14 14:49:10 +08:00
commit df928772c0
15 changed files with 89 additions and 27 deletions

View File

@ -21,10 +21,12 @@ type Value = {
type WeightedScoreProps = {
value: Value
onChange: (value: Value) => void
readonly?: boolean
}
const WeightedScore = ({
value,
onChange = noop,
readonly = false,
}: WeightedScoreProps) => {
const { t } = useTranslation()
@ -37,7 +39,7 @@ const WeightedScore = ({
min={0}
step={0.1}
value={value.value[0]}
onChange={v => onChange({ value: [v, (10 - v * 10) / 10] })}
onChange={v => !readonly && onChange({ value: [v, (10 - v * 10) / 10] })}
trackClassName='weightedScoreSliderTrack'
/>
<div className='mt-3 flex justify-between'>

View File

@ -18,3 +18,4 @@ export * from './use-format-time-from-now'
export * from './use-nodes-meta-data'
export * from './use-available-blocks'
export * from './use-workflow-refresh-draft'
export * from './use-tool-icon'

View File

@ -0,0 +1,34 @@
import {
useMemo,
} from 'react'
import type {
Node,
} from '../types'
import {
BlockEnum,
} from '../types'
import {
useStore,
} from '../store'
import { CollectionType } from '@/app/components/tools/types'
import { canFindTool } from '@/utils'
export const useToolIcon = (data: Node['data']) => {
const buildInTools = useStore(s => s.buildInTools)
const customTools = useStore(s => s.customTools)
const workflowTools = useStore(s => s.workflowTools)
const toolIcon = useMemo(() => {
if (data.type === BlockEnum.Tool) {
let targetTools = buildInTools
if (data.provider_type === CollectionType.builtIn)
targetTools = buildInTools
else if (data.provider_type === CollectionType.custom)
targetTools = customTools
else
targetTools = workflowTools
return targetTools.find(toolWithProvider => canFindTool(toolWithProvider.id, data.provider_id))?.icon
}
}, [data, buildInTools, customTools, workflowTools])
return toolIcon
}

View File

@ -1,6 +1,5 @@
import {
useCallback,
useMemo,
} from 'react'
import { uniqBy } from 'lodash-es'
import { useTranslation } from 'react-i18next'
@ -39,11 +38,9 @@ import {
fetchAllCustomTools,
fetchAllWorkflowTools,
} from '@/service/tools'
import { CollectionType } from '@/app/components/tools/types'
import { CUSTOM_ITERATION_START_NODE } from '@/app/components/workflow/nodes/iteration-start/constants'
import { CUSTOM_LOOP_START_NODE } from '@/app/components/workflow/nodes/loop-start/constants'
import { basePath } from '@/utils/var'
import { canFindTool } from '@/utils'
export const useIsChatMode = () => {
const appDetail = useAppStore(s => s.appDetail)
@ -489,26 +486,6 @@ export const useNodesReadOnly = () => {
}
}
export const useToolIcon = (data: Node['data']) => {
const buildInTools = useStore(s => s.buildInTools)
const customTools = useStore(s => s.customTools)
const workflowTools = useStore(s => s.workflowTools)
const toolIcon = useMemo(() => {
if (data.type === BlockEnum.Tool) {
let targetTools = buildInTools
if (data.provider_type === CollectionType.builtIn)
targetTools = buildInTools
else if (data.provider_type === CollectionType.custom)
targetTools = customTools
else
targetTools = workflowTools
return targetTools.find(toolWithProvider => canFindTool(toolWithProvider.id, data.provider_id))?.icon
}
}, [data, buildInTools, customTools, workflowTools])
return toolIcon
}
export const useIsNodeInIteration = (iterationId: string) => {
const store = useStoreApi()

View File

@ -8,10 +8,12 @@ import { useChunkStructure } from './hooks'
type ChunkStructureProps = {
chunkStructure: ChunkStructureEnum
onChunkStructureChange: (value: ChunkStructureEnum) => void
readonly?: boolean
}
const ChunkStructure = ({
chunkStructure,
onChunkStructureChange,
readonly = false,
}: ChunkStructureProps) => {
const {
options,
@ -28,6 +30,7 @@ const ChunkStructure = ({
options={options}
value={chunkStructure}
onChange={onChunkStructureChange}
readonly={readonly}
/>
),
}}

View File

@ -13,11 +13,13 @@ type SelectorProps = {
options: Option[]
value: ChunkStructureEnum
onChange: (key: ChunkStructureEnum) => void
readonly?: boolean
}
const Selector = ({
options,
value,
onChange,
readonly,
}: SelectorProps) => {
const [open, setOpen] = useState(false)
@ -31,7 +33,11 @@ const Selector = ({
open={open}
onOpenChange={setOpen}
>
<PortalToFollowElemTrigger onClick={() => setOpen(!open)}>
<PortalToFollowElemTrigger onClick={() => {
if (readonly)
return
setOpen(!open)
}}>
<Button
size='small'
variant='ghost-accent'
@ -54,6 +60,8 @@ const Selector = ({
title={option.title}
description={option.description}
onClick={() => {
if (readonly)
return
onChange(option.id)
setOpen(false)
}}

View File

@ -15,11 +15,13 @@ type EmbeddingModelProps = {
embeddingModel: string
embeddingModelProvider: string
}) => void
readonly?: boolean
}
const EmbeddingModel = ({
embeddingModel,
embeddingModelProvider,
onEmbeddingModelChange,
readonly = false,
}: EmbeddingModelProps) => {
const {
modelList: embeddingModelList,
@ -51,6 +53,7 @@ const handleRerankingModelChange = (model: DefaultModel) => {
defaultModel={embeddingModelConfig && { provider: embeddingModelConfig.providerName, model: embeddingModelConfig.modelName }}
modelList={embeddingModelList}
onSelect={handleRerankingModelChange}
readonly={readonly}
/>
</Field>
)

View File

@ -21,12 +21,14 @@ type IndexMethodProps = {
onIndexMethodChange: (value: IndexMethodEnum) => void
keywordNumber: number
onKeywordNumberChange: (value: number) => void
readonly?: boolean
}
const IndexMethod = ({
indexMethod,
onIndexMethodChange,
keywordNumber,
onKeywordNumberChange,
readonly = false,
}: IndexMethodProps) => {
const { t } = useTranslation()
const isHighQuality = indexMethod === IndexMethodEnum.QUALIFIED
@ -95,11 +97,13 @@ const IndexMethod = ({
</Tooltip>
</div>
<Slider
disabled={readonly}
className='mr-3 w-24 shrink-0'
value={keywordNumber}
onChange={onKeywordNumberChange}
/>
<Input
disabled={readonly}
className='shrink-0'
wrapperClassName='shrink-0 w-[72px]'
type='number'

View File

@ -7,11 +7,13 @@ type InputVariableProps = {
nodeId: string
inputVariable?: string[]
onInputVariableChange: (inputVariable: string | ValueSelector) => void
readonly?: boolean
}
const InputVariable = ({
nodeId,
inputVariable = [],
onInputVariableChange,
readonly = false,
}: InputVariableProps) => {
return (
<Field
@ -25,7 +27,7 @@ const InputVariable = ({
isShowNodeName
value={inputVariable}
onChange={onInputVariableChange}
readonly={false}
readonly={readonly}
/>
</Field>
)

View File

@ -31,6 +31,7 @@ type OptionCardProps<T> = {
effectColor?: string
showEffectColor?: boolean
onClick?: (id: T) => void
readonly?: boolean
}
const OptionCard = memo(({
id,
@ -47,14 +48,16 @@ const OptionCard = memo(({
effectColor,
showEffectColor,
onClick,
readonly,
}) => {
return (
<div
className={cn(
'cursor-pointer rounded-xl border border-components-option-card-option-border bg-components-option-card-option-bg',
showHighlightBorder && 'border-[2px] border-components-option-card-option-selected-border',
readonly && 'cursor-not-allowed',
)}
onClick={() => onClick?.(id)}
onClick={() => !readonly && onClick?.(id)}
>
<div className={cn(
'relative flex rounded-t-xl p-2',

View File

@ -15,6 +15,7 @@ import type { RerankingModelSelectorProps } from './reranking-model-selector'
import SearchMethodOption from './search-method-option'
type RetrievalSettingProps = {
readonly?: boolean
searchMethod: RetrievalSearchMethodEnum
onRetrievalSearchMethodChange: (value: RetrievalSearchMethodEnum) => void
hybridSearchMode: HybridSearchModeEnum
@ -24,6 +25,7 @@ type RetrievalSettingProps = {
} & RerankingModelSelectorProps & TopKAndScoreThresholdProps
const RetrievalSetting = ({
readonly,
searchMethod,
onRetrievalSearchMethodChange,
hybridSearchMode,
@ -84,6 +86,7 @@ const RetrievalSetting = ({
onScoreThresholdEnabledChange={onScoreThresholdEnabledChange}
rerankingModel={rerankingModel}
onRerankingModelChange={onRerankingModelChange}
readonly={readonly}
/>
))
}

View File

@ -11,10 +11,12 @@ import type { RerankingModel } from '../../types'
export type RerankingModelSelectorProps = {
rerankingModel?: RerankingModel
onRerankingModelChange?: (model: RerankingModel) => void
readonly?: boolean
}
const RerankingModelSelector = ({
rerankingModel,
onRerankingModelChange,
readonly = false,
}: RerankingModelSelectorProps) => {
const {
modelList: rerankModelList,
@ -41,6 +43,7 @@ const RerankingModelSelector = ({
defaultModel={rerankModel && { provider: rerankModel.providerName, model: rerankModel.modelName }}
modelList={rerankModelList}
onSelect={handleRerankingModelChange}
readonly={readonly}
/>
)
}

View File

@ -23,6 +23,7 @@ import type { RerankingModelSelectorProps } from './reranking-model-selector'
import RerankingModelSelector from './reranking-model-selector'
type SearchMethodOptionProps = {
readonly?: boolean
option: Option
hybridSearchModeOptions: HybridSearchModeOption[]
searchMethod: RetrievalSearchMethodEnum
@ -33,6 +34,7 @@ type SearchMethodOptionProps = {
onWeightedScoreChange: (value: { value: number[] }) => void
} & RerankingModelSelectorProps & TopKAndScoreThresholdProps
const SearchMethodOption = ({
readonly,
option,
hybridSearchModeOptions,
searchMethod,
@ -89,6 +91,7 @@ const SearchMethodOption = ({
showChildren={isActive}
showHighlightBorder={isActive}
showEffectColor={isActive}
readonly={readonly}
>
<div className='space-y-3'>
{
@ -105,6 +108,7 @@ const SearchMethodOption = ({
showRadio
radioIsActive={hybridOption.id === hybridSearchMode}
onClick={onHybridSearchModeChange}
readonly={readonly}
/>
))
}
@ -116,6 +120,7 @@ const SearchMethodOption = ({
<WeightedScoreComponent
value={weightedScoreValue}
onChange={onWeightedScoreChange}
readonly={readonly}
/>
)
}
@ -124,6 +129,7 @@ const SearchMethodOption = ({
<RerankingModelSelector
rerankingModel={rerankingModel}
onRerankingModelChange={onRerankingModelChange}
readonly={readonly}
/>
)
}
@ -134,6 +140,7 @@ const SearchMethodOption = ({
onScoreThresholdChange={onScoreThresholdChange}
isScoreThresholdEnabled={isScoreThresholdEnabled}
onScoreThresholdEnabledChange={onScoreThresholdEnabledChange}
readonly={readonly}
/>
</div>
</OptionCard>

View File

@ -10,6 +10,7 @@ export type TopKAndScoreThresholdProps = {
onScoreThresholdChange?: (value: number) => void
isScoreThresholdEnabled?: boolean
onScoreThresholdEnabledChange?: (value: boolean) => void
readonly?: boolean
}
const TopKAndScoreThreshold = ({
topK,
@ -18,6 +19,7 @@ const TopKAndScoreThreshold = ({
onScoreThresholdChange,
isScoreThresholdEnabled,
onScoreThresholdEnabledChange,
readonly,
}: TopKAndScoreThresholdProps) => {
const handleTopKChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = Number(e.target.value)
@ -47,6 +49,7 @@ const TopKAndScoreThreshold = ({
type='number'
value={topK}
onChange={handleTopKChange}
disabled={readonly}
/>
</div>
<div>
@ -55,6 +58,7 @@ const TopKAndScoreThreshold = ({
className='mr-2'
defaultValue={isScoreThresholdEnabled}
onChange={onScoreThresholdEnabledChange}
disabled={readonly}
/>
<div className='system-sm-medium grow truncate text-text-secondary'>
Score Threshold
@ -68,6 +72,7 @@ const TopKAndScoreThreshold = ({
type='number'
value={scoreThreshold}
onChange={handleScoreThresholdChange}
disabled={readonly}
/>
</div>
</div>

View File

@ -18,11 +18,13 @@ import {
GroupWithBox,
} from '@/app/components/workflow/nodes/_base/components/layout'
import Split from '../_base/components/split'
import { useNodesReadOnly } from '@/app/components/workflow/hooks'
const Panel: FC<NodePanelProps<KnowledgeBaseNodeType>> = ({
id,
data,
}) => {
const { nodesReadOnly } = useNodesReadOnly()
const {
handleChunkStructureChange,
handleIndexMethodChange,
@ -45,6 +47,7 @@ const Panel: FC<NodePanelProps<KnowledgeBaseNodeType>> = ({
nodeId={id}
inputVariable={data.index_chunk_variable_selector}
onInputVariableChange={handleInputVariableChange}
readonly={nodesReadOnly}
/>
</GroupWithBox>
<Group
@ -54,6 +57,7 @@ const Panel: FC<NodePanelProps<KnowledgeBaseNodeType>> = ({
<ChunkStructure
chunkStructure={data.chunk_structure}
onChunkStructureChange={handleChunkStructureChange}
readonly={nodesReadOnly}
/>
</Group>
<GroupWithBox>
@ -63,6 +67,7 @@ const Panel: FC<NodePanelProps<KnowledgeBaseNodeType>> = ({
onIndexMethodChange={handleIndexMethodChange}
keywordNumber={data.keyword_number}
onKeywordNumberChange={handleKeywordNumberChange}
readonly={nodesReadOnly}
/>
{
data.indexing_technique === IndexMethodEnum.QUALIFIED && (
@ -70,6 +75,7 @@ const Panel: FC<NodePanelProps<KnowledgeBaseNodeType>> = ({
embeddingModel={data.embedding_model}
embeddingModelProvider={data.embedding_model_provider}
onEmbeddingModelChange={handleEmbeddingModelChange}
readonly={nodesReadOnly}
/>
)
}
@ -91,6 +97,7 @@ const Panel: FC<NodePanelProps<KnowledgeBaseNodeType>> = ({
onScoreThresholdChange={handleScoreThresholdChange}
isScoreThresholdEnabled={data.retrieval_model.score_threshold_enabled}
onScoreThresholdEnabledChange={handleScoreThresholdEnabledChange}
readonly={nodesReadOnly}
/>
</div>
</GroupWithBox>