| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176 | 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)
 |