Spaces:
Build error
Build error
import { | |
forwardRef, | |
memo, | |
useCallback, | |
useEffect, | |
useImperativeHandle, | |
useMemo, | |
} from 'react' | |
import { useNodes } from 'reactflow' | |
import { BlockEnum } from '../../types' | |
import { | |
useStore, | |
useWorkflowStore, | |
} from '../../store' | |
import type { StartNodeType } from '../../nodes/start/types' | |
import Empty from './empty' | |
import UserInput from './user-input' | |
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 { ChatItem, OnSend } from '@/app/components/base/chat/types' | |
import { useFeatures } from '@/app/components/base/features/hooks' | |
import { | |
fetchSuggestedQuestions, | |
stopChatMessageResponding, | |
} from '@/service/debug' | |
import { useStore as useAppStore } from '@/app/components/app/store' | |
import { getLastAnswer } from '@/app/components/base/chat/utils' | |
type ChatWrapperProps = { | |
showConversationVariableModal: boolean | |
onConversationModalHide: () => void | |
showInputsFieldsPanel: boolean | |
onHide: () => void | |
} | |
const ChatWrapper = forwardRef<ChatWrapperRefType, ChatWrapperProps>(({ | |
showConversationVariableModal, | |
onConversationModalHide, | |
showInputsFieldsPanel, | |
onHide, | |
}, ref) => { | |
const nodes = useNodes<StartNodeType>() | |
const startNode = nodes.find(node => node.data.type === BlockEnum.Start) | |
const startVariables = startNode?.data.variables | |
const appDetail = useAppStore(s => s.appDetail) | |
const workflowStore = useWorkflowStore() | |
const inputs = useStore(s => s.inputs) | |
const features = useFeatures(s => s.features) | |
const config = useMemo(() => { | |
return { | |
opening_statement: features.opening?.enabled ? (features.opening?.opening_statement || '') : '', | |
suggested_questions: features.opening?.enabled ? (features.opening?.suggested_questions || []) : [], | |
suggested_questions_after_answer: features.suggested, | |
text_to_speech: features.text2speech, | |
speech_to_text: features.speech2text, | |
retriever_resource: features.citation, | |
sensitive_word_avoidance: features.moderation, | |
file_upload: features.file, | |
} | |
}, [features.opening, features.suggested, features.text2speech, features.speech2text, features.citation, features.moderation, features.file]) | |
const setShowFeaturesPanel = useStore(s => s.setShowFeaturesPanel) | |
const { | |
conversationId, | |
chatList, | |
chatListRef, | |
handleUpdateChatList, | |
handleStop, | |
isResponding, | |
suggestedQuestions, | |
handleSend, | |
handleRestart, | |
} = useChat( | |
config, | |
{ | |
inputs, | |
inputsForm: (startVariables || []) as any, | |
}, | |
[], | |
taskId => stopChatMessageResponding(appDetail!.id, taskId), | |
) | |
const doSend = useCallback<OnSend>((query, files, last_answer) => { | |
handleSend( | |
{ | |
query, | |
files, | |
inputs: workflowStore.getState().inputs, | |
conversation_id: conversationId, | |
parent_message_id: last_answer?.id || getLastAnswer(chatListRef.current)?.id || null, | |
}, | |
{ | |
onGetSuggestedQuestions: (messageId, getAbortController) => fetchSuggestedQuestions(appDetail!.id, messageId, getAbortController), | |
}, | |
) | |
}, [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 = getLastAnswer(prevMessages) | |
if (!question) | |
return | |
handleUpdateChatList(prevMessages) | |
doSend(question.content, question.message_files, lastAnswer) | |
}, [chatList, handleUpdateChatList, doSend]) | |
useImperativeHandle(ref, () => { | |
return { | |
handleRestart, | |
} | |
}, [handleRestart]) | |
useEffect(() => { | |
if (isResponding) | |
onHide() | |
}, [isResponding, onHide]) | |
return ( | |
<> | |
<Chat | |
config={{ | |
...config, | |
supportCitationHitInfo: true, | |
} as any} | |
chatList={chatList} | |
isResponding={isResponding} | |
chatContainerClassName='px-3' | |
chatContainerInnerClassName='pt-6 w-full max-w-full mx-auto' | |
chatFooterClassName='px-4 rounded-bl-2xl' | |
chatFooterInnerClassName='pb-0' | |
showFileUpload | |
showFeatureBar | |
onFeatureBarClick={setShowFeaturesPanel} | |
onSend={doSend} | |
inputs={inputs} | |
inputsForm={(startVariables || []) as any} | |
onRegenerate={doRegenerate} | |
onStopResponding={handleStop} | |
chatNode={( | |
<> | |
{showInputsFieldsPanel && <UserInput />} | |
{ | |
!chatList.length && ( | |
<Empty /> | |
) | |
} | |
</> | |
)} | |
noSpacing | |
suggestedQuestions={suggestedQuestions} | |
showPromptLog | |
chatAnswerContainerInner='!pr-2' | |
/> | |
{showConversationVariableModal && ( | |
<ConversationVariableModal | |
conversationID={conversationId} | |
onHide={onConversationModalHide} | |
/> | |
)} | |
</> | |
) | |
}) | |
ChatWrapper.displayName = 'ChatWrapper' | |
export default memo(ChatWrapper) | |