mirror of
http://112.124.100.131/huang.ze/ebiz-dify-ai.git
synced 2025-12-09 19:06:51 +08:00
feat: regenerate in Chat, agent and Chatflow app (#7661)
This commit is contained in:
@@ -2,7 +2,6 @@ import {
|
||||
memo,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { RiCloseLine } from '@remixicon/react'
|
||||
@@ -17,50 +16,70 @@ import type { ChatItem } from '@/app/components/base/chat/types'
|
||||
import { fetchConversationMessages } from '@/service/debug'
|
||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
import { UUID_NIL } from '@/app/components/base/chat/constants'
|
||||
|
||||
function appendQAToChatList(newChatList: ChatItem[], item: any) {
|
||||
newChatList.push({
|
||||
id: item.id,
|
||||
content: item.answer,
|
||||
feedback: item.feedback,
|
||||
isAnswer: true,
|
||||
citation: item.metadata?.retriever_resources,
|
||||
message_files: item.message_files?.filter((file: any) => file.belongs_to === 'assistant') || [],
|
||||
workflow_run_id: item.workflow_run_id,
|
||||
})
|
||||
newChatList.push({
|
||||
id: `question-${item.id}`,
|
||||
content: item.query,
|
||||
isAnswer: false,
|
||||
message_files: item.message_files?.filter((file: any) => file.belongs_to === 'user') || [],
|
||||
})
|
||||
}
|
||||
|
||||
function getFormattedChatList(messages: any[]) {
|
||||
const newChatList: ChatItem[] = []
|
||||
let nextMessageId = null
|
||||
for (const item of messages) {
|
||||
if (!item.parent_message_id) {
|
||||
appendQAToChatList(newChatList, item)
|
||||
break
|
||||
}
|
||||
|
||||
if (!nextMessageId) {
|
||||
appendQAToChatList(newChatList, item)
|
||||
nextMessageId = item.parent_message_id
|
||||
}
|
||||
else {
|
||||
if (item.id === nextMessageId || nextMessageId === UUID_NIL) {
|
||||
appendQAToChatList(newChatList, item)
|
||||
nextMessageId = item.parent_message_id
|
||||
}
|
||||
}
|
||||
}
|
||||
return newChatList.reverse()
|
||||
}
|
||||
|
||||
const ChatRecord = () => {
|
||||
const [fetched, setFetched] = useState(false)
|
||||
const [chatList, setChatList] = useState([])
|
||||
const [chatList, setChatList] = useState<ChatItem[]>([])
|
||||
const appDetail = useAppStore(s => s.appDetail)
|
||||
const workflowStore = useWorkflowStore()
|
||||
const { handleLoadBackupDraft } = useWorkflowRun()
|
||||
const historyWorkflowData = useStore(s => s.historyWorkflowData)
|
||||
const currentConversationID = historyWorkflowData?.conversation_id
|
||||
|
||||
const chatMessageList = useMemo(() => {
|
||||
const res: ChatItem[] = []
|
||||
if (chatList.length) {
|
||||
chatList.forEach((item: any) => {
|
||||
res.push({
|
||||
id: `question-${item.id}`,
|
||||
content: item.query,
|
||||
isAnswer: false,
|
||||
message_files: item.message_files?.filter((file: any) => file.belongs_to === 'user') || [],
|
||||
})
|
||||
res.push({
|
||||
id: item.id,
|
||||
content: item.answer,
|
||||
feedback: item.feedback,
|
||||
isAnswer: true,
|
||||
citation: item.metadata?.retriever_resources,
|
||||
message_files: item.message_files?.filter((file: any) => file.belongs_to === 'assistant') || [],
|
||||
workflow_run_id: item.workflow_run_id,
|
||||
})
|
||||
})
|
||||
}
|
||||
return res
|
||||
}, [chatList])
|
||||
|
||||
const handleFetchConversationMessages = useCallback(async () => {
|
||||
if (appDetail && currentConversationID) {
|
||||
try {
|
||||
setFetched(false)
|
||||
const res = await fetchConversationMessages(appDetail.id, currentConversationID)
|
||||
setFetched(true)
|
||||
setChatList((res as any).data)
|
||||
setChatList(getFormattedChatList((res as any).data))
|
||||
}
|
||||
catch (e) {
|
||||
|
||||
console.error(e)
|
||||
}
|
||||
finally {
|
||||
setFetched(true)
|
||||
}
|
||||
}
|
||||
}, [appDetail, currentConversationID])
|
||||
@@ -101,7 +120,7 @@ const ChatRecord = () => {
|
||||
config={{
|
||||
supportCitationHitInfo: true,
|
||||
} as any}
|
||||
chatList={chatMessageList}
|
||||
chatList={chatList}
|
||||
chatContainerClassName='px-4'
|
||||
chatContainerInnerClassName='pt-6 w-full max-w-full mx-auto'
|
||||
chatFooterClassName='px-4 rounded-b-2xl'
|
||||
|
||||
@@ -18,7 +18,7 @@ import ConversationVariableModal from './conversation-variable-modal'
|
||||
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 type { ChatItem, OnSend } from '@/app/components/base/chat/types'
|
||||
import { useFeaturesStore } from '@/app/components/base/features/hooks'
|
||||
import {
|
||||
fetchSuggestedQuestions,
|
||||
@@ -58,6 +58,8 @@ const ChatWrapper = forwardRef<ChatWrapperRefType, ChatWrapperProps>(({ showConv
|
||||
const {
|
||||
conversationId,
|
||||
chatList,
|
||||
chatListRef,
|
||||
handleUpdateChatList,
|
||||
handleStop,
|
||||
isResponding,
|
||||
suggestedQuestions,
|
||||
@@ -73,19 +75,36 @@ const ChatWrapper = forwardRef<ChatWrapperRefType, ChatWrapperProps>(({ showConv
|
||||
taskId => stopChatMessageResponding(appDetail!.id, taskId),
|
||||
)
|
||||
|
||||
const doSend = useCallback<OnSend>((query, files) => {
|
||||
const doSend = useCallback<OnSend>((query, files, last_answer) => {
|
||||
handleSend(
|
||||
{
|
||||
query,
|
||||
files,
|
||||
inputs: workflowStore.getState().inputs,
|
||||
conversation_id: conversationId,
|
||||
parent_message_id: last_answer?.id || chatListRef.current.at(-1)?.id || null,
|
||||
},
|
||||
{
|
||||
onGetSuggestedQuestions: (messageId, getAbortController) => fetchSuggestedQuestions(appDetail!.id, messageId, getAbortController),
|
||||
},
|
||||
)
|
||||
}, [conversationId, handleSend, workflowStore, appDetail])
|
||||
}, [chatListRef, conversationId, handleSend, workflowStore, appDetail])
|
||||
|
||||
const doRegenerate = useCallback((chatItem: ChatItem) => {
|
||||
const index = chatList.findIndex(item => item.id === chatItem.id)
|
||||
if (index === -1)
|
||||
return
|
||||
|
||||
const prevMessages = chatList.slice(0, index)
|
||||
const question = prevMessages.pop()
|
||||
const lastAnswer = prevMessages.at(-1)
|
||||
|
||||
if (!question)
|
||||
return
|
||||
|
||||
handleUpdateChatList(prevMessages)
|
||||
doSend(question.content, question.message_files, (!lastAnswer || lastAnswer.isOpeningStatement) ? undefined : lastAnswer)
|
||||
}, [chatList, handleUpdateChatList, doSend])
|
||||
|
||||
useImperativeHandle(ref, () => {
|
||||
return {
|
||||
@@ -107,6 +126,7 @@ const ChatWrapper = forwardRef<ChatWrapperRefType, ChatWrapperProps>(({ showConv
|
||||
chatFooterClassName='px-4 rounded-bl-2xl'
|
||||
chatFooterInnerClassName='pb-4 w-full max-w-full mx-auto'
|
||||
onSend={doSend}
|
||||
onRegenerate={doRegenerate}
|
||||
onStopResponding={handleStop}
|
||||
chatNode={(
|
||||
<>
|
||||
|
||||
@@ -387,6 +387,8 @@ export const useChat = (
|
||||
return {
|
||||
conversationId: conversationId.current,
|
||||
chatList,
|
||||
chatListRef,
|
||||
handleUpdateChatList,
|
||||
handleSend,
|
||||
handleStop,
|
||||
handleRestart,
|
||||
|
||||
Reference in New Issue
Block a user