From e33260d2e2945003beaf8c5bd10d19f4e6b77e8c Mon Sep 17 00:00:00 2001 From: StyleZhang Date: Fri, 15 Mar 2024 19:51:46 +0800 Subject: [PATCH 1/9] node value init --- .../workflow/hooks/use-nodes-data.ts | 4 +- .../components/workflow/hooks/use-workflow.ts | 2 +- web/app/components/workflow/utils.ts | 97 ------------------- 3 files changed, 4 insertions(+), 99 deletions(-) diff --git a/web/app/components/workflow/hooks/use-nodes-data.ts b/web/app/components/workflow/hooks/use-nodes-data.ts index 417cb3399c25f0..66c6b9a8dc0bed 100644 --- a/web/app/components/workflow/hooks/use-nodes-data.ts +++ b/web/app/components/workflow/hooks/use-nodes-data.ts @@ -16,13 +16,15 @@ export const useNodesInitialData = () => { return useMemo(() => produce(NODES_INITIAL_DATA, (draft) => { Object.keys(draft).forEach((key) => { draft[key as BlockEnum].title = t(`workflow.blocks.${key}`) - draft[key as BlockEnum]._isReady = true if (nodesDefaultConfigs[key as BlockEnum]) { draft[key as BlockEnum] = { ...draft[key as BlockEnum], ...nodesDefaultConfigs[key as BlockEnum], } } + else { + draft[key as BlockEnum]._isReady = true + } }) }), [t, nodesDefaultConfigs]) } diff --git a/web/app/components/workflow/hooks/use-workflow.ts b/web/app/components/workflow/hooks/use-workflow.ts index 07233fc3696bcc..703182959354d2 100644 --- a/web/app/components/workflow/hooks/use-workflow.ts +++ b/web/app/components/workflow/hooks/use-workflow.ts @@ -236,7 +236,7 @@ export const useWorkflowInit = () => { workflowStore.setState({ nodesDefaultConfigs: nodesDefaultConfigsData.reduce((acc, block) => { if (!acc[block.type]) - acc[block.type] = block.config + acc[block.type] = { ...block.config, _isReady: true } return acc }, {} as Record), }) diff --git a/web/app/components/workflow/utils.ts b/web/app/components/workflow/utils.ts index 8281164f9cfcab..1082fef195173f 100644 --- a/web/app/components/workflow/utils.ts +++ b/web/app/components/workflow/utils.ts @@ -1,7 +1,6 @@ import { Position, getConnectedEdges, - getOutgoers, } from 'reactflow' import dagre from 'dagre' import { cloneDeep } from 'lodash-es' @@ -12,76 +11,6 @@ import type { import { BlockEnum } from './types' import type { QuestionClassifierNodeType } from './nodes/question-classifier/types' -export const nodesLevelOrderTraverse = ( - firstNode: Node, - nodes: Node[], - edges: Edge[], - callback: (n: any) => void, -) => { - const queue = [{ - node: firstNode, - depth: 0, - breath: 0, - }] - - let currenDepth = 0 - let currentBreath = 0 - while (queue.length) { - const { node, depth, breath } = queue.shift()! - - if (currenDepth !== depth) { - currenDepth = depth - currentBreath = 0 - } - - callback({ node, depth, breath }) - - const targetBranches = node.data._targetBranches - if (targetBranches?.length) { - const targetEdges = getConnectedEdges([node], edges) - - if (targetEdges.length) { - const sortedTargetEdges = targetEdges - .filter(edge => edge.source === node.id) - .sort((a, b) => { - const aIndex = targetBranches.findIndex(branch => branch.id === a.sourceHandle) - const bIndex = targetBranches.findIndex(branch => branch.id === b.sourceHandle) - - return aIndex - bIndex - }) - - const outgoers = getOutgoers(node, nodes, sortedTargetEdges) - - queue.push(...outgoers.map((outgoer, index) => { - return { - node: outgoer, - depth: depth + 1, - breath: currentBreath + index, - } - })) - - currentBreath += outgoers.length - } - else { - currentBreath += 1 - } - } - else { - const outgoers = getOutgoers(node, nodes, edges) - - if (outgoers.length === 1) { - queue.push({ - node: outgoers[0], - depth: depth + 1, - breath: 0, - }) - } - - currentBreath += 1 - } - } -} - export const initialNodes = (nodes: Node[], edges: Edge[]) => { return nodes.map((node) => { node.type = 'custom' @@ -121,34 +50,8 @@ export const initialEdges = (edges: Edge[]) => { }) } -export type PositionMap = { - index: { - x: number - y: number - } -} - -export const getNodesPositionMap = (nodes: Node[], edges: Edge[]) => { - const startNode = nodes.find((node: Node) => node.data.type === BlockEnum.Start) - const positionMap: Record = {} - - if (startNode) { - nodesLevelOrderTraverse(startNode, nodes, edges, ({ node, depth, breath }) => { - positionMap[node.id] = { - index: { - x: depth, - y: breath, - }, - } - }) - } - - return positionMap -} - const dagreGraph = new dagre.graphlib.Graph() dagreGraph.setDefaultEdgeLabel(() => ({})) - export const getLayoutByDagre = (originNodes: Node[], originEdges: Edge[]) => { const nodes = cloneDeep(originNodes) const edges = cloneDeep(originEdges) From 9908a8bf1fde94221ec2cf11d26746dbde7cf2f3 Mon Sep 17 00:00:00 2001 From: JzoNg Date: Fri, 15 Mar 2024 19:54:50 +0800 Subject: [PATCH 2/9] prompt log --- web/app/components/app/chat/answer/index.tsx | 27 ++++++++++++++--- web/app/components/app/chat/log/index.tsx | 30 ++----------------- .../base/chat/chat/answer/index.tsx | 27 +++++++++++++++-- .../base/chat/chat/answer/operation.tsx | 8 ++--- .../base/prompt-log-modal/index.tsx | 7 +++-- 5 files changed, 59 insertions(+), 40 deletions(-) diff --git a/web/app/components/app/chat/answer/index.tsx b/web/app/components/app/chat/answer/index.tsx index af37d60b05129b..ae3fd18429d881 100644 --- a/web/app/components/app/chat/answer/index.tsx +++ b/web/app/components/app/chat/answer/index.tsx @@ -1,6 +1,6 @@ 'use client' import type { FC, ReactNode } from 'react' -import React, { useRef, useState } from 'react' +import React, { useEffect, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import { UserCircleIcon } from '@heroicons/react/24/solid' import cn from 'classnames' @@ -27,6 +27,7 @@ import type { Emoji } from '@/app/components/tools/types' import type { VisionFile } from '@/types/app' import ImageGallery from '@/app/components/base/image-gallery' import Log from '@/app/components/app/chat/log' +import PromptLogModal from '@/app/components/base/prompt-log-modal' const IconWrapper: FC<{ children: React.ReactNode | string }> = ({ children }) => { return
@@ -233,7 +234,19 @@ const Answer: FC = ({
) - const ref = useRef(null) + const [showPromptLogModal, setShowPromptLogModal] = useState(false) + const [width, setWidth] = useState(0) + + const ref = useRef(null) + + const adjustModalWidth = () => { + if (ref.current) + setWidth(document.body.clientWidth - (ref.current?.clientWidth + 56 + 16)) + } + + useEffect(() => { + adjustModalWidth() + }, []) return ( // data-id for debug the item message is right @@ -323,7 +336,7 @@ const Answer: FC = ({ {((isShowPromptLog && !isResponding) || (!item.isOpeningStatement && isShowTextToSpeech)) && (
{isShowPromptLog && !isResponding && ( - + )} {!item.isOpeningStatement && isShowTextToSpeech && ( <> @@ -373,7 +386,13 @@ const Answer: FC = ({ {!feedbackDisabled && renderFeedbackRating(feedback?.rating, !isHideFeedbackEdit, displayScene !== 'console')}
- + {showPromptLogModal && ( + setShowPromptLogModal(false)} + /> + )} {more && } diff --git a/web/app/components/app/chat/log/index.tsx b/web/app/components/app/chat/log/index.tsx index 0ef14162d9e79c..cb7e6520deeac1 100644 --- a/web/app/components/app/chat/log/index.tsx +++ b/web/app/components/app/chat/log/index.tsx @@ -1,8 +1,6 @@ -import type { Dispatch, FC, ReactNode, RefObject, SetStateAction } from 'react' -import { useEffect, useState } from 'react' +import type { Dispatch, FC, ReactNode, SetStateAction } from 'react' import { useTranslation } from 'react-i18next' import { File02 } from '@/app/components/base/icons/src/vender/line/files' -import PromptLogModal from '@/app/components/base/prompt-log-modal' export type LogData = { role: string @@ -10,29 +8,16 @@ export type LogData = { } type LogProps = { - containerRef: RefObject - log: LogData[] runID?: string + setShowModal: Dispatch> children?: (v: Dispatch>) => ReactNode } const Log: FC = ({ - containerRef, children, - log, runID, + setShowModal, }) => { const { t } = useTranslation() - const [showModal, setShowModal] = useState(false) - const [width, setWidth] = useState(0) - - const adjustModalWidth = () => { - if (containerRef.current) - setWidth(document.body.clientWidth - (containerRef.current?.clientWidth + 56 + 16)) - } - - useEffect(() => { - adjustModalWidth() - }, []) return ( <> @@ -52,15 +37,6 @@ const Log: FC = ({ ) } - { - showModal && ( - setShowModal(false)} - /> - ) - } ) } diff --git a/web/app/components/base/chat/chat/answer/index.tsx b/web/app/components/base/chat/chat/answer/index.tsx index 581b031bab5438..d50a978654d2d8 100644 --- a/web/app/components/base/chat/chat/answer/index.tsx +++ b/web/app/components/base/chat/chat/answer/index.tsx @@ -2,7 +2,7 @@ import type { FC, ReactNode, } from 'react' -import { memo, useRef } from 'react' +import { memo, useEffect, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import type { ChatConfig, @@ -18,6 +18,7 @@ import LoadingAnim from '@/app/components/app/chat/loading-anim' import Citation from '@/app/components/app/chat/citation' import { EditTitle } from '@/app/components/app/annotation/edit-annotation-modal/edit-item' import type { Emoji } from '@/app/components/tools/types' +import PromptLogModal from '@/app/components/base/prompt-log-modal' type AnswerProps = { item: ChatItem @@ -40,7 +41,6 @@ const Answer: FC = ({ showPromptLog, }) => { const { t } = useTranslation() - const ref = useRef(null) const { content, citation, @@ -50,6 +50,20 @@ const Answer: FC = ({ } = item const hasAgentThoughts = !!agent_thoughts?.length + const [showPromptLogModal, setShowPromptLogModal] = useState(false) + const [width, setWidth] = useState(0) + + const ref = useRef(null) + + const adjustModalWidth = () => { + if (ref.current) + setWidth(document.body.clientWidth - (ref.current?.clientWidth + 56 + 16)) + } + + useEffect(() => { + adjustModalWidth() + }, []) + return (
@@ -79,7 +93,7 @@ const Answer: FC = ({ question={question} index={index} showPromptLog={showPromptLog} - containerRef={ref} + setShowPromptLogModal={setShowPromptLogModal} /> ) } @@ -122,6 +136,13 @@ const Answer: FC = ({
+ {showPromptLogModal && ( + setShowPromptLogModal(false)} + /> + )} ) } diff --git a/web/app/components/base/chat/chat/answer/operation.tsx b/web/app/components/base/chat/chat/answer/operation.tsx index aeed0c9e4fdcd1..e824b051e87f70 100644 --- a/web/app/components/base/chat/chat/answer/operation.tsx +++ b/web/app/components/base/chat/chat/answer/operation.tsx @@ -1,4 +1,4 @@ -import type { FC, RefObject } from 'react' +import type { Dispatch, FC, SetStateAction } from 'react' import { memo, useMemo, @@ -24,14 +24,14 @@ type OperationProps = { question: string index: number showPromptLog?: boolean - containerRef: RefObject + setShowPromptLogModal: Dispatch> } const Operation: FC = ({ item, question, index, showPromptLog, - containerRef, + setShowPromptLogModal, }) => { const { t } = useTranslation() const { @@ -79,7 +79,7 @@ const Operation: FC = ({
{showPromptLog && ( - + )} {(!isOpeningStatement && config?.text_to_speech?.enabled) && ( <> diff --git a/web/app/components/base/prompt-log-modal/index.tsx b/web/app/components/base/prompt-log-modal/index.tsx index 2948e9f06723ac..f0e5b27dded25e 100644 --- a/web/app/components/base/prompt-log-modal/index.tsx +++ b/web/app/components/base/prompt-log-modal/index.tsx @@ -4,9 +4,10 @@ import { useClickAway } from 'ahooks' import Card from './card' import { CopyFeedbackNew } from '@/app/components/base/copy-feedback' import { XClose } from '@/app/components/base/icons/src/vender/line/general' +import type { VisionFile } from '@/types/app' type PromptLogModalProps = { - log: { role: string; text: string }[] + log: { role: string; text: string; files?: VisionFile[] }[] width: number onCancel: () => void } @@ -19,8 +20,10 @@ const PromptLogModal: FC = ({ const [mounted, setMounted] = useState(false) useClickAway(() => { - if (mounted) + if (mounted) { + console.log(111) onCancel() + } }, ref) useEffect(() => { From 6146f24932f2fd62bb5ed1fa9a963cf8e1544ed3 Mon Sep 17 00:00:00 2001 From: JzoNg Date: Fri, 15 Mar 2024 20:15:57 +0800 Subject: [PATCH 3/9] fix tip of workflow --- web/app/components/app/create-app-dialog/appForm.tsx | 2 +- web/i18n/en-US/app.ts | 1 + web/i18n/zh-Hans/app.ts | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/web/app/components/app/create-app-dialog/appForm.tsx b/web/app/components/app/create-app-dialog/appForm.tsx index 796754caa5b974..ff392a264fe70e 100644 --- a/web/app/components/app/create-app-dialog/appForm.tsx +++ b/web/app/components/app/create-app-dialog/appForm.tsx @@ -165,7 +165,7 @@ const AppForm = ({
-
{t('app.newApp.completionWarning')}
+
{t('app.newApp.workflowWarning')}
} diff --git a/web/i18n/en-US/app.ts b/web/i18n/en-US/app.ts index 934266b44a3f94..35cf85550d0a10 100644 --- a/web/i18n/en-US/app.ts +++ b/web/i18n/en-US/app.ts @@ -30,6 +30,7 @@ const translation = { completionWarning: 'This type of app will no longer be supported.', agentDescription: 'Build an intelligent Agent which can autonomously choose tools to complete the tasks', workflowDescription: 'Description text here', + workflowWarning: 'Currently in beta', chatbotType: 'Chatbot orchestrate method', basic: 'Basic Orchestrate', basicFor: 'FOR BEGINNERS', diff --git a/web/i18n/zh-Hans/app.ts b/web/i18n/zh-Hans/app.ts index 923cfc3d3bba0a..a61548285f0d66 100644 --- a/web/i18n/zh-Hans/app.ts +++ b/web/i18n/zh-Hans/app.ts @@ -29,6 +29,7 @@ const translation = { completionWarning: '该类型不久后将不再支持创建', agentDescription: '构建一个智能Agent,可以自主选择工具来完成任务', workflowDescription: 'Description text here', + workflowWarning: '正在进行 Beta 测试', chatbotType: '聊天助手编排方法', basic: '基础编排', basicFor: '新手适用', From 56c53d1f0785feba497325f880fece121d329c2a Mon Sep 17 00:00:00 2001 From: StyleZhang Date: Fri, 15 Mar 2024 20:00:27 +0800 Subject: [PATCH 4/9] node value init --- web/app/components/workflow/hooks/use-nodes-data.ts | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/web/app/components/workflow/hooks/use-nodes-data.ts b/web/app/components/workflow/hooks/use-nodes-data.ts index 66c6b9a8dc0bed..fc4cb30b5d873f 100644 --- a/web/app/components/workflow/hooks/use-nodes-data.ts +++ b/web/app/components/workflow/hooks/use-nodes-data.ts @@ -6,27 +6,16 @@ import { NODES_EXTRA_DATA, NODES_INITIAL_DATA, } from '../constants' -import { useStore } from '../store' import { useIsChatMode } from './use-workflow' export const useNodesInitialData = () => { const { t } = useTranslation() - const nodesDefaultConfigs = useStore(s => s.nodesDefaultConfigs) return useMemo(() => produce(NODES_INITIAL_DATA, (draft) => { Object.keys(draft).forEach((key) => { draft[key as BlockEnum].title = t(`workflow.blocks.${key}`) - if (nodesDefaultConfigs[key as BlockEnum]) { - draft[key as BlockEnum] = { - ...draft[key as BlockEnum], - ...nodesDefaultConfigs[key as BlockEnum], - } - } - else { - draft[key as BlockEnum]._isReady = true - } }) - }), [t, nodesDefaultConfigs]) + }), [t]) } export const useNodesExtraData = () => { From 9b069bd3d4ae38b3c18613dff7cf41aafe634262 Mon Sep 17 00:00:00 2001 From: StyleZhang Date: Fri, 15 Mar 2024 20:17:58 +0800 Subject: [PATCH 5/9] node value form --- .../workflow/panel/inputs-panel.tsx | 72 ++++++++++--------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/web/app/components/workflow/panel/inputs-panel.tsx b/web/app/components/workflow/panel/inputs-panel.tsx index 430a0728917a61..0c187289a4b97c 100644 --- a/web/app/components/workflow/panel/inputs-panel.tsx +++ b/web/app/components/workflow/panel/inputs-panel.tsx @@ -44,41 +44,43 @@ const InputsPanel = () => { } return ( -
-
- {t('workflow.singleRun.testRun')} -
-
- { - variables.map(variable => ( -
- handleValueChange(variable.variable, v)} - /> -
- )) - } -
-
- - +
+
+
+ {t('workflow.singleRun.testRun')} +
+
+ { + variables.map(variable => ( +
+ handleValueChange(variable.variable, v)} + /> +
+ )) + } +
+
+ + +
) From e3c65c072c3765a23c2f4aee24168984ede19472 Mon Sep 17 00:00:00 2001 From: StyleZhang Date: Fri, 15 Mar 2024 20:26:00 +0800 Subject: [PATCH 6/9] node value init --- .../workflow/hooks/use-nodes-interactions.ts | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/web/app/components/workflow/hooks/use-nodes-interactions.ts b/web/app/components/workflow/hooks/use-nodes-interactions.ts index a5c7f00da75e81..d13f0f89e3f490 100644 --- a/web/app/components/workflow/hooks/use-nodes-interactions.ts +++ b/web/app/components/workflow/hooks/use-nodes-interactions.ts @@ -1,4 +1,5 @@ import { useCallback, useRef } from 'react' +import { useTranslation } from 'react-i18next' import produce from 'immer' import type { HandleType, @@ -20,6 +21,7 @@ import type { import { BlockEnum } from '../types' import { useWorkflowStore } from '../store' import { + NODES_INITIAL_DATA, NODE_WIDTH_X_OFFSET, Y_OFFSET, } from '../constants' @@ -27,17 +29,14 @@ import { generateNewNode, getNodesConnectedSourceOrTargetHandleIdsMap, } from '../utils' -import { - useNodesExtraData, - useNodesInitialData, -} from './use-nodes-data' +import { useNodesExtraData } from './use-nodes-data' import { useNodesSyncDraft } from './use-nodes-sync-draft' import { useWorkflow } from './use-workflow' export const useNodesInteractions = () => { + const { t } = useTranslation() const store = useStoreApi() const workflowStore = useWorkflowStore() - const nodesInitialData = useNodesInitialData() const nodesExtraData = useNodesExtraData() const { handleSyncWorkflowDraft } = useNodesSyncDraft() const { getAfterNodesInSameBranch } = useWorkflow() @@ -422,8 +421,8 @@ export const useNodesInteractions = () => { const nodesWithSameType = nodes.filter(node => node.data.type === nodeType) const newNode = generateNewNode({ data: { - ...nodesInitialData[nodeType], - title: nodesWithSameType.length > 0 ? `${nodesInitialData[nodeType].title} ${nodesWithSameType.length + 1}` : nodesInitialData[nodeType].title, + ...NODES_INITIAL_DATA[nodeType], + title: nodesWithSameType.length > 0 ? `${t(`workflow.blocks.${nodeType}`)} ${nodesWithSameType.length + 1}` : t(`workflow.blocks.${nodeType}`), ...(toolDefaultValue || {}), selected: true, }, @@ -566,7 +565,7 @@ export const useNodesInteractions = () => { setEdges(newEdges) } handleSyncWorkflowDraft() - }, [store, nodesInitialData, handleSyncWorkflowDraft, getAfterNodesInSameBranch, workflowStore]) + }, [store, handleSyncWorkflowDraft, getAfterNodesInSameBranch, workflowStore, t]) const handleNodeChange = useCallback(( currentNodeId: string, @@ -591,8 +590,8 @@ export const useNodesInteractions = () => { const nodesWithSameType = nodes.filter(node => node.data.type === nodeType) const newCurrentNode = generateNewNode({ data: { - ...nodesInitialData[nodeType], - title: nodesWithSameType.length > 0 ? `${nodesInitialData[nodeType].title} ${nodesWithSameType.length + 1}` : nodesInitialData[nodeType].title, + ...NODES_INITIAL_DATA[nodeType], + title: nodesWithSameType.length > 0 ? `${t(`workflow.blocks.${nodeType}`)} ${nodesWithSameType.length + 1}` : t(`workflow.blocks.${nodeType}`), ...(toolDefaultValue || {}), _connectedSourceHandleIds: [], _connectedTargetHandleIds: [], @@ -632,7 +631,7 @@ export const useNodesInteractions = () => { }) setEdges(newEdges) handleSyncWorkflowDraft() - }, [store, nodesInitialData, handleSyncWorkflowDraft, workflowStore]) + }, [store, handleSyncWorkflowDraft, workflowStore, t]) return { handleNodeDragStart, From 777cca1a099f9e1525367c6cdeb7aede40886067 Mon Sep 17 00:00:00 2001 From: Joel Date: Fri, 15 Mar 2024 20:50:55 +0800 Subject: [PATCH 7/9] feat: question classify init --- .../components/workflow/nodes/code/panel.tsx | 2 + .../workflow/nodes/code/use-config.ts | 7 ++ .../if-else/components/condition-item.tsx | 9 ++- .../if-else/components/condition-list.tsx | 5 ++ .../workflow/nodes/if-else/panel.tsx | 2 + .../workflow/nodes/if-else/use-config.ts | 13 +++- .../nodes/knowledge-retrieval/use-config.ts | 19 +++--- .../nodes/question-classifier/panel.tsx | 19 +----- .../nodes/question-classifier/use-config.ts | 64 +++++++++++++++++-- .../nodes/template-transform/panel.tsx | 2 + .../nodes/template-transform/use-config.ts | 11 +++- 11 files changed, 115 insertions(+), 38 deletions(-) diff --git a/web/app/components/workflow/nodes/code/panel.tsx b/web/app/components/workflow/nodes/code/panel.tsx index f03d41bfea8034..131257035b9657 100644 --- a/web/app/components/workflow/nodes/code/panel.tsx +++ b/web/app/components/workflow/nodes/code/panel.tsx @@ -41,6 +41,7 @@ const Panel: FC> = ({ handleCodeLanguageChange, handleVarsChange, handleAddOutputVariable, + filterVar, // single run isShowSingleRun, hideSingleRun, @@ -67,6 +68,7 @@ const Panel: FC> = ({ nodeId={id} list={inputs.variables} onChange={handleVarListChange} + filterVar={filterVar} /> diff --git a/web/app/components/workflow/nodes/code/use-config.ts b/web/app/components/workflow/nodes/code/use-config.ts index 1df9e5381f82cd..7f6768a398d941 100644 --- a/web/app/components/workflow/nodes/code/use-config.ts +++ b/web/app/components/workflow/nodes/code/use-config.ts @@ -2,6 +2,8 @@ import { useCallback } from 'react' import produce from 'immer' import useVarList from '../_base/hooks/use-var-list' import useOutputVarList from '../_base/hooks/use-output-var-list' +import { VarType } from '../../types' +import type { Var } from '../../types' import type { CodeLanguage, CodeNodeType } from './types' import useNodeCrud from '@/app/components/workflow/nodes/_base/hooks/use-node-crud' import useOneStepRun from '@/app/components/workflow/nodes/_base/hooks/use-one-step-run' @@ -32,6 +34,10 @@ const useConfig = (id: string, payload: CodeNodeType) => { setInputs, }) + const filterVar = useCallback((varPayload: Var) => { + return [VarType.string, VarType.number, VarType.object, VarType.array, VarType.arrayNumber, VarType.arrayString, VarType.arrayObject].includes(varPayload.type) + }, []) + // single run const { isShowSingleRun, @@ -72,6 +78,7 @@ const useConfig = (id: string, payload: CodeNodeType) => { handleCodeChange, handleCodeLanguageChange, handleVarsChange, + filterVar, handleAddOutputVariable, // single run isShowSingleRun, diff --git a/web/app/components/workflow/nodes/if-else/components/condition-item.tsx b/web/app/components/workflow/nodes/if-else/components/condition-item.tsx index 2ee7f08cd6b495..9102bb3e68e6f4 100644 --- a/web/app/components/workflow/nodes/if-else/components/condition-item.tsx +++ b/web/app/components/workflow/nodes/if-else/components/condition-item.tsx @@ -7,7 +7,7 @@ import VarReferencePicker from '../../_base/components/variable/var-reference-pi import { isComparisonOperatorNeedTranslate } from '../utils' import type { Condition } from '@/app/components/workflow/nodes/if-else/types' import { ComparisonOperator, LogicalOperator } from '@/app/components/workflow/nodes/if-else/types' -import type { ValueSelector } from '@/app/components/workflow/types' +import type { ValueSelector, Var } from '@/app/components/workflow/types' import { Trash03 } from '@/app/components/base/icons/src/vender/line/general' import { RefreshCw05 } from '@/app/components/base/icons/src/vender/line/arrows' import Selector from '@/app/components/workflow/nodes/_base/components/selector' @@ -73,6 +73,7 @@ type ItemProps = { isShowLogicalOperator?: boolean logicalOperator: LogicalOperator onLogicalOperatorToggle: () => void + filterVar: (varPayload: Var) => boolean } const Item: FC = ({ @@ -85,14 +86,15 @@ const Item: FC = ({ isShowLogicalOperator, logicalOperator, onLogicalOperatorToggle, + filterVar, }) => { const { t } = useTranslation() const isValueReadOnly = [ComparisonOperator.empty, ComparisonOperator.notEmpty, ComparisonOperator.isNull, ComparisonOperator.isNotNull].includes(payload.comparison_operator) - const handleVarReferenceChange = useCallback((value: ValueSelector) => { + const handleVarReferenceChange = useCallback((value: ValueSelector | string) => { onChange({ ...payload, - variable_selector: value, + variable_selector: value as ValueSelector, }) // TODO: handle value type change will effect the comparisonOperators }, [onChange, payload]) @@ -140,6 +142,7 @@ const Item: FC = ({ className='grow' value={payload.variable_selector} onChange={handleVarReferenceChange} + filterVar={filterVar} /> void logicalOperator: LogicalOperator onLogicalOperatorToggle: () => void + filterVar: (varPayload: Var) => boolean } const ConditionList: FC = ({ @@ -24,6 +26,7 @@ const ConditionList: FC = ({ onChange, logicalOperator, onLogicalOperatorToggle, + filterVar, }) => { const handleItemChange = useCallback((index: number) => { return (newItem: Condition) => { @@ -59,6 +62,7 @@ const ConditionList: FC = ({ onRemove={handleItemRemove(0)} logicalOperator={logicalOperator} onLogicalOperatorToggle={onLogicalOperatorToggle} + filterVar={filterVar} /> { list.length > 1 && ( @@ -74,6 +78,7 @@ const ConditionList: FC = ({ isShowLogicalOperator logicalOperator={logicalOperator} onLogicalOperatorToggle={onLogicalOperatorToggle} + filterVar={filterVar} /> ))) } diff --git a/web/app/components/workflow/nodes/if-else/panel.tsx b/web/app/components/workflow/nodes/if-else/panel.tsx index 5cbe28be7b0c6c..d3dd3be05378a8 100644 --- a/web/app/components/workflow/nodes/if-else/panel.tsx +++ b/web/app/components/workflow/nodes/if-else/panel.tsx @@ -22,6 +22,7 @@ const Panel: FC> = ({ handleConditionsChange, handleAddCondition, handleLogicalOperatorToggle, + filterVar, } = useConfig(id, data) return (
@@ -38,6 +39,7 @@ const Panel: FC> = ({ onChange={handleConditionsChange} logicalOperator={inputs.logical_operator} onLogicalOperatorToggle={handleLogicalOperatorToggle} + filterVar={filterVar} /> { draft.conditions = newConditions }) setInputs(newInputs) - }, []) + }, [inputs, setInputs]) const handleAddCondition = useCallback(() => { const newInputs = produce(inputs, (draft) => { @@ -24,20 +26,25 @@ const useConfig = (id: string, payload: IfElseNodeType) => { }) }) setInputs(newInputs) - }, [inputs]) + }, [inputs, setInputs]) const handleLogicalOperatorToggle = useCallback(() => { const newInputs = produce(inputs, (draft) => { draft.logical_operator = draft.logical_operator === LogicalOperator.and ? LogicalOperator.or : LogicalOperator.and }) setInputs(newInputs) - }, [inputs]) + }, [inputs, setInputs]) + + const filterVar = useCallback((varPayload: Var) => { + return varPayload.type !== VarType.arrayFile + }, []) return { inputs, handleConditionsChange, handleAddCondition, handleLogicalOperatorToggle, + filterVar, } } diff --git a/web/app/components/workflow/nodes/knowledge-retrieval/use-config.ts b/web/app/components/workflow/nodes/knowledge-retrieval/use-config.ts index e37e1ce9cae736..81d47312393ae4 100644 --- a/web/app/components/workflow/nodes/knowledge-retrieval/use-config.ts +++ b/web/app/components/workflow/nodes/knowledge-retrieval/use-config.ts @@ -12,6 +12,7 @@ import useOneStepRun from '@/app/components/workflow/nodes/_base/hooks/use-one-s const useConfig = (id: string, payload: KnowledgeRetrievalNodeType) => { const isChatMode = useIsChatMode() + console.log() const { getBeforeNodesInSameBranch } = useWorkflow() const startNode = getBeforeNodesInSameBranch(id).find(node => node.data.type === BlockEnum.Start) const startNodeId = startNode?.id @@ -55,14 +56,16 @@ const useConfig = (id: string, payload: KnowledgeRetrievalNodeType) => { }, []) useEffect(() => { - if (inputs._isReady) { - if (isChatMode && inputs.query_variable_selector.length === 0 && startNodeId) { - handleQueryVarChange( - [startNodeId, 'sys.query'], - ) - } - } - }, [inputs._isReady]) + let query_variable_selector: ValueSelector = [] + if (isChatMode && inputs.query_variable_selector.length === 0 && startNodeId) + query_variable_selector = [startNodeId, 'sys.query'] + + setInputs({ + ...inputs, + query_variable_selector, + }) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) const handleOnDatasetsChange = useCallback((newDatasets: DataSet[]) => { const newInputs = produce(inputs, (draft) => { diff --git a/web/app/components/workflow/nodes/question-classifier/panel.tsx b/web/app/components/workflow/nodes/question-classifier/panel.tsx index e094275ada0bfe..52919ad885be72 100644 --- a/web/app/components/workflow/nodes/question-classifier/panel.tsx +++ b/web/app/components/workflow/nodes/question-classifier/panel.tsx @@ -1,5 +1,5 @@ import type { FC } from 'react' -import React, { useEffect } from 'react' +import React from 'react' import { useTranslation } from 'react-i18next' import VarReferencePicker from '../_base/components/variable/var-reference-picker' import useConfig from './use-config' @@ -11,7 +11,6 @@ import ModelParameterModal from '@/app/components/header/account-setting/model-p import { InputVarType, type NodePanelProps } from '@/app/components/workflow/types' import BeforeRunForm from '@/app/components/workflow/nodes/_base/components/before-run-form' import ResultPanel from '@/app/components/workflow/run/result-panel' -import { useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks' const i18nPrefix = 'workflow.nodes.questionClassifiers' @@ -21,10 +20,6 @@ const Panel: FC> = ({ }) => { const { t } = useTranslation() const readOnly = false - const { - currentProvider, - currentModel, - } = useModelListAndDefaultModelAndCurrentProviderAndModel(1) const { inputs, @@ -42,20 +37,11 @@ const Panel: FC> = ({ query, setQuery, runResult, + filterVar, } = useConfig(id, data) const model = inputs.model - useEffect(() => { - if (currentProvider?.provider && currentModel?.model && !model.provider) { - handleModelChanged({ - provider: currentProvider?.provider, - modelId: currentModel?.model, - mode: currentModel?.model_properties?.mode as string, - }) - } - }, [model.provider, currentProvider, currentModel, handleModelChanged]) - return (
@@ -68,6 +54,7 @@ const Panel: FC> = ({ nodeId={id} value={inputs.query_variable_selector} onChange={handleQueryVarChange} + filterVar={filterVar} /> { + const isChatMode = useIsChatMode() + const defaultConfig = useStore(s => s.nodesDefaultConfigs)[payload.type] + const { getBeforeNodesInSameBranch } = useWorkflow() + const startNode = getBeforeNodesInSameBranch(id).find(node => node.data.type === BlockEnum.Start) + const startNodeId = startNode?.id const { inputs, setInputs } = useNodeCrud(id, payload) + const inputRef = useRef(inputs) + useEffect(() => { + inputRef.current = inputs + }, [inputs]) // model + const { + currentProvider, + currentModel, + } = useModelListAndDefaultModelAndCurrentProviderAndModel(1) + + const model = inputs.model + const handleModelChanged = useCallback((model: { provider: string; modelId: string; mode?: string }) => { - const newInputs = produce(inputs, (draft) => { + const newInputs = produce(inputRef.current, (draft) => { draft.model.provider = model.provider draft.model.name = model.modelId draft.model.mode = model.mode! }) setInputs(newInputs) - }, [inputs, setInputs]) + }, [setInputs]) + + useEffect(() => { + if (currentProvider?.provider && currentModel?.model && !model.provider) { + handleModelChanged({ + provider: currentProvider?.provider, + modelId: currentModel?.model, + mode: currentModel?.model_properties?.mode as string, + }) + } + }, [model.provider, currentProvider, currentModel, handleModelChanged]) const handleCompletionParamsChange = useCallback((newParams: Record) => { const newInputs = produce(inputs, (draft) => { @@ -25,13 +55,30 @@ const useConfig = (id: string, payload: QuestionClassifierNodeType) => { setInputs(newInputs) }, [inputs, setInputs]) - const handleQueryVarChange = useCallback((newVar: ValueSelector) => { + const handleQueryVarChange = useCallback((newVar: ValueSelector | string) => { const newInputs = produce(inputs, (draft) => { - draft.query_variable_selector = newVar + draft.query_variable_selector = newVar as ValueSelector }) setInputs(newInputs) + // console.log(newInputs.query_variable_selector) }, [inputs, setInputs]) + useEffect(() => { + const isReady = defaultConfig && Object.keys(defaultConfig).length > 0 + if (isReady) { + let query_variable_selector: ValueSelector = [] + if (isChatMode && inputs.query_variable_selector.length === 0 && startNodeId) + query_variable_selector = [startNodeId, 'sys.query'] + setInputs({ + ...inputs, + ...defaultConfig, + query_variable_selector: inputs.query_variable_selector.length > 0 ? inputs.query_variable_selector : query_variable_selector, + }) + console.log(query_variable_selector) + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [defaultConfig]) + const handleClassesChange = useCallback((newClasses: any) => { const newInputs = produce(inputs, (draft) => { draft.classes = newClasses @@ -80,11 +127,16 @@ const useConfig = (id: string, payload: QuestionClassifierNodeType) => { }) }, [runInputData, setRunInputData]) + const filterVar = useCallback((varPayload: Var) => { + return varPayload.type === VarType.string + }, []) + return { inputs, handleModelChanged, handleCompletionParamsChange, handleQueryVarChange, + filterVar, handleTopicsChange: handleClassesChange, handleInstructionChange, handleMemoryChange, diff --git a/web/app/components/workflow/nodes/template-transform/panel.tsx b/web/app/components/workflow/nodes/template-transform/panel.tsx index 725e4f67b27956..b3f336ef3d855f 100644 --- a/web/app/components/workflow/nodes/template-transform/panel.tsx +++ b/web/app/components/workflow/nodes/template-transform/panel.tsx @@ -29,6 +29,7 @@ const Panel: FC> = ({ handleVarListChange, handleAddVariable, handleCodeChange, + filterVar, // single run isShowSingleRun, hideSingleRun, @@ -56,6 +57,7 @@ const Panel: FC> = ({ readonly={readOnly} list={inputs.variables} onChange={handleVarListChange} + filterVar={filterVar} /> diff --git a/web/app/components/workflow/nodes/template-transform/use-config.ts b/web/app/components/workflow/nodes/template-transform/use-config.ts index 534bec9ea4ba46..c5235fde1dcfa1 100644 --- a/web/app/components/workflow/nodes/template-transform/use-config.ts +++ b/web/app/components/workflow/nodes/template-transform/use-config.ts @@ -1,6 +1,8 @@ import { useCallback } from 'react' import produce from 'immer' import useVarList from '../_base/hooks/use-var-list' +import type { Var } from '../../types' +import { VarType } from '../../types' import type { TemplateTransformNodeType } from './types' import useNodeCrud from '@/app/components/workflow/nodes/_base/hooks/use-node-crud' import useOneStepRun from '@/app/components/workflow/nodes/_base/hooks/use-one-step-run' @@ -17,7 +19,7 @@ const useConfig = (id: string, payload: TemplateTransformNodeType) => { draft.template = template }) setInputs(newInputs) - }, [setInputs]) + }, [inputs, setInputs]) // single run const { @@ -48,13 +50,18 @@ const useConfig = (id: string, payload: TemplateTransformNodeType) => { const setInputVarValues = useCallback((newPayload: Record) => { setRunInputData(newPayload) - }, [runInputData, setRunInputData]) + }, [setRunInputData]) + + const filterVar = useCallback((varPayload: Var) => { + return [VarType.string, VarType.number, VarType.object, VarType.array, VarType.arrayNumber, VarType.arrayString, VarType.arrayObject].includes(varPayload.type) + }, []) return { inputs, handleVarListChange, handleAddVariable, handleCodeChange, + filterVar, // single run isShowSingleRun, hideSingleRun, From e5c8743712401e226ba3a7fc2ffbcd0f7391c540 Mon Sep 17 00:00:00 2001 From: JzoNg Date: Fri, 15 Mar 2024 21:15:22 +0800 Subject: [PATCH 8/9] fix elpased time --- web/app/components/workflow/run/node.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/web/app/components/workflow/run/node.tsx b/web/app/components/workflow/run/node.tsx index f4cbbb80ee8ca8..42acf8ef08b4ec 100644 --- a/web/app/components/workflow/run/node.tsx +++ b/web/app/components/workflow/run/node.tsx @@ -24,6 +24,7 @@ const NodePanel: FC = ({ nodeInfo, collapsed, collapseHandle }) => { return `${(time * 1000).toFixed(3)} ms` if (time > 60) return `${parseInt(Math.round(time / 60).toString())} m ${(time % 60).toFixed(3)} s` + return `${time.toFixed(3)} s` } const getTokenCount = (tokens: number) => { From a577db9ddd12bad12c7e23f5565e0a49802e3d65 Mon Sep 17 00:00:00 2001 From: StyleZhang Date: Fri, 15 Mar 2024 21:33:30 +0800 Subject: [PATCH 9/9] stop run --- .../line/mediaAndDevices/stop-circle.svg | 8 +++ .../line/mediaAndDevices/StopCircle.json | 59 +++++++++++++++++ .../line/mediaAndDevices/StopCircle.tsx | 16 +++++ .../src/vender/line/mediaAndDevices/index.ts | 1 + .../base/icons/src/vender/workflow/index.ts | 2 +- .../workflow/header/run-and-history.tsx | 66 ++++++++++++------- .../workflow/hooks/use-workflow-run.ts | 19 ++++-- .../panel/debug-and-preview/chat-wrapper.tsx | 10 ++- 8 files changed, 143 insertions(+), 38 deletions(-) create mode 100644 web/app/components/base/icons/assets/vender/line/mediaAndDevices/stop-circle.svg create mode 100644 web/app/components/base/icons/src/vender/line/mediaAndDevices/StopCircle.json create mode 100644 web/app/components/base/icons/src/vender/line/mediaAndDevices/StopCircle.tsx diff --git a/web/app/components/base/icons/assets/vender/line/mediaAndDevices/stop-circle.svg b/web/app/components/base/icons/assets/vender/line/mediaAndDevices/stop-circle.svg new file mode 100644 index 00000000000000..7a7983ae5cd1bd --- /dev/null +++ b/web/app/components/base/icons/assets/vender/line/mediaAndDevices/stop-circle.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/web/app/components/base/icons/src/vender/line/mediaAndDevices/StopCircle.json b/web/app/components/base/icons/src/vender/line/mediaAndDevices/StopCircle.json new file mode 100644 index 00000000000000..2d456014b83352 --- /dev/null +++ b/web/app/components/base/icons/src/vender/line/mediaAndDevices/StopCircle.json @@ -0,0 +1,59 @@ +{ + "icon": { + "type": "element", + "isRootNode": true, + "name": "svg", + "attributes": { + "width": "17", + "height": "16", + "viewBox": "0 0 17 16", + "fill": "none", + "xmlns": "http://www.w3.org/2000/svg" + }, + "children": [ + { + "type": "element", + "name": "g", + "attributes": { + "id": "Icon" + }, + "children": [ + { + "type": "element", + "name": "g", + "attributes": { + "id": "Icon_2" + }, + "children": [ + { + "type": "element", + "name": "path", + "attributes": { + "d": "M8.49967 14.6663C12.1816 14.6663 15.1663 11.6816 15.1663 7.99967C15.1663 4.31778 12.1816 1.33301 8.49967 1.33301C4.81778 1.33301 1.83301 4.31778 1.83301 7.99967C1.83301 11.6816 4.81778 14.6663 8.49967 14.6663Z", + "stroke": "currentColor", + "stroke-width": "1.5", + "stroke-linecap": "round", + "stroke-linejoin": "round" + }, + "children": [] + }, + { + "type": "element", + "name": "path", + "attributes": { + "d": "M10.4997 5.99967H6.49967V9.99967H10.4997V5.99967Z", + "stroke": "currentColor", + "stroke-width": "1.5", + "stroke-linecap": "round", + "stroke-linejoin": "round" + }, + "children": [] + } + ] + } + ] + } + ] + }, + "name": "StopCircle" +} \ No newline at end of file diff --git a/web/app/components/base/icons/src/vender/line/mediaAndDevices/StopCircle.tsx b/web/app/components/base/icons/src/vender/line/mediaAndDevices/StopCircle.tsx new file mode 100644 index 00000000000000..6022e6bbfb6fad --- /dev/null +++ b/web/app/components/base/icons/src/vender/line/mediaAndDevices/StopCircle.tsx @@ -0,0 +1,16 @@ +// GENERATE BY script +// DON NOT EDIT IT MANUALLY + +import * as React from 'react' +import data from './StopCircle.json' +import IconBase from '@/app/components/base/icons/IconBase' +import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase' + +const Icon = React.forwardRef, Omit>(( + props, + ref, +) => ) + +Icon.displayName = 'StopCircle' + +export default Icon diff --git a/web/app/components/base/icons/src/vender/line/mediaAndDevices/index.ts b/web/app/components/base/icons/src/vender/line/mediaAndDevices/index.ts index d78d0c7980a0cb..0253031952b57f 100644 --- a/web/app/components/base/icons/src/vender/line/mediaAndDevices/index.ts +++ b/web/app/components/base/icons/src/vender/line/mediaAndDevices/index.ts @@ -2,4 +2,5 @@ export { default as Microphone01 } from './Microphone01' export { default as Play } from './Play' export { default as SlidersH } from './SlidersH' export { default as Speaker } from './Speaker' +export { default as StopCircle } from './StopCircle' export { default as Stop } from './Stop' diff --git a/web/app/components/base/icons/src/vender/workflow/index.ts b/web/app/components/base/icons/src/vender/workflow/index.ts index ec1f4e5c013cac..a0ebc3001472c3 100644 --- a/web/app/components/base/icons/src/vender/workflow/index.ts +++ b/web/app/components/base/icons/src/vender/workflow/index.ts @@ -1,5 +1,5 @@ -export { default as Code } from './Code' export { default as Answer } from './Answer' +export { default as Code } from './Code' export { default as End } from './End' export { default as Home } from './Home' export { default as Http } from './Http' diff --git a/web/app/components/workflow/header/run-and-history.tsx b/web/app/components/workflow/header/run-and-history.tsx index 73036e5fe1575f..204080a7a6b3bf 100644 --- a/web/app/components/workflow/header/run-and-history.tsx +++ b/web/app/components/workflow/header/run-and-history.tsx @@ -10,7 +10,10 @@ import { useWorkflowRun, } from '../hooks' import { WorkflowRunningStatus } from '../types' -import { Play } from '@/app/components/base/icons/src/vender/line/mediaAndDevices' +import { + Play, + StopCircle, +} from '@/app/components/base/icons/src/vender/line/mediaAndDevices' import { ClockPlay } from '@/app/components/base/icons/src/vender/line/time' import TooltipPlus from '@/app/components/base/tooltip-plus' import { Loading02 } from '@/app/components/base/icons/src/vender/line/general' @@ -18,6 +21,7 @@ import { Loading02 } from '@/app/components/base/icons/src/vender/line/general' const RunMode = memo(() => { const { t } = useTranslation() const workflowStore = useWorkflowStore() + const { handleStopRun } = useWorkflowRun() const runningStatus = useStore(s => s.runningStatus) const showInputsPanel = useStore(s => s.showInputsPanel) const isRunning = runningStatus === WorkflowRunningStatus.Running @@ -27,31 +31,43 @@ const RunMode = memo(() => { } return ( -
!isRunning && handleClick()} - > + <> +
!isRunning && handleClick()} + > + { + isRunning + ? ( + <> + + {t('workflow.common.running')} + + ) + : ( + <> + + {t('workflow.common.run')} + + ) + } +
{ - isRunning - ? ( - <> - - {t('workflow.common.running')} - - ) - : ( - <> - - {t('workflow.common.run')} - - ) + isRunning && ( +
+ +
+ ) } -
+ ) }) RunMode.displayName = 'RunMode' @@ -116,7 +132,7 @@ const RunAndHistory: FC = () => { flex items-center justify-center w-7 h-7 rounded-md hover:bg-black/5 cursor-pointer ${showRunHistory && 'bg-primary-50'} `} - onClick={() => workflowStore.setState({ showRunHistory: true })} + onClick={() => workflowStore.setState({ showRunHistory: !showRunHistory })} >
diff --git a/web/app/components/workflow/hooks/use-workflow-run.ts b/web/app/components/workflow/hooks/use-workflow-run.ts index e89fd7d61f865b..32c767735e7a7d 100644 --- a/web/app/components/workflow/hooks/use-workflow-run.ts +++ b/web/app/components/workflow/hooks/use-workflow-run.ts @@ -1,7 +1,4 @@ -import { - useCallback, - useRef, -} from 'react' +import { useCallback } from 'react' import { useReactFlow, useStoreApi, @@ -16,12 +13,12 @@ import { NODE_WIDTH } from '../constants' import { useStore as useAppStore } from '@/app/components/app/store' import type { IOtherOptions } from '@/service/base' import { ssePost } from '@/service/base' +import { stopWorkflowRun } from '@/service/workflow' export const useWorkflowRun = () => { const store = useStoreApi() const workflowStore = useWorkflowStore() const reactflow = useReactFlow() - const workflowContainerRef = useRef(null) const handleBackupDraft = useCallback(() => { const { @@ -62,6 +59,9 @@ export const useWorkflowRun = () => { const handleRunSetting = useCallback((shouldClear?: boolean) => { workflowStore.setState({ runningStatus: shouldClear ? undefined : WorkflowRunningStatus.Waiting }) + workflowStore.setState({ taskId: '' }) + workflowStore.setState({ currentSequenceNumber: 0 }) + workflowStore.setState({ workflowRunId: '' }) const { setNodes, getNodes, @@ -174,10 +174,17 @@ export const useWorkflowRun = () => { ) }, [store, reactflow, workflowStore]) + const handleStopRun = useCallback(() => { + const appId = useAppStore.getState().appDetail?.id + const taskId = workflowStore.getState().taskId + + stopWorkflowRun(`/apps/${appId}/workflow-runs/tasks/${taskId}/stop`) + }, [workflowStore]) + return { handleBackupDraft, handleRunSetting, handleRun, - workflowContainerRef, + handleStopRun, } } diff --git a/web/app/components/workflow/panel/debug-and-preview/chat-wrapper.tsx b/web/app/components/workflow/panel/debug-and-preview/chat-wrapper.tsx index f8bd3ef3df27df..f1804157552eb6 100644 --- a/web/app/components/workflow/panel/debug-and-preview/chat-wrapper.tsx +++ b/web/app/components/workflow/panel/debug-and-preview/chat-wrapper.tsx @@ -4,6 +4,7 @@ import { useMemo, } from 'react' import { useWorkflowStore } from '../../store' +import { useWorkflowRun } from '../../hooks' import UserInput from './user-input' import { useChat } from './hooks' import Chat from '@/app/components/base/chat/chat' @@ -11,11 +12,11 @@ import type { OnSend } from '@/app/components/base/chat/types' import { useFeaturesStore } from '@/app/components/base/features/hooks' import { fetchConvesationMessages } from '@/service/debug' import { useStore as useAppStore } from '@/app/components/app/store' -import { stopWorkflowRun } from '@/service/workflow' const ChatWrapper = () => { const workflowStore = useWorkflowStore() const featuresStore = useFeaturesStore() + const { handleStopRun } = useWorkflowRun() const features = featuresStore!.getState().features const config = useMemo(() => { @@ -58,12 +59,9 @@ const ChatWrapper = () => { }, [conversationId, handleSend, workflowStore]) const doStop = useCallback(() => { - const appId = useAppStore.getState().appDetail?.id - const taskId = workflowStore.getState().taskId - handleStop() - stopWorkflowRun(`/apps/${appId}/workflow-runs/tasks/${taskId}/stop`) - }, [handleStop, workflowStore]) + handleStopRun() + }, [handleStop, handleStopRun]) return (