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 ea4f463c478daa..12113995d95e14 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 @@ -1,19 +1,26 @@ import { + forwardRef, memo, useCallback, + useImperativeHandle, useMemo, } from 'react' import { useWorkflowStore } from '../../store' import { useWorkflowRun } from '../../hooks' import UserInput from './user-input' import { useChat } from './hooks' +import type { ChatWrapperRefType } from './index' import Chat from '@/app/components/base/chat/chat' import type { OnSend } from '@/app/components/base/chat/types' import { useFeaturesStore } from '@/app/components/base/features/hooks' -import { fetchSuggestedQuestions } from '@/service/debug' +import { + fetchSuggestedQuestions, + stopChatMessageResponding, +} from '@/service/debug' import { useStore as useAppStore } from '@/app/components/app/store' -const ChatWrapper = () => { +const ChatWrapper = forwardRef((_, ref) => { + const appDetail = useAppStore(s => s.appDetail) const workflowStore = useWorkflowStore() const featuresStore = useFeaturesStore() const { handleStopRun } = useWorkflowRun() @@ -38,31 +45,38 @@ const ChatWrapper = () => { isResponding, suggestedQuestions, handleSend, - } = useChat(config) + handleRestart, + } = useChat( + config, + [], + taskId => stopChatMessageResponding(appDetail!.id, taskId), + ) const doSend = useCallback((query, files) => { - const appId = useAppStore.getState().appDetail?.id - - if (appId) { - handleSend( - { - query, - files, - inputs: workflowStore.getState().inputs, - conversation_id: conversationId, - }, - { - onGetSuggestedQuestions: (messageId, getAbortController) => fetchSuggestedQuestions(appId, messageId, getAbortController), - }, - ) - } - }, [conversationId, handleSend, workflowStore]) + handleSend( + { + query, + files, + inputs: workflowStore.getState().inputs, + conversation_id: conversationId, + }, + { + onGetSuggestedQuestions: (messageId, getAbortController) => fetchSuggestedQuestions(appDetail!.id, messageId, getAbortController), + }, + ) + }, [conversationId, handleSend, workflowStore, appDetail]) const doStop = useCallback(() => { handleStop() handleStopRun() }, [handleStop, handleStopRun]) + useImperativeHandle(ref, () => { + return { + handleRestart, + } + }, [handleRestart]) + return ( { suggestedQuestions={suggestedQuestions} /> ) -} +}) + +ChatWrapper.displayName = 'ChatWrapper' export default memo(ChatWrapper) diff --git a/web/app/components/workflow/panel/debug-and-preview/hooks.ts b/web/app/components/workflow/panel/debug-and-preview/hooks.ts index d1e5cacf8dd31a..4e1a2ea1213546 100644 --- a/web/app/components/workflow/panel/debug-and-preview/hooks.ts +++ b/web/app/components/workflow/panel/debug-and-preview/hooks.ts @@ -19,12 +19,14 @@ type SendCallback = { export const useChat = ( config: any, prevChatList?: ChatItem[], + stopChat?: (taskId: string) => void, ) => { const { t } = useTranslation() const { notify } = useToastContext() const { handleRun } = useWorkflowRun() const hasStopResponded = useRef(false) const connversationId = useRef('') + const taskIdRef = useRef('') const [chatList, setChatList] = useState(prevChatList || []) const chatListRef = useRef(prevChatList || []) const [isResponding, setIsResponding] = useState(false) @@ -52,10 +54,33 @@ export const useChat = ( const handleStop = useCallback(() => { hasStopResponded.current = true handleResponding(false) + if (stopChat && taskIdRef.current) + stopChat(taskIdRef.current) if (suggestedQuestionsAbortControllerRef.current) suggestedQuestionsAbortControllerRef.current.abort() - }, [handleResponding]) + }, [handleResponding, stopChat]) + + const handleRestart = useCallback(() => { + connversationId.current = '' + taskIdRef.current = '' + handleStop() + const newChatList = config?.opening_statement + ? [{ + id: `${Date.now()}`, + content: config.opening_statement, + isAnswer: true, + isOpeningStatement: true, + suggestedQuestions: config.suggested_questions, + }] + : [] + handleUpdateChatList(newChatList) + setSuggestQuestions([]) + }, [ + config, + handleStop, + handleUpdateChatList, + ]) const updateCurrentQA = useCallback(({ responseItem, @@ -140,7 +165,7 @@ export const useChat = ( handleRun( params, { - onData: (message: string, isFirstMessage: boolean, { conversationId: newConversationId, messageId }: any) => { + onData: (message: string, isFirstMessage: boolean, { conversationId: newConversationId, messageId, taskId }: any) => { responseItem.content = responseItem.content + message if (messageId && !hasSetResponseId) { @@ -151,6 +176,7 @@ export const useChat = ( if (isFirstMessage && newConversationId) connversationId.current = newConversationId + taskIdRef.current = taskId if (messageId) responseItem.id = messageId @@ -207,6 +233,7 @@ export const useChat = ( chatList, handleSend, handleStop, + handleRestart, isResponding, suggestedQuestions, } diff --git a/web/app/components/workflow/panel/debug-and-preview/index.tsx b/web/app/components/workflow/panel/debug-and-preview/index.tsx index de88f8c30ad861..df6abcdb77013e 100644 --- a/web/app/components/workflow/panel/debug-and-preview/index.tsx +++ b/web/app/components/workflow/panel/debug-and-preview/index.tsx @@ -1,10 +1,19 @@ -import { memo } from 'react' +import { + memo, + useRef, +} from 'react' import { useTranslation } from 'react-i18next' import { useStore } from '../../store' import ChatWrapper from './chat-wrapper' +import Button from '@/app/components/base/button' +import { RefreshCcw01 } from '@/app/components/base/icons/src/vender/line/arrows' +export type ChatWrapperRefType = { + handleRestart: () => void +} const DebugAndPreview = () => { const { t } = useTranslation() + const chatRef = useRef({ handleRestart: () => {} }) const showRunHistory = useStore(s => s.showRunHistory) return ( @@ -19,10 +28,16 @@ const DebugAndPreview = () => { >
{t('workflow.common.debugAndPreview').toLocaleUpperCase()} -
+
-
- +
+
)