Fix:webapp UI issues (#15601)
This commit is contained in:
parent
b0e28f58aa
commit
c304f8e702
@ -20,6 +20,7 @@ import {
|
|||||||
import AppIcon from '@/app/components/base/app-icon'
|
import AppIcon from '@/app/components/base/app-icon'
|
||||||
import AnswerIcon from '@/app/components/base/answer-icon'
|
import AnswerIcon from '@/app/components/base/answer-icon'
|
||||||
import SuggestedQuestions from '@/app/components/base/chat/chat/answer/suggested-questions'
|
import SuggestedQuestions from '@/app/components/base/chat/chat/answer/suggested-questions'
|
||||||
|
import { Markdown } from '@/app/components/base/markdown'
|
||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
|
|
||||||
const ChatWrapper = () => {
|
const ChatWrapper = () => {
|
||||||
@ -41,6 +42,9 @@ const ChatWrapper = () => {
|
|||||||
appData,
|
appData,
|
||||||
themeBuilder,
|
themeBuilder,
|
||||||
sidebarCollapseState,
|
sidebarCollapseState,
|
||||||
|
clearChatList,
|
||||||
|
setClearChatList,
|
||||||
|
setIsResponding,
|
||||||
} = useChatWithHistoryContext()
|
} = useChatWithHistoryContext()
|
||||||
const appConfig = useMemo(() => {
|
const appConfig = useMemo(() => {
|
||||||
const config = appParams || {}
|
const config = appParams || {}
|
||||||
@ -60,7 +64,7 @@ const ChatWrapper = () => {
|
|||||||
setTargetMessageId,
|
setTargetMessageId,
|
||||||
handleSend,
|
handleSend,
|
||||||
handleStop,
|
handleStop,
|
||||||
isResponding,
|
isResponding: respondingState,
|
||||||
suggestedQuestions,
|
suggestedQuestions,
|
||||||
} = useChat(
|
} = useChat(
|
||||||
appConfig,
|
appConfig,
|
||||||
@ -70,6 +74,8 @@ const ChatWrapper = () => {
|
|||||||
},
|
},
|
||||||
appPrevChatTree,
|
appPrevChatTree,
|
||||||
taskId => stopChatMessageResponding('', taskId, isInstalledApp, appId),
|
taskId => stopChatMessageResponding('', taskId, isInstalledApp, appId),
|
||||||
|
clearChatList,
|
||||||
|
setClearChatList,
|
||||||
)
|
)
|
||||||
const inputsFormValue = currentConversationId ? currentConversationItem?.inputs : newConversationInputsRef?.current
|
const inputsFormValue = currentConversationId ? currentConversationItem?.inputs : newConversationInputsRef?.current
|
||||||
const inputDisabled = useMemo(() => {
|
const inputDisabled = useMemo(() => {
|
||||||
@ -110,6 +116,10 @@ const ChatWrapper = () => {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// 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 doSend: OnSend = useCallback((message, files, isRegenerate = false, parentAnswer: ChatItem | null = null) => {
|
||||||
const data: any = {
|
const data: any = {
|
||||||
query: message,
|
query: message,
|
||||||
@ -146,10 +156,10 @@ const ChatWrapper = () => {
|
|||||||
}, [chatList, doSend])
|
}, [chatList, doSend])
|
||||||
|
|
||||||
const messageList = useMemo(() => {
|
const messageList = useMemo(() => {
|
||||||
if (currentConversationId || isResponding)
|
if (currentConversationId)
|
||||||
return chatList
|
return chatList
|
||||||
return chatList.filter(item => !item.isOpeningStatement)
|
return chatList.filter(item => !item.isOpeningStatement)
|
||||||
}, [chatList, currentConversationId, isResponding])
|
}, [chatList, currentConversationId])
|
||||||
|
|
||||||
const [collapsed, setCollapsed] = useState(!!currentConversationId)
|
const [collapsed, setCollapsed] = useState(!!currentConversationId)
|
||||||
|
|
||||||
@ -168,7 +178,7 @@ const ChatWrapper = () => {
|
|||||||
|
|
||||||
const welcome = useMemo(() => {
|
const welcome = useMemo(() => {
|
||||||
const welcomeMessage = chatList.find(item => item.isOpeningStatement)
|
const welcomeMessage = chatList.find(item => item.isOpeningStatement)
|
||||||
if (isResponding)
|
if (respondingState)
|
||||||
return null
|
return null
|
||||||
if (currentConversationId)
|
if (currentConversationId)
|
||||||
return null
|
return null
|
||||||
@ -188,7 +198,7 @@ const ChatWrapper = () => {
|
|||||||
imageUrl={appData?.site.icon_url}
|
imageUrl={appData?.site.icon_url}
|
||||||
/>
|
/>
|
||||||
<div className='grow px-4 py-3 bg-chat-bubble-bg text-text-primary rounded-2xl body-lg-regular'>
|
<div className='grow px-4 py-3 bg-chat-bubble-bg text-text-primary rounded-2xl body-lg-regular'>
|
||||||
{welcomeMessage.content}
|
<Markdown content={welcomeMessage.content} />
|
||||||
<SuggestedQuestions item={welcomeMessage} />
|
<SuggestedQuestions item={welcomeMessage} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -204,10 +214,12 @@ const ChatWrapper = () => {
|
|||||||
background={appData?.site.icon_background}
|
background={appData?.site.icon_background}
|
||||||
imageUrl={appData?.site.icon_url}
|
imageUrl={appData?.site.icon_url}
|
||||||
/>
|
/>
|
||||||
<div className='text-text-tertiary body-2xl-regular'>{welcomeMessage.content}</div>
|
<div className='max-w-[768px]'>
|
||||||
|
<Markdown className='!text-text-tertiary !body-2xl-regular' content={welcomeMessage.content} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}, [appData?.site.icon, appData?.site.icon_background, appData?.site.icon_type, appData?.site.icon_url, chatList, collapsed, currentConversationId, inputsForms.length, isResponding])
|
}, [appData?.site.icon, appData?.site.icon_background, appData?.site.icon_type, appData?.site.icon_url, chatList, collapsed, currentConversationId, inputsForms.length, respondingState])
|
||||||
|
|
||||||
const answerIcon = (appData?.site && appData.site.use_icon_as_answer_icon)
|
const answerIcon = (appData?.site && appData.site.use_icon_as_answer_icon)
|
||||||
? <AnswerIcon
|
? <AnswerIcon
|
||||||
@ -226,10 +238,10 @@ const ChatWrapper = () => {
|
|||||||
appData={appData}
|
appData={appData}
|
||||||
config={appConfig}
|
config={appConfig}
|
||||||
chatList={messageList}
|
chatList={messageList}
|
||||||
isResponding={isResponding}
|
isResponding={respondingState}
|
||||||
chatContainerInnerClassName={`mx-auto pt-6 w-full max-w-[720px] ${isMobile && 'px-4'}`}
|
chatContainerInnerClassName={`mx-auto pt-6 w-full max-w-[768px] ${isMobile && 'px-4'}`}
|
||||||
chatFooterClassName='pb-4'
|
chatFooterClassName='pb-4'
|
||||||
chatFooterInnerClassName={`mx-auto w-full max-w-[720px] ${isMobile ? 'px-2' : 'px-4'}`}
|
chatFooterInnerClassName={`mx-auto w-full max-w-[768px] ${isMobile ? 'px-2' : 'px-4'}`}
|
||||||
onSend={doSend}
|
onSend={doSend}
|
||||||
inputs={currentConversationId ? currentConversationItem?.inputs as any : newConversationInputs}
|
inputs={currentConversationId ? currentConversationItem?.inputs as any : newConversationInputs}
|
||||||
inputsForm={inputsForms}
|
inputsForm={inputsForms}
|
||||||
|
@ -50,6 +50,10 @@ export type ChatWithHistoryContextValue = {
|
|||||||
themeBuilder?: ThemeBuilder
|
themeBuilder?: ThemeBuilder
|
||||||
sidebarCollapseState?: boolean
|
sidebarCollapseState?: boolean
|
||||||
handleSidebarCollapse: (state: boolean) => void
|
handleSidebarCollapse: (state: boolean) => void
|
||||||
|
clearChatList?: boolean
|
||||||
|
setClearChatList: (state: boolean) => void
|
||||||
|
isResponding?: boolean
|
||||||
|
setIsResponding: (state: boolean) => void,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ChatWithHistoryContext = createContext<ChatWithHistoryContextValue>({
|
export const ChatWithHistoryContext = createContext<ChatWithHistoryContextValue>({
|
||||||
@ -77,5 +81,9 @@ export const ChatWithHistoryContext = createContext<ChatWithHistoryContextValue>
|
|||||||
currentChatInstanceRef: { current: { handleStop: () => {} } },
|
currentChatInstanceRef: { current: { handleStop: () => {} } },
|
||||||
sidebarCollapseState: false,
|
sidebarCollapseState: false,
|
||||||
handleSidebarCollapse: () => {},
|
handleSidebarCollapse: () => {},
|
||||||
|
clearChatList: false,
|
||||||
|
setClearChatList: () => {},
|
||||||
|
isResponding: false,
|
||||||
|
setIsResponding: () => {},
|
||||||
})
|
})
|
||||||
export const useChatWithHistoryContext = () => useContext(ChatWithHistoryContext)
|
export const useChatWithHistoryContext = () => useContext(ChatWithHistoryContext)
|
||||||
|
@ -33,6 +33,7 @@ const Header = () => {
|
|||||||
handleNewConversation,
|
handleNewConversation,
|
||||||
sidebarCollapseState,
|
sidebarCollapseState,
|
||||||
handleSidebarCollapse,
|
handleSidebarCollapse,
|
||||||
|
isResponding,
|
||||||
} = useChatWithHistoryContext()
|
} = useChatWithHistoryContext()
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const isSidebarCollapsed = sidebarCollapseState
|
const isSidebarCollapsed = sidebarCollapseState
|
||||||
@ -111,7 +112,12 @@ const Header = () => {
|
|||||||
popupContent={t('share.chat.newChatTip')}
|
popupContent={t('share.chat.newChatTip')}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<ActionButton size='l' state={!currentConversationId ? ActionButtonState.Disabled : ActionButtonState.Default} disabled={!currentConversationId} onClick={handleNewConversation}>
|
<ActionButton
|
||||||
|
size='l'
|
||||||
|
state={(!currentConversationId || isResponding) ? ActionButtonState.Disabled : ActionButtonState.Default}
|
||||||
|
disabled={!currentConversationId || isResponding}
|
||||||
|
onClick={handleNewConversation}
|
||||||
|
>
|
||||||
<RiEditBoxLine className='w-[18px] h-[18px]' />
|
<RiEditBoxLine className='w-[18px] h-[18px]' />
|
||||||
</ActionButton>
|
</ActionButton>
|
||||||
</div>
|
</div>
|
||||||
|
@ -150,6 +150,8 @@ export const useChatWithHistory = (installedAppInfo?: InstalledApp) => {
|
|||||||
const { data: appConversationData, isLoading: appConversationDataLoading, mutate: mutateAppConversationData } = useSWR(['appConversationData', isInstalledApp, appId, false], () => fetchConversations(isInstalledApp, appId, undefined, false, 100))
|
const { data: appConversationData, isLoading: appConversationDataLoading, mutate: mutateAppConversationData } = useSWR(['appConversationData', isInstalledApp, appId, false], () => fetchConversations(isInstalledApp, appId, undefined, false, 100))
|
||||||
const { data: appChatListData, isLoading: appChatListDataLoading } = useSWR(chatShouldReloadKey ? ['appChatList', chatShouldReloadKey, isInstalledApp, appId] : null, () => fetchChatList(chatShouldReloadKey, isInstalledApp, appId))
|
const { data: appChatListData, isLoading: appChatListDataLoading } = useSWR(chatShouldReloadKey ? ['appChatList', chatShouldReloadKey, isInstalledApp, appId] : null, () => fetchChatList(chatShouldReloadKey, isInstalledApp, appId))
|
||||||
|
|
||||||
|
const [clearChatList, setClearChatList] = useState(false)
|
||||||
|
const [isResponding, setIsResponding] = useState(false)
|
||||||
const appPrevChatTree = useMemo(
|
const appPrevChatTree = useMemo(
|
||||||
() => (currentConversationId && appChatListData?.data.length)
|
() => (currentConversationId && appChatListData?.data.length)
|
||||||
? buildChatItemTree(getFormattedChatList(appChatListData.data))
|
? buildChatItemTree(getFormattedChatList(appChatListData.data))
|
||||||
@ -310,20 +312,16 @@ export const useChatWithHistory = (installedAppInfo?: InstalledApp) => {
|
|||||||
currentChatInstanceRef.current.handleStop()
|
currentChatInstanceRef.current.handleStop()
|
||||||
setNewConversationId('')
|
setNewConversationId('')
|
||||||
handleConversationIdInfoChange(conversationId)
|
handleConversationIdInfoChange(conversationId)
|
||||||
}, [handleConversationIdInfoChange])
|
if (conversationId)
|
||||||
|
setClearChatList(false)
|
||||||
|
}, [handleConversationIdInfoChange, setClearChatList])
|
||||||
const handleNewConversation = useCallback(() => {
|
const handleNewConversation = useCallback(() => {
|
||||||
currentChatInstanceRef.current.handleStop()
|
currentChatInstanceRef.current.handleStop()
|
||||||
setNewConversationId('')
|
setShowNewConversationItemInList(true)
|
||||||
|
handleChangeConversation('')
|
||||||
if (showNewConversationItemInList) {
|
handleNewConversationInputsChange({})
|
||||||
handleChangeConversation('')
|
setClearChatList(true)
|
||||||
}
|
}, [handleChangeConversation, setShowNewConversationItemInList, handleNewConversationInputsChange, setClearChatList])
|
||||||
else if (currentConversationId) {
|
|
||||||
handleConversationIdInfoChange('')
|
|
||||||
setShowNewConversationItemInList(true)
|
|
||||||
handleNewConversationInputsChange({})
|
|
||||||
}
|
|
||||||
}, [handleChangeConversation, currentConversationId, handleConversationIdInfoChange, setShowNewConversationItemInList, showNewConversationItemInList, handleNewConversationInputsChange])
|
|
||||||
const handleUpdateConversationList = useCallback(() => {
|
const handleUpdateConversationList = useCallback(() => {
|
||||||
mutateAppConversationData()
|
mutateAppConversationData()
|
||||||
mutateAppPinnedConversationData()
|
mutateAppPinnedConversationData()
|
||||||
@ -462,5 +460,9 @@ export const useChatWithHistory = (installedAppInfo?: InstalledApp) => {
|
|||||||
currentChatInstanceRef,
|
currentChatInstanceRef,
|
||||||
sidebarCollapseState,
|
sidebarCollapseState,
|
||||||
handleSidebarCollapse,
|
handleSidebarCollapse,
|
||||||
|
clearChatList,
|
||||||
|
setClearChatList,
|
||||||
|
isResponding,
|
||||||
|
setIsResponding,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,6 +153,10 @@ const ChatWithHistoryWrap: FC<ChatWithHistoryWrapProps> = ({
|
|||||||
currentChatInstanceRef,
|
currentChatInstanceRef,
|
||||||
sidebarCollapseState,
|
sidebarCollapseState,
|
||||||
handleSidebarCollapse,
|
handleSidebarCollapse,
|
||||||
|
clearChatList,
|
||||||
|
setClearChatList,
|
||||||
|
isResponding,
|
||||||
|
setIsResponding,
|
||||||
} = useChatWithHistory(installedAppInfo)
|
} = useChatWithHistory(installedAppInfo)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -190,6 +194,10 @@ const ChatWithHistoryWrap: FC<ChatWithHistoryWrapProps> = ({
|
|||||||
themeBuilder,
|
themeBuilder,
|
||||||
sidebarCollapseState,
|
sidebarCollapseState,
|
||||||
handleSidebarCollapse,
|
handleSidebarCollapse,
|
||||||
|
clearChatList,
|
||||||
|
setClearChatList,
|
||||||
|
isResponding,
|
||||||
|
setIsResponding,
|
||||||
}}>
|
}}>
|
||||||
<ChatWithHistory className={className} />
|
<ChatWithHistory className={className} />
|
||||||
</ChatWithHistoryContext.Provider>
|
</ChatWithHistoryContext.Provider>
|
||||||
|
@ -41,6 +41,7 @@ const Sidebar = ({ isPanel }: Props) => {
|
|||||||
sidebarCollapseState,
|
sidebarCollapseState,
|
||||||
handleSidebarCollapse,
|
handleSidebarCollapse,
|
||||||
isMobile,
|
isMobile,
|
||||||
|
isResponding,
|
||||||
} = useChatWithHistoryContext()
|
} = useChatWithHistoryContext()
|
||||||
const isSidebarCollapsed = sidebarCollapseState
|
const isSidebarCollapsed = sidebarCollapseState
|
||||||
|
|
||||||
@ -105,7 +106,7 @@ const Sidebar = ({ isPanel }: Props) => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className='shrink-0 px-3 py-4'>
|
<div className='shrink-0 px-3 py-4'>
|
||||||
<Button variant='secondary-accent' className='w-full justify-center' onClick={handleNewConversation}>
|
<Button variant='secondary-accent' disabled={isResponding} className='w-full justify-center' onClick={handleNewConversation}>
|
||||||
<RiEditBoxLine className='w-4 h-4 mr-1' />
|
<RiEditBoxLine className='w-4 h-4 mr-1' />
|
||||||
{t('share.chat.newChat')}
|
{t('share.chat.newChat')}
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -8,7 +8,7 @@ import { useTranslation } from 'react-i18next'
|
|||||||
import {
|
import {
|
||||||
RiClipboardLine,
|
RiClipboardLine,
|
||||||
RiEditLine,
|
RiEditLine,
|
||||||
RiReplay15Line,
|
RiResetLeftLine,
|
||||||
RiThumbDownLine,
|
RiThumbDownLine,
|
||||||
RiThumbUpLine,
|
RiThumbUpLine,
|
||||||
} from '@remixicon/react'
|
} from '@remixicon/react'
|
||||||
@ -130,7 +130,7 @@ const Operation: FC<OperationProps> = ({
|
|||||||
</ActionButton>
|
</ActionButton>
|
||||||
{!noChatInput && (
|
{!noChatInput && (
|
||||||
<ActionButton onClick={() => onRegenerate?.(item)}>
|
<ActionButton onClick={() => onRegenerate?.(item)}>
|
||||||
<RiReplay15Line className='w-4 h-4' />
|
<RiResetLeftLine className='w-4 h-4' />
|
||||||
</ActionButton>
|
</ActionButton>
|
||||||
)}
|
)}
|
||||||
{(config?.supportAnnotation && config.annotation_reply?.enabled) && (
|
{(config?.supportAnnotation && config.annotation_reply?.enabled) && (
|
||||||
|
@ -51,6 +51,8 @@ export const useChat = (
|
|||||||
},
|
},
|
||||||
prevChatTree?: ChatItemInTree[],
|
prevChatTree?: ChatItemInTree[],
|
||||||
stopChat?: (taskId: string) => void,
|
stopChat?: (taskId: string) => void,
|
||||||
|
clearChatList?: boolean,
|
||||||
|
clearChatListCallback?: (state: boolean) => void,
|
||||||
) => {
|
) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { formatTime } = useTimestamp()
|
const { formatTime } = useTimestamp()
|
||||||
@ -90,7 +92,7 @@ export const useChat = (
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ret.unshift({
|
ret.unshift({
|
||||||
id: `${Date.now()}`,
|
id: 'opening-statement',
|
||||||
content: getIntroduction(config.opening_statement),
|
content: getIntroduction(config.opening_statement),
|
||||||
isAnswer: true,
|
isAnswer: true,
|
||||||
isOpeningStatement: true,
|
isOpeningStatement: true,
|
||||||
@ -163,12 +165,13 @@ export const useChat = (
|
|||||||
suggestedQuestionsAbortControllerRef.current.abort()
|
suggestedQuestionsAbortControllerRef.current.abort()
|
||||||
}, [stopChat, handleResponding])
|
}, [stopChat, handleResponding])
|
||||||
|
|
||||||
const handleRestart = useCallback(() => {
|
const handleRestart = useCallback((cb?: any) => {
|
||||||
conversationId.current = ''
|
conversationId.current = ''
|
||||||
taskIdRef.current = ''
|
taskIdRef.current = ''
|
||||||
handleStop()
|
handleStop()
|
||||||
setChatTree([])
|
setChatTree([])
|
||||||
setSuggestQuestions([])
|
setSuggestQuestions([])
|
||||||
|
cb?.()
|
||||||
}, [handleStop])
|
}, [handleStop])
|
||||||
|
|
||||||
const updateCurrentQAOnTree = useCallback(({
|
const updateCurrentQAOnTree = useCallback(({
|
||||||
@ -682,6 +685,11 @@ export const useChat = (
|
|||||||
})
|
})
|
||||||
}, [chatList, updateChatTreeNode])
|
}, [chatList, updateChatTreeNode])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (clearChatList)
|
||||||
|
handleRestart(() => clearChatListCallback?.(false))
|
||||||
|
}, [clearChatList, clearChatListCallback, handleRestart])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
chatList,
|
chatList,
|
||||||
setTargetMessageId,
|
setTargetMessageId,
|
||||||
|
@ -21,6 +21,8 @@ import {
|
|||||||
import AppIcon from '@/app/components/base/app-icon'
|
import AppIcon from '@/app/components/base/app-icon'
|
||||||
import LogoAvatar from '@/app/components/base/logo/logo-embedded-chat-avatar'
|
import LogoAvatar from '@/app/components/base/logo/logo-embedded-chat-avatar'
|
||||||
import AnswerIcon from '@/app/components/base/answer-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 cn from '@/utils/classnames'
|
||||||
|
|
||||||
const ChatWrapper = () => {
|
const ChatWrapper = () => {
|
||||||
@ -41,6 +43,9 @@ const ChatWrapper = () => {
|
|||||||
handleFeedback,
|
handleFeedback,
|
||||||
currentChatInstanceRef,
|
currentChatInstanceRef,
|
||||||
themeBuilder,
|
themeBuilder,
|
||||||
|
clearChatList,
|
||||||
|
setClearChatList,
|
||||||
|
setIsResponding,
|
||||||
} = useEmbeddedChatbotContext()
|
} = useEmbeddedChatbotContext()
|
||||||
const appConfig = useMemo(() => {
|
const appConfig = useMemo(() => {
|
||||||
const config = appParams || {}
|
const config = appParams || {}
|
||||||
@ -60,7 +65,7 @@ const ChatWrapper = () => {
|
|||||||
setTargetMessageId,
|
setTargetMessageId,
|
||||||
handleSend,
|
handleSend,
|
||||||
handleStop,
|
handleStop,
|
||||||
isResponding,
|
isResponding: respondingState,
|
||||||
suggestedQuestions,
|
suggestedQuestions,
|
||||||
} = useChat(
|
} = useChat(
|
||||||
appConfig,
|
appConfig,
|
||||||
@ -70,6 +75,8 @@ const ChatWrapper = () => {
|
|||||||
},
|
},
|
||||||
appPrevChatList,
|
appPrevChatList,
|
||||||
taskId => stopChatMessageResponding('', taskId, isInstalledApp, appId),
|
taskId => stopChatMessageResponding('', taskId, isInstalledApp, appId),
|
||||||
|
clearChatList,
|
||||||
|
setClearChatList,
|
||||||
)
|
)
|
||||||
const inputsFormValue = currentConversationId ? currentConversationItem?.inputs : newConversationInputsRef?.current
|
const inputsFormValue = currentConversationId ? currentConversationItem?.inputs : newConversationInputsRef?.current
|
||||||
const inputDisabled = useMemo(() => {
|
const inputDisabled = useMemo(() => {
|
||||||
@ -108,6 +115,9 @@ const ChatWrapper = () => {
|
|||||||
if (currentChatInstanceRef.current)
|
if (currentChatInstanceRef.current)
|
||||||
currentChatInstanceRef.current.handleStop = handleStop
|
currentChatInstanceRef.current.handleStop = handleStop
|
||||||
}, [currentChatInstanceRef, handleStop])
|
}, [currentChatInstanceRef, handleStop])
|
||||||
|
useEffect(() => {
|
||||||
|
setIsResponding(respondingState)
|
||||||
|
}, [respondingState, setIsResponding])
|
||||||
|
|
||||||
const doSend: OnSend = useCallback((message, files, isRegenerate = false, parentAnswer: ChatItem | null = null) => {
|
const doSend: OnSend = useCallback((message, files, isRegenerate = false, parentAnswer: ChatItem | null = null) => {
|
||||||
const data: any = {
|
const data: any = {
|
||||||
@ -167,12 +177,33 @@ const ChatWrapper = () => {
|
|||||||
|
|
||||||
const welcome = useMemo(() => {
|
const welcome = useMemo(() => {
|
||||||
const welcomeMessage = chatList.find(item => item.isOpeningStatement)
|
const welcomeMessage = chatList.find(item => item.isOpeningStatement)
|
||||||
|
if (respondingState)
|
||||||
|
return null
|
||||||
if (currentConversationId)
|
if (currentConversationId)
|
||||||
return null
|
return null
|
||||||
if (!welcomeMessage)
|
if (!welcomeMessage)
|
||||||
return null
|
return null
|
||||||
if (!collapsed && inputsForms.length > 0)
|
if (!collapsed && inputsForms.length > 0)
|
||||||
return null
|
return null
|
||||||
|
if (welcomeMessage.suggestedQuestions && welcomeMessage.suggestedQuestions?.length > 0) {
|
||||||
|
return (
|
||||||
|
<div className='h-[50vh] py-12 px-4 flex items-center justify-center'>
|
||||||
|
<div className='grow max-w-[720px] flex 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='grow px-4 py-3 bg-chat-bubble-bg text-text-primary rounded-2xl body-lg-regular'>
|
||||||
|
<Markdown content={welcomeMessage.content} />
|
||||||
|
<SuggestedQuestions item={welcomeMessage} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div className={cn('h-[50vh] py-12 flex flex-col items-center justify-center gap-3')}>
|
<div className={cn('h-[50vh] py-12 flex flex-col items-center justify-center gap-3')}>
|
||||||
<AppIcon
|
<AppIcon
|
||||||
@ -182,10 +213,12 @@ const ChatWrapper = () => {
|
|||||||
background={appData?.site.icon_background}
|
background={appData?.site.icon_background}
|
||||||
imageUrl={appData?.site.icon_url}
|
imageUrl={appData?.site.icon_url}
|
||||||
/>
|
/>
|
||||||
<div className='text-text-tertiary body-2xl-regular'>{welcomeMessage.content}</div>
|
<div className='max-w-[768px]'>
|
||||||
|
<Markdown className='!text-text-tertiary !body-2xl-regular' content={welcomeMessage.content} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}, [appData?.site.icon, appData?.site.icon_background, appData?.site.icon_type, appData?.site.icon_url, chatList, collapsed, currentConversationId, inputsForms.length])
|
}, [appData?.site.icon, appData?.site.icon_background, appData?.site.icon_type, appData?.site.icon_url, chatList, collapsed, currentConversationId, inputsForms.length, respondingState])
|
||||||
|
|
||||||
const answerIcon = isDify()
|
const answerIcon = isDify()
|
||||||
? <LogoAvatar className='relative shrink-0' />
|
? <LogoAvatar className='relative shrink-0' />
|
||||||
@ -203,10 +236,10 @@ const ChatWrapper = () => {
|
|||||||
appData={appData}
|
appData={appData}
|
||||||
config={appConfig}
|
config={appConfig}
|
||||||
chatList={messageList}
|
chatList={messageList}
|
||||||
isResponding={isResponding}
|
isResponding={respondingState}
|
||||||
chatContainerInnerClassName={cn('mx-auto w-full max-w-full pt-4 tablet:px-4', isMobile && 'px-4')}
|
chatContainerInnerClassName={cn('mx-auto w-full max-w-full pt-4 tablet:px-4', isMobile && 'px-4')}
|
||||||
chatFooterClassName={cn('pb-4', !isMobile && 'rounded-b-2xl')}
|
chatFooterClassName={cn('pb-4', !isMobile && 'rounded-b-2xl')}
|
||||||
chatFooterInnerClassName={cn('mx-auto w-full max-w-full tablet:px-4', isMobile && 'px-2')}
|
chatFooterInnerClassName={cn('mx-auto w-full max-w-full px-4', isMobile && 'px-2')}
|
||||||
onSend={doSend}
|
onSend={doSend}
|
||||||
inputs={currentConversationId ? currentConversationItem?.inputs as any : newConversationInputs}
|
inputs={currentConversationId ? currentConversationItem?.inputs as any : newConversationInputs}
|
||||||
inputsForm={inputsForms}
|
inputsForm={inputsForms}
|
||||||
|
@ -42,6 +42,10 @@ export type EmbeddedChatbotContextValue = {
|
|||||||
handleFeedback: (messageId: string, feedback: Feedback) => void
|
handleFeedback: (messageId: string, feedback: Feedback) => void
|
||||||
currentChatInstanceRef: RefObject<{ handleStop: () => void }>
|
currentChatInstanceRef: RefObject<{ handleStop: () => void }>
|
||||||
themeBuilder?: ThemeBuilder
|
themeBuilder?: ThemeBuilder
|
||||||
|
clearChatList?: boolean
|
||||||
|
setClearChatList: (state: boolean) => void
|
||||||
|
isResponding?: boolean
|
||||||
|
setIsResponding: (state: boolean) => void,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const EmbeddedChatbotContext = createContext<EmbeddedChatbotContextValue>({
|
export const EmbeddedChatbotContext = createContext<EmbeddedChatbotContextValue>({
|
||||||
@ -62,5 +66,9 @@ export const EmbeddedChatbotContext = createContext<EmbeddedChatbotContextValue>
|
|||||||
isInstalledApp: false,
|
isInstalledApp: false,
|
||||||
handleFeedback: () => {},
|
handleFeedback: () => {},
|
||||||
currentChatInstanceRef: { current: { handleStop: () => {} } },
|
currentChatInstanceRef: { current: { handleStop: () => {} } },
|
||||||
|
clearChatList: false,
|
||||||
|
setClearChatList: () => {},
|
||||||
|
isResponding: false,
|
||||||
|
setIsResponding: () => {},
|
||||||
})
|
})
|
||||||
export const useEmbeddedChatbotContext = () => useContext(EmbeddedChatbotContext)
|
export const useEmbeddedChatbotContext = () => useContext(EmbeddedChatbotContext)
|
||||||
|
@ -103,6 +103,8 @@ export const useEmbeddedChatbot = () => {
|
|||||||
const { data: appConversationData, isLoading: appConversationDataLoading, mutate: mutateAppConversationData } = useSWR(['appConversationData', isInstalledApp, appId, false], () => fetchConversations(isInstalledApp, appId, undefined, false, 100))
|
const { data: appConversationData, isLoading: appConversationDataLoading, mutate: mutateAppConversationData } = useSWR(['appConversationData', isInstalledApp, appId, false], () => fetchConversations(isInstalledApp, appId, undefined, false, 100))
|
||||||
const { data: appChatListData, isLoading: appChatListDataLoading } = useSWR(chatShouldReloadKey ? ['appChatList', chatShouldReloadKey, isInstalledApp, appId] : null, () => fetchChatList(chatShouldReloadKey, isInstalledApp, appId))
|
const { data: appChatListData, isLoading: appChatListDataLoading } = useSWR(chatShouldReloadKey ? ['appChatList', chatShouldReloadKey, isInstalledApp, appId] : null, () => fetchChatList(chatShouldReloadKey, isInstalledApp, appId))
|
||||||
|
|
||||||
|
const [clearChatList, setClearChatList] = useState(false)
|
||||||
|
const [isResponding, setIsResponding] = useState(false)
|
||||||
const appPrevChatList = useMemo(
|
const appPrevChatList = useMemo(
|
||||||
() => (currentConversationId && appChatListData?.data.length)
|
() => (currentConversationId && appChatListData?.data.length)
|
||||||
? buildChatItemTree(getFormattedChatList(appChatListData.data))
|
? buildChatItemTree(getFormattedChatList(appChatListData.data))
|
||||||
@ -283,20 +285,16 @@ export const useEmbeddedChatbot = () => {
|
|||||||
currentChatInstanceRef.current.handleStop()
|
currentChatInstanceRef.current.handleStop()
|
||||||
setNewConversationId('')
|
setNewConversationId('')
|
||||||
handleConversationIdInfoChange(conversationId)
|
handleConversationIdInfoChange(conversationId)
|
||||||
}, [handleConversationIdInfoChange])
|
if (conversationId)
|
||||||
|
setClearChatList(false)
|
||||||
|
}, [handleConversationIdInfoChange, setClearChatList])
|
||||||
const handleNewConversation = useCallback(() => {
|
const handleNewConversation = useCallback(() => {
|
||||||
currentChatInstanceRef.current.handleStop()
|
currentChatInstanceRef.current.handleStop()
|
||||||
setNewConversationId('')
|
setShowNewConversationItemInList(true)
|
||||||
|
handleChangeConversation('')
|
||||||
if (showNewConversationItemInList) {
|
handleNewConversationInputsChange({})
|
||||||
handleChangeConversation('')
|
setClearChatList(true)
|
||||||
}
|
}, [handleChangeConversation, setShowNewConversationItemInList, handleNewConversationInputsChange, setClearChatList])
|
||||||
else if (currentConversationId) {
|
|
||||||
handleConversationIdInfoChange('')
|
|
||||||
setShowNewConversationItemInList(true)
|
|
||||||
handleNewConversationInputsChange({})
|
|
||||||
}
|
|
||||||
}, [handleChangeConversation, currentConversationId, handleConversationIdInfoChange, setShowNewConversationItemInList, showNewConversationItemInList, handleNewConversationInputsChange])
|
|
||||||
|
|
||||||
const handleNewConversationCompleted = useCallback((newConversationId: string) => {
|
const handleNewConversationCompleted = useCallback((newConversationId: string) => {
|
||||||
setNewConversationId(newConversationId)
|
setNewConversationId(newConversationId)
|
||||||
@ -342,5 +340,9 @@ export const useEmbeddedChatbot = () => {
|
|||||||
chatShouldReloadKey,
|
chatShouldReloadKey,
|
||||||
handleFeedback,
|
handleFeedback,
|
||||||
currentChatInstanceRef,
|
currentChatInstanceRef,
|
||||||
|
clearChatList,
|
||||||
|
setClearChatList,
|
||||||
|
isResponding,
|
||||||
|
setIsResponding,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -156,6 +156,10 @@ const EmbeddedChatbotWrapper = () => {
|
|||||||
appId,
|
appId,
|
||||||
handleFeedback,
|
handleFeedback,
|
||||||
currentChatInstanceRef,
|
currentChatInstanceRef,
|
||||||
|
clearChatList,
|
||||||
|
setClearChatList,
|
||||||
|
isResponding,
|
||||||
|
setIsResponding,
|
||||||
} = useEmbeddedChatbot()
|
} = useEmbeddedChatbot()
|
||||||
|
|
||||||
return <EmbeddedChatbotContext.Provider value={{
|
return <EmbeddedChatbotContext.Provider value={{
|
||||||
@ -185,6 +189,10 @@ const EmbeddedChatbotWrapper = () => {
|
|||||||
handleFeedback,
|
handleFeedback,
|
||||||
currentChatInstanceRef,
|
currentChatInstanceRef,
|
||||||
themeBuilder,
|
themeBuilder,
|
||||||
|
clearChatList,
|
||||||
|
setClearChatList,
|
||||||
|
isResponding,
|
||||||
|
setIsResponding,
|
||||||
}}>
|
}}>
|
||||||
<Chatbot />
|
<Chatbot />
|
||||||
</EmbeddedChatbotContext.Provider>
|
</EmbeddedChatbotContext.Provider>
|
||||||
|
@ -213,7 +213,7 @@
|
|||||||
display: block;
|
display: block;
|
||||||
width: max-content;
|
width: max-content;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
overflow: hidden;
|
overflow: auto;
|
||||||
border: 1px solid var(--color-divider-regular);
|
border: 1px solid var(--color-divider-regular);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user