From a430284aa21e3ae1f0d5654e55b2ad2852519cc2 Mon Sep 17 00:00:00 2001 From: wwf <yearningwang@iqtogether.com> Date: 星期三, 04 六月 2025 15:17:49 +0800 Subject: [PATCH] 初始化 --- app/components/base/chat/chat-with-history/chat-wrapper.tsx | 194 +++++++++++++---------------------------------- 1 files changed, 55 insertions(+), 139 deletions(-) diff --git a/app/components/base/chat/chat-with-history/chat-wrapper.tsx b/app/components/base/chat/chat-with-history/chat-wrapper.tsx index 63de135..7725920 100644 --- a/app/components/base/chat/chat-with-history/chat-wrapper.tsx +++ b/app/components/base/chat/chat-with-history/chat-wrapper.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useMemo, useState } from 'react' +import { useCallback, useEffect, useMemo } from 'react' import Chat from '../chat' import type { ChatConfig, @@ -9,20 +9,14 @@ import { useChat } from '../chat/hooks' import { getLastAnswer, isValidGeneratedAnswer } from '../utils' import { useChatWithHistoryContext } from './context' -import { InputVarType } from '@/app/components/workflow/types' -import { TransferMethod } from '@/types/app' -import InputsForm from '@/app/components/base/chat/chat-with-history/inputs-form' +import Header from './header' +import ConfigPanel from './config-panel' import { fetchSuggestedQuestions, getUrl, stopChatMessageResponding, } from '@/service/share' -import AppIcon from '@/app/components/base/app-icon' import AnswerIcon from '@/app/components/base/answer-icon' -import SuggestedQuestions from '@/app/components/base/chat/chat/answer/suggested-questions' -import { Markdown } from '@/app/components/base/markdown' -import cn from '@/utils/classnames' -import type { FileEntity } from '../../file-uploader/types' const ChatWrapper = () => { const { @@ -30,10 +24,8 @@ appPrevChatTree, currentConversationId, currentConversationItem, - currentConversationInputs, inputsForms, newConversationInputs, - newConversationInputsRef, handleNewConversationCompleted, isMobile, isInstalledApp, @@ -43,10 +35,6 @@ currentChatInstanceRef, appData, themeBuilder, - sidebarCollapseState, - clearChatList, - setClearChatList, - setIsResponding, } = useChatWithHistoryContext() const appConfig = useMemo(() => { const config = appParams || {} @@ -66,51 +54,17 @@ setTargetMessageId, handleSend, handleStop, - isResponding: respondingState, + isResponding, suggestedQuestions, } = useChat( appConfig, { - inputs: (currentConversationId ? currentConversationInputs : newConversationInputs) as any, + inputs: (currentConversationId ? currentConversationItem?.inputs : newConversationInputs) as any, inputsForm: inputsForms, }, appPrevChatTree, taskId => stopChatMessageResponding('', taskId, isInstalledApp, appId), - clearChatList, - setClearChatList, ) - const inputsFormValue = currentConversationId ? currentConversationInputs : newConversationInputsRef?.current - const inputDisabled = useMemo(() => { - let hasEmptyInput = '' - let fileIsUploading = false - const requiredVars = inputsForms.filter(({ required }) => required) - if (requiredVars.length) { - requiredVars.forEach(({ variable, label, type }) => { - if (hasEmptyInput) - return - - if (fileIsUploading) - return - - if (!inputsFormValue?.[variable]) - hasEmptyInput = label as string - - if ((type === InputVarType.singleFile || type === InputVarType.multiFiles) && inputsFormValue?.[variable]) { - const files = inputsFormValue[variable] - if (Array.isArray(files)) - fileIsUploading = files.find(item => item.transferMethod === TransferMethod.local_file && !item.uploadedId) - else - fileIsUploading = files.transferMethod === TransferMethod.local_file && !files.uploadedId - } - }) - } - if (hasEmptyInput) - return true - - if (fileIsUploading) - return true - return false - }, [inputsFormValue, inputsForms]) useEffect(() => { if (currentChatInstanceRef.current) @@ -118,15 +72,11 @@ // eslint-disable-next-line react-hooks/exhaustive-deps }, []) - useEffect(() => { - setIsResponding(respondingState) - }, [respondingState, setIsResponding]) - const doSend: OnSend = useCallback((message, files, isRegenerate = false, parentAnswer: ChatItem | null = null) => { const data: any = { query: message, files, - inputs: currentConversationId ? currentConversationInputs : newConversationInputs, + inputs: currentConversationId ? currentConversationItem?.inputs : newConversationInputs, conversation_id: currentConversationId, parent_message_id: (isRegenerate ? parentAnswer?.id : getLastAnswer(chatList)?.id) || null, } @@ -140,85 +90,59 @@ isPublicAPI: !isInstalledApp, }, ) - }, [chatList, handleNewConversationCompleted, handleSend, currentConversationId, currentConversationInputs, newConversationInputs, isInstalledApp, appId]) + }, [ + chatList, + handleNewConversationCompleted, + handleSend, + currentConversationId, + currentConversationItem, + newConversationInputs, + isInstalledApp, + appId, + ]) - const doRegenerate = useCallback((chatItem: ChatItemInTree, editedQuestion?: { message: string, files?: FileEntity[] }) => { - const question = editedQuestion ? chatItem : chatList.find(item => item.id === chatItem.parentMessageId)! + const doRegenerate = useCallback((chatItem: ChatItemInTree) => { + const question = chatList.find(item => item.id === chatItem.parentMessageId)! const parentAnswer = chatList.find(item => item.id === question.parentMessageId) - doSend(editedQuestion ? editedQuestion.message : question.content, - editedQuestion ? editedQuestion.files : question.message_files, - true, - isValidGeneratedAnswer(parentAnswer) ? parentAnswer : null, - ) + doSend(question.content, question.message_files, true, isValidGeneratedAnswer(parentAnswer) ? parentAnswer : null) }, [chatList, doSend]) - const messageList = useMemo(() => { - if (currentConversationId) - return chatList - return chatList.filter(item => !item.isOpeningStatement) - }, [chatList, currentConversationId]) - - const [collapsed, setCollapsed] = useState(!!currentConversationId) - const chatNode = useMemo(() => { - if (!inputsForms.length) - return null - if (isMobile) { - if (!currentConversationId) - return <InputsForm collapsed={collapsed} setCollapsed={setCollapsed} /> - return null - } - else { - return <InputsForm collapsed={collapsed} setCollapsed={setCollapsed} /> - } - }, [inputsForms.length, isMobile, currentConversationId, collapsed]) - - const welcome = useMemo(() => { - const welcomeMessage = chatList.find(item => item.isOpeningStatement) - if (respondingState) - return null - if (currentConversationId) - return null - if (!welcomeMessage) - return null - if (!collapsed && inputsForms.length > 0) - return null - if (welcomeMessage.suggestedQuestions && welcomeMessage.suggestedQuestions?.length > 0) { + if (inputsForms.length) { return ( - <div className='flex min-h-[50vh] items-center justify-center px-4 py-12'> - <div className='flex max-w-[720px] grow gap-4'> - <AppIcon - size='xl' - iconType={appData?.site.icon_type} - icon={appData?.site.icon} - background={appData?.site.icon_background} - imageUrl={appData?.site.icon_url} - /> - <div className='w-0 grow'> - <div className='body-lg-regular grow rounded-2xl bg-chat-bubble-bg px-4 py-3 text-text-primary'> - <Markdown content={welcomeMessage.content} /> - <SuggestedQuestions item={welcomeMessage} /> + <> + <Header + isMobile={isMobile} + title={currentConversationItem?.name || ''} + /> + { + !currentConversationId && ( + <div className={`mx-auto w-full max-w-[720px] ${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> - </div> - </div> - </div> + ) + } + </> ) } + return ( - <div className={cn('flex h-[50vh] flex-col items-center justify-center gap-3 py-12')}> - <AppIcon - size='xl' - iconType={appData?.site.icon_type} - icon={appData?.site.icon} - background={appData?.site.icon_background} - imageUrl={appData?.site.icon_url} - /> - <div className='max-w-[768px] px-4'> - <Markdown className='!body-2xl-regular !text-text-tertiary' content={welcomeMessage.content} /> - </div> - </div> + <Header + isMobile={isMobile} + title={currentConversationItem?.name || ''} + /> ) - }, [appData?.site.icon, appData?.site.icon_background, appData?.site.icon_type, appData?.site.icon_url, chatList, collapsed, currentConversationId, inputsForms.length, respondingState]) + }, [ + currentConversationId, + inputsForms, + currentConversationItem, + isMobile, + ]) const answerIcon = (appData?.site && appData.site.use_icon_as_answer_icon) ? <AnswerIcon @@ -231,27 +155,22 @@ return ( <div - className='h-full overflow-hidden bg-chatbot-bg' + className='h-full bg-chatbot-bg overflow-hidden' > <Chat appData={appData} config={appConfig} - chatList={messageList} - isResponding={respondingState} - chatContainerInnerClassName={`mx-auto pt-6 w-full max-w-[768px] ${isMobile && 'px-4'}`} + chatList={chatList} + isResponding={isResponding} + chatContainerInnerClassName={`mx-auto pt-6 w-full max-w-[720px] ${isMobile && 'px-4'}`} chatFooterClassName='pb-4' - chatFooterInnerClassName={`mx-auto w-full max-w-[768px] ${isMobile ? 'px-2' : 'px-4'}`} + chatFooterInnerClassName={`mx-auto w-full max-w-[720px] ${isMobile && 'px-4'}`} onSend={doSend} - inputs={currentConversationId ? currentConversationInputs as any : newConversationInputs} + inputs={currentConversationId ? currentConversationItem?.inputs as any : newConversationInputs} inputsForm={inputsForms} onRegenerate={doRegenerate} onStopResponding={handleStop} - chatNode={ - <> - {chatNode} - {welcome} - </> - } + chatNode={chatNode} allToolIcons={appMeta?.tool_icons || {}} onFeedback={handleFeedback} suggestedQuestions={suggestedQuestions} @@ -259,9 +178,6 @@ hideProcessDetail themeBuilder={themeBuilder} switchSibling={siblingMessageId => setTargetMessageId(siblingMessageId)} - inputDisabled={inputDisabled} - isMobile={isMobile} - sidebarCollapseState={sidebarCollapseState} /> </div> ) -- Gitblit v1.8.0