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

This commit is contained in:
twwu 2025-05-08 16:26:37 +08:00
commit 0099f2296d
16 changed files with 181 additions and 66 deletions

View File

@ -1,4 +1,7 @@
import { useMemo } from 'react'
import {
memo,
useMemo,
} from 'react'
import type { PanelProps } from '@/app/components/workflow/panel'
import Panel from '@/app/components/workflow/panel'
import { useStore } from '@/app/components/workflow/store'
@ -28,4 +31,4 @@ const RagPipelinePanel = () => {
)
}
export default RagPipelinePanel
export default memo(RagPipelinePanel)

View File

@ -1,3 +1,4 @@
import { memo } from 'react'
import { useStore } from '../../workflow/store'
import InputField from './input-field'
import RagPipelinePanel from './panel'
@ -17,4 +18,4 @@ const RagPipelineChildren = () => {
)
}
export default RagPipelineChildren
export default memo(RagPipelineChildren)

View File

@ -1,10 +1,25 @@
import { useMemo } from 'react'
import {
memo,
useMemo,
} from 'react'
import type { HeaderProps } from '@/app/components/workflow/header'
import Header from '@/app/components/workflow/header'
import { fetchWorkflowRunHistory } from '@/service/workflow'
import { useStore } from '@/app/components/workflow/store'
import InputFieldButton from './input-field-button'
import Publisher from './publisher'
const RagPipelineHeader = () => {
const pipelineId = useStore(s => s.pipelineId)
const viewHistoryProps = useMemo(() => {
return {
historyUrl: '',
// historyUrl: `/rag/pipeline/${pipelineId}/workflow-runs`,
historyFetcher: fetchWorkflowRunHistory,
}
}, [pipelineId])
const headerProps: HeaderProps = useMemo(() => {
return {
normal: {
@ -12,13 +27,21 @@ const RagPipelineHeader = () => {
left: <InputFieldButton />,
middle: <Publisher />,
},
runAndHistoryProps: {
showRunButton: true,
runButtonText: 'Test Run',
viewHistoryProps,
},
},
viewHistory: {
viewHistoryProps,
},
}
}, [])
}, [viewHistoryProps])
return (
<Header {...headerProps} />
)
}
export default RagPipelineHeader
export default memo(RagPipelineHeader)

View File

@ -1,3 +1,4 @@
import { memo } from 'react'
import { useTranslation } from 'react-i18next'
import { RiArrowDownSLine } from '@remixicon/react'
import Button from '@/app/components/base/button'
@ -25,11 +26,11 @@ const Publisher = () => {
<RiArrowDownSLine className='h-4 w-4' />
</Button>
</PortalToFollowElemTrigger>
<PortalToFollowElemContent>
<PortalToFollowElemContent className='z-[11]'>
<Popup />
</PortalToFollowElemContent>
</PortalToFollowElem>
)
}
export default Publisher
export default memo(Publisher)

View File

@ -1,4 +1,5 @@
import {
memo,
useCallback,
useState,
} from 'react'
@ -77,9 +78,10 @@ const Popup = () => {
}
</Button>
</div>
<div className='space-y-1 border-t-[0.5px] border-t-divider-regular p-4 pt-3'>
<div className='border-t-[0.5px] border-t-divider-regular p-4 pt-3'>
<Button
className='w-full'
className='mb-1 w-full hover:bg-state-accent-hover hover:text-text-accent'
variant='tertiary'
>
<div className='flex grow items-center'>
<RiPlayCircleLine className='mr-2 h-4 w-4' />
@ -88,7 +90,8 @@ const Popup = () => {
<RiArrowRightUpLine className='ml-2 h-4 w-4 shrink-0' />
</Button>
<Button
className='w-full'
className='w-full hover:bg-state-accent-hover hover:text-text-accent'
variant='tertiary'
>
<div className='flex grow items-center'>
<RiTerminalBoxLine className='mr-2 h-4 w-4' />
@ -96,16 +99,19 @@ const Popup = () => {
</div>
<RiArrowRightUpLine className='ml-2 h-4 w-4 shrink-0' />
</Button>
<Divider />
<Divider className='my-2' />
<Button
className='w-full'
className='w-full hover:bg-state-accent-hover hover:text-text-accent'
variant='tertiary'
>
<RiHammerLine className='mr-2 h-4 w-4' />
Publish as a Knowledge Pipeline
<div className='flex grow items-center'>
<RiHammerLine className='mr-2 h-4 w-4' />
Publish as a Knowledge Pipeline
</div>
</Button>
</div>
</div>
)
}
export default Popup
export default memo(Popup)

View File

@ -279,6 +279,7 @@ export const useWorkflowRun = () => {
const handleStopRun = useCallback((taskId: string) => {
const { pipelineId } = workflowStore.getState()
return
stopWorkflowRun(`/rag/pipeline/${pipelineId}/workflow-runs/tasks/${taskId}/stop`)
}, [workflowStore])

View File

@ -1,14 +1,41 @@
import { useMemo } from 'react'
import {
memo,
useCallback,
useMemo,
} from 'react'
import { useShallow } from 'zustand/react/shallow'
import type { HeaderProps } from '@/app/components/workflow/header'
import Header from '@/app/components/workflow/header'
import { useStore as useAppStore } from '@/app/components/app/store'
import {
fetchWorkflowRunHistory,
} from '@/service/workflow'
import ChatVariableTrigger from './chat-variable-trigger'
import FeaturesTrigger from './features-trigger'
import { useResetWorkflowVersionHistory } from '@/service/use-workflow'
import { useIsChatMode } from '../../hooks'
const WorkflowHeader = () => {
const appDetail = useAppStore(s => s.appDetail)
const { appDetail, setCurrentLogItem, setShowMessageLogModal } = useAppStore(useShallow(state => ({
appDetail: state.appDetail,
setCurrentLogItem: state.setCurrentLogItem,
setShowMessageLogModal: state.setShowMessageLogModal,
})))
const resetWorkflowVersionHistory = useResetWorkflowVersionHistory(appDetail!.id)
const isChatMode = useIsChatMode()
const handleClearLogAndMessageModal = useCallback(() => {
setCurrentLogItem()
setShowMessageLogModal(false)
}, [setCurrentLogItem, setShowMessageLogModal])
const viewHistoryProps = useMemo(() => {
return {
onClearLogAndMessageModal: handleClearLogAndMessageModal,
historyUrl: isChatMode ? `/apps/${appDetail!.id}/advanced-chat/workflow-runs` : `/apps/${appDetail!.id}/workflow-runs`,
historyFetcher: fetchWorkflowRunHistory,
}
}, [appDetail, isChatMode, handleClearLogAndMessageModal])
const headerProps: HeaderProps = useMemo(() => {
return {
@ -17,15 +44,23 @@ const WorkflowHeader = () => {
left: <ChatVariableTrigger />,
middle: <FeaturesTrigger />,
},
runAndHistoryProps: {
showRunButton: !isChatMode,
showPreviewButton: isChatMode,
viewHistoryProps,
},
},
viewHistory: {
viewHistoryProps,
},
restoring: {
onRestoreSettled: resetWorkflowVersionHistory,
},
}
}, [resetWorkflowVersionHistory])
}, [resetWorkflowVersionHistory, isChatMode, viewHistoryProps])
return (
<Header {...headerProps} />
)
}
export default WorkflowHeader
export default memo(WorkflowHeader)

View File

@ -1,4 +1,7 @@
import { useMemo } from 'react'
import {
memo,
useMemo,
} from 'react'
import { useShallow } from 'zustand/react/shallow'
import { useStore } from '@/app/components/workflow/store'
import {
@ -106,4 +109,4 @@ const WorkflowPanel = () => {
)
}
export default WorkflowPanel
export default memo(WorkflowPanel)

View File

@ -13,6 +13,7 @@ import {
useWorkflowRun,
} from '../hooks'
import Divider from '../../base/divider'
import type { RunAndHistoryProps } from './run-and-history'
import RunAndHistory from './run-and-history'
import EditingTitle from './editing-title'
import EnvButton from './env-button'
@ -23,9 +24,11 @@ export type HeaderInNormalProps = {
left?: React.ReactNode
middle?: React.ReactNode
}
runAndHistoryProps?: RunAndHistoryProps
}
const HeaderInNormal = ({
components,
runAndHistoryProps,
}: HeaderInNormalProps) => {
const workflowStore = useWorkflowStore()
const { nodesReadOnly } = useNodesReadOnly()
@ -58,7 +61,7 @@ const HeaderInNormal = ({
{components?.left}
<EnvButton disabled={nodesReadOnly} />
<Divider type='vertical' className='mx-auto h-3.5' />
<RunAndHistory />
<RunAndHistory {...runAndHistoryProps} />
{components?.middle}
<VersionHistoryButton onClick={onStartRestoring} />
</div>

View File

@ -10,11 +10,17 @@ import {
} from '../hooks'
import Divider from '../../base/divider'
import RunningTitle from './running-title'
import type { ViewHistoryProps } from './view-history'
import ViewHistory from './view-history'
import Button from '@/app/components/base/button'
import { ArrowNarrowLeft } from '@/app/components/base/icons/src/vender/line/arrows'
const HeaderInHistory = () => {
export type HeaderInHistoryProps = {
viewHistoryProps?: ViewHistoryProps
}
const HeaderInHistory = ({
viewHistoryProps,
}: HeaderInHistoryProps) => {
const { t } = useTranslation()
const workflowStore = useWorkflowStore()
@ -33,7 +39,7 @@ const HeaderInHistory = () => {
<RunningTitle />
</div>
<div className='flex items-center space-x-2'>
<ViewHistory withText />
<ViewHistory {...viewHistoryProps} withText />
<Divider type='vertical' className='mx-auto h-3.5' />
<Button
variant='primary'

View File

@ -3,16 +3,19 @@ import {
} from '../hooks'
import type { HeaderInNormalProps } from './header-in-normal'
import HeaderInNormal from './header-in-normal'
import type { HeaderInHistoryProps } from './header-in-view-history'
import HeaderInHistory from './header-in-view-history'
import type { HeaderInRestoringProps } from './header-in-restoring'
import HeaderInRestoring from './header-in-restoring'
export type HeaderProps = {
normal?: HeaderInNormalProps
viewHistory?: HeaderInHistoryProps
restoring?: HeaderInRestoringProps
}
const Header = ({
normal: normalProps,
viewHistory: viewHistoryProps,
restoring: restoringProps,
}: HeaderProps) => {
const {
@ -34,7 +37,9 @@ const Header = ({
}
{
viewHistory && (
<HeaderInHistory />
<HeaderInHistory
{...viewHistoryProps}
/>
)
}
{

View File

@ -1,4 +1,3 @@
import type { FC } from 'react'
import { memo } from 'react'
import { useTranslation } from 'react-i18next'
import {
@ -7,12 +6,12 @@ import {
} from '@remixicon/react'
import { useStore } from '../store'
import {
useIsChatMode,
useNodesReadOnly,
useWorkflowRun,
useWorkflowStartRun,
} from '../hooks'
import { WorkflowRunningStatus } from '../types'
import type { ViewHistoryProps } from './view-history'
import ViewHistory from './view-history'
import Checklist from './checklist'
import cn from '@/utils/classnames'
@ -20,7 +19,12 @@ import {
StopCircle,
} from '@/app/components/base/icons/src/vender/line/mediaAndDevices'
const RunMode = memo(() => {
type RunModeProps = {
text?: string
}
const RunMode = memo(({
text,
}: RunModeProps) => {
const { t } = useTranslation()
const { handleWorkflowStartRunInWorkflow } = useWorkflowStartRun()
const { handleStopRun } = useWorkflowRun()
@ -50,7 +54,7 @@ const RunMode = memo(() => {
: (
<>
<RiPlayLargeLine className='mr-1 h-4 w-4' />
{t('workflow.common.run')}
{text ?? t('workflow.common.run')}
</>
)
}
@ -68,7 +72,6 @@ const RunMode = memo(() => {
</>
)
})
RunMode.displayName = 'RunMode'
const PreviewMode = memo(() => {
const { t } = useTranslation()
@ -87,22 +90,31 @@ const PreviewMode = memo(() => {
</div>
)
})
PreviewMode.displayName = 'PreviewMode'
const RunAndHistory: FC = () => {
const isChatMode = useIsChatMode()
export type RunAndHistoryProps = {
showRunButton?: boolean
runButtonText?: string
showPreviewButton?: boolean
viewHistoryProps?: ViewHistoryProps
}
const RunAndHistory = ({
showRunButton,
runButtonText,
showPreviewButton,
viewHistoryProps,
}: RunAndHistoryProps) => {
const { nodesReadOnly } = useNodesReadOnly()
return (
<div className='flex h-8 items-center rounded-lg border-[0.5px] border-components-button-secondary-border bg-components-button-secondary-bg px-0.5 shadow-xs'>
{
!isChatMode && <RunMode />
showRunButton && <RunMode text={runButtonText} />
}
{
isChatMode && <PreviewMode />
showPreviewButton && <PreviewMode />
}
<div className='mx-0.5 h-3.5 w-[1px] bg-divider-regular'></div>
<ViewHistory />
<ViewHistory {...viewHistoryProps} />
<Checklist disabled={nodesReadOnly} />
</div>
)

View File

@ -2,9 +2,10 @@ import {
memo,
useState,
} from 'react'
import type { Fetcher } from 'swr'
import useSWR from 'swr'
import { useTranslation } from 'react-i18next'
import { useShallow } from 'zustand/react/shallow'
import { noop } from 'lodash-es'
import {
RiCheckboxCircleLine,
RiCloseLine,
@ -25,27 +26,29 @@ import {
PortalToFollowElemTrigger,
} from '@/app/components/base/portal-to-follow-elem'
import Tooltip from '@/app/components/base/tooltip'
import { useStore as useAppStore } from '@/app/components/app/store'
import {
ClockPlay,
ClockPlaySlim,
} from '@/app/components/base/icons/src/vender/line/time'
import { AlertTriangle } from '@/app/components/base/icons/src/vender/line/alertsAndFeedback'
import {
fetchChatRunHistory,
fetchWorkflowRunHistory,
} from '@/service/workflow'
import Loading from '@/app/components/base/loading'
import {
useStore,
useWorkflowStore,
} from '@/app/components/workflow/store'
import type { WorkflowRunHistoryResponse } from '@/types/workflow'
type ViewHistoryProps = {
export type ViewHistoryProps = {
withText?: boolean
onClearLogAndMessageModal?: () => void
historyUrl?: string
historyFetcher?: Fetcher<WorkflowRunHistoryResponse, string>
}
const ViewHistory = ({
withText,
onClearLogAndMessageModal,
historyUrl,
historyFetcher,
}: ViewHistoryProps) => {
const { t } = useTranslation()
const isChatMode = useIsChatMode()
@ -59,18 +62,14 @@ const ViewHistory = ({
} = useWorkflowInteractions()
const workflowStore = useWorkflowStore()
const setControlMode = useStore(s => s.setControlMode)
const { appDetail, setCurrentLogItem, setShowMessageLogModal } = useAppStore(useShallow(state => ({
appDetail: state.appDetail,
setCurrentLogItem: state.setCurrentLogItem,
setShowMessageLogModal: state.setShowMessageLogModal,
})))
const historyWorkflowData = useStore(s => s.historyWorkflowData)
const { handleBackupDraft } = useWorkflowRun()
const { data: runList, isLoading: runListLoading } = useSWR((appDetail && !isChatMode && open) ? `/apps/${appDetail.id}/workflow-runs` : null, fetchWorkflowRunHistory)
const { data: chatList, isLoading: chatListLoading } = useSWR((appDetail && isChatMode && open) ? `/apps/${appDetail.id}/advanced-chat/workflow-runs` : null, fetchChatRunHistory)
const data = isChatMode ? chatList : runList
const isLoading = isChatMode ? chatListLoading : runListLoading
const fetcher = historyFetcher ?? (noop as Fetcher<WorkflowRunHistoryResponse, string>)
const {
data,
isLoading,
} = useSWR((open && historyUrl && historyFetcher) ? historyUrl : null, fetcher)
return (
(
@ -106,8 +105,7 @@ const ViewHistory = ({
<div
className={cn('group flex h-7 w-7 cursor-pointer items-center justify-center rounded-md hover:bg-state-accent-hover', open && 'bg-state-accent-hover')}
onClick={() => {
setCurrentLogItem()
setShowMessageLogModal(false)
onClearLogAndMessageModal?.()
}}
>
<ClockPlay className={cn('h-4 w-4 group-hover:text-components-button-secondary-accent-text', open ? 'text-components-button-secondary-accent-text' : 'text-components-button-ghost-text')} />
@ -128,8 +126,7 @@ const ViewHistory = ({
<div
className='flex h-6 w-6 shrink-0 cursor-pointer items-center justify-center'
onClick={() => {
setCurrentLogItem()
setShowMessageLogModal(false)
onClearLogAndMessageModal?.()
setOpen(false)
}}
>

View File

@ -1,12 +1,18 @@
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'
import type { ValueSelector } from '@/app/components/workflow/types'
const InputVariable = () => {
const handleChange = () => {
console.log('')
}
type InputVariableProps = {
nodeId: string
inputVariable?: string[]
onInputVariableChange: (inputVariable: string | ValueSelector) => void
}
const InputVariable = ({
nodeId,
inputVariable = [],
onInputVariableChange,
}: InputVariableProps) => {
return (
<Field
fieldTitleProps={{
@ -15,10 +21,10 @@ const InputVariable = () => {
}}
>
<VarReferencePicker
nodeId={''}
nodeId={nodeId}
isShowNodeName
value={[]}
onChange={handleChange}
value={inputVariable}
onChange={onInputVariableChange}
readonly={false}
/>
</Field>

View File

@ -3,6 +3,7 @@ import {
} from 'react'
import { useStoreApi } from 'reactflow'
import { useNodeDataUpdate } from '@/app/components/workflow/hooks'
import type { ValueSelector } from '@/app/components/workflow/types'
import type {
ChunkStructureEnum,
HybridSearchModeEnum,
@ -147,6 +148,12 @@ export const useConfig = (id: string) => {
})
}, [getNodeData, handleNodeDataUpdate])
const handleInputVariableChange = useCallback((inputVariable: string | ValueSelector) => {
handleNodeDataUpdate({
index_chunk_variable_selector: Array.isArray(inputVariable) ? inputVariable : [],
})
}, [handleNodeDataUpdate])
return {
handleChunkStructureChange,
handleIndexMethodChange,
@ -159,5 +166,6 @@ export const useConfig = (id: string) => {
handleTopKChange,
handleScoreThresholdChange,
handleScoreThresholdEnabledChange,
handleInputVariableChange,
}
}

View File

@ -35,12 +35,17 @@ const Panel: FC<NodePanelProps<KnowledgeBaseNodeType>> = ({
handleTopKChange,
handleScoreThresholdChange,
handleScoreThresholdEnabledChange,
handleInputVariableChange,
} = useConfig(id)
return (
<div>
<GroupWithBox boxProps={{ withBorderBottom: true }}>
<InputVariable />
<InputVariable
nodeId={id}
inputVariable={data.index_chunk_variable_selector}
onInputVariableChange={handleInputVariableChange}
/>
</GroupWithBox>
<Group
className='py-3'