Spaces:
Build error
Build error
import { useCallback, useEffect, useMemo } from 'react' | |
import Chat from '../chat' | |
import type { | |
ChatConfig, | |
ChatItem, | |
OnSend, | |
} from '../types' | |
import { useChat } from '../chat/hooks' | |
import { getLastAnswer } from '../utils' | |
import { useEmbeddedChatbotContext } from './context' | |
import ConfigPanel from './config-panel' | |
import { isDify } from './utils' | |
import cn from '@/utils/classnames' | |
import { | |
fetchSuggestedQuestions, | |
getUrl, | |
stopChatMessageResponding, | |
} from '@/service/share' | |
import LogoAvatar from '@/app/components/base/logo/logo-embedded-chat-avatar' | |
import AnswerIcon from '@/app/components/base/answer-icon' | |
const ChatWrapper = () => { | |
const { | |
appData, | |
appParams, | |
appPrevChatList, | |
currentConversationId, | |
currentConversationItem, | |
inputsForms, | |
newConversationInputs, | |
handleNewConversationCompleted, | |
isMobile, | |
isInstalledApp, | |
appId, | |
appMeta, | |
handleFeedback, | |
currentChatInstanceRef, | |
themeBuilder, | |
} = useEmbeddedChatbotContext() | |
const appConfig = useMemo(() => { | |
const config = appParams || {} | |
return { | |
...config, | |
file_upload: { | |
...(config as any).file_upload, | |
fileUploadConfig: (config as any).system_parameters, | |
}, | |
supportFeedback: true, | |
opening_statement: currentConversationId ? currentConversationItem?.introduction : (config as any).opening_statement, | |
} as ChatConfig | |
}, [appParams, currentConversationItem?.introduction, currentConversationId]) | |
const { | |
chatListRef, | |
chatList, | |
handleSend, | |
handleStop, | |
isResponding, | |
suggestedQuestions, | |
handleUpdateChatList, | |
} = useChat( | |
appConfig, | |
{ | |
inputs: (currentConversationId ? currentConversationItem?.inputs : newConversationInputs) as any, | |
inputsForm: inputsForms, | |
}, | |
appPrevChatList, | |
taskId => stopChatMessageResponding('', taskId, isInstalledApp, appId), | |
) | |
useEffect(() => { | |
if (currentChatInstanceRef.current) | |
currentChatInstanceRef.current.handleStop = handleStop | |
}, []) | |
const doSend: OnSend = useCallback((message, files, last_answer) => { | |
const data: any = { | |
query: message, | |
files, | |
inputs: currentConversationId ? currentConversationItem?.inputs : newConversationInputs, | |
conversation_id: currentConversationId, | |
parent_message_id: last_answer?.id || getLastAnswer(chatListRef.current)?.id || null, | |
} | |
handleSend( | |
getUrl('chat-messages', isInstalledApp, appId || ''), | |
data, | |
{ | |
onGetSuggestedQuestions: responseItemId => fetchSuggestedQuestions(responseItemId, isInstalledApp, appId), | |
onConversationComplete: currentConversationId ? undefined : handleNewConversationCompleted, | |
isPublicAPI: !isInstalledApp, | |
}, | |
) | |
}, [ | |
chatListRef, | |
appConfig, | |
currentConversationId, | |
currentConversationItem, | |
handleSend, | |
newConversationInputs, | |
handleNewConversationCompleted, | |
isInstalledApp, | |
appId, | |
]) | |
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]) | |
const chatNode = useMemo(() => { | |
if (inputsForms.length) { | |
return ( | |
<> | |
{!currentConversationId && ( | |
<div className={cn('mx-auto w-full max-w-full tablet:px-4', isMobile && 'px-4')}> | |
<div className='mb-6' /> | |
<ConfigPanel /> | |
<div | |
className='my-6 h-[1px]' | |
style={{ background: 'linear-gradient(90deg, rgba(242, 244, 247, 0.00) 0%, #F2F4F7 49.17%, rgba(242, 244, 247, 0.00) 100%)' }} | |
/> | |
</div> | |
)} | |
</> | |
) | |
} | |
return null | |
}, [currentConversationId, inputsForms, isMobile]) | |
const answerIcon = isDify() | |
? <LogoAvatar className='relative shrink-0' /> | |
: (appData?.site && appData.site.use_icon_as_answer_icon) | |
? <AnswerIcon | |
iconType={appData.site.icon_type} | |
icon={appData.site.icon} | |
background={appData.site.icon_background} | |
imageUrl={appData.site.icon_url} | |
/> | |
: null | |
return ( | |
<Chat | |
appData={appData} | |
config={appConfig} | |
chatList={chatList} | |
isResponding={isResponding} | |
chatContainerInnerClassName={cn('mx-auto w-full max-w-full tablet:px-4', isMobile && 'px-4')} | |
chatFooterClassName='pb-4' | |
chatFooterInnerClassName={cn('mx-auto w-full max-w-full tablet:px-4', isMobile && 'px-4')} | |
onSend={doSend} | |
inputs={currentConversationId ? currentConversationItem?.inputs as any : newConversationInputs} | |
inputsForm={inputsForms} | |
onRegenerate={doRegenerate} | |
onStopResponding={handleStop} | |
chatNode={chatNode} | |
allToolIcons={appMeta?.tool_icons || {}} | |
onFeedback={handleFeedback} | |
suggestedQuestions={suggestedQuestions} | |
answerIcon={answerIcon} | |
hideProcessDetail | |
themeBuilder={themeBuilder} | |
/> | |
) | |
} | |
export default ChatWrapper | |