fix: typing delay (#2200)

This commit is contained in:
zxhlyh
2024-01-25 14:55:12 +08:00
committed by GitHub
parent 301e0496ff
commit f2b2effc4b
6 changed files with 201 additions and 161 deletions

View File

@@ -1,4 +1,4 @@
import { useState } from 'react'
import { useCallback, useState } from 'react'
import produce from 'immer'
import { useGetState } from 'ahooks'
import type { ConversationItem } from '@/models/share'
@@ -11,7 +11,7 @@ function useConversation() {
const [pinnedConversationList, setPinnedConversationList] = useState<ConversationItem[]>([])
const [currConversationId, doSetCurrConversationId, getCurrConversationId] = useGetState<string>('-1')
// when set conversation id, we do not have set appId
const setCurrConversationId = (id: string, appId: string, isSetToLocalStroge = true, newConversationName = '') => {
const setCurrConversationId = useCallback((id: string, appId: string, isSetToLocalStroge = true, newConversationName = '') => {
doSetCurrConversationId(id)
if (isSetToLocalStroge && id !== '-1') {
// conversationIdInfo: {[appId1]: conversationId1, [appId2]: conversationId2}
@@ -19,7 +19,7 @@ function useConversation() {
conversationIdInfo[appId] = id
globalThis.localStorage?.setItem(storageConversationIdKey, JSON.stringify(conversationIdInfo))
}
}
}, [doSetCurrConversationId])
const getConversationIdFromStorage = (appId: string) => {
const conversationIdInfo = globalThis.localStorage?.getItem(storageConversationIdKey) ? JSON.parse(globalThis.localStorage?.getItem(storageConversationIdKey) || '') : {}

View File

@@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-use-before-define */
'use client'
import type { FC } from 'react'
import React, { useEffect, useRef, useState } from 'react'
import React, { useCallback, useEffect, useRef, useState } from 'react'
import cn from 'classnames'
import useSWR from 'swr'
import { useTranslation } from 'react-i18next'
@@ -65,6 +65,7 @@ const Main: FC<IMainProps> = ({
installedAppInfo,
}) => {
const { t } = useTranslation()
const { notify } = useContext(ToastContext)
const media = useBreakpoints()
const isMobile = media === MediaType.mobile
@@ -123,7 +124,8 @@ const Main: FC<IMainProps> = ({
const [suggestedQuestions, setSuggestQuestions] = useState<string[]>([])
const [hasMore, setHasMore] = useState<boolean>(true)
const [hasPinnedMore, setHasPinnedMore] = useState<boolean>(true)
const onMoreLoaded = ({ data: conversations, has_more }: any) => {
const [isShowSuggestion, setIsShowSuggestion] = useState(false)
const onMoreLoaded = useCallback(({ data: conversations, has_more }: any) => {
setHasMore(has_more)
if (isClearConversationList) {
setConversationList(conversations)
@@ -132,8 +134,8 @@ const Main: FC<IMainProps> = ({
else {
setConversationList([...conversationList, ...conversations])
}
}
const onPinnedMoreLoaded = ({ data: conversations, has_more }: any) => {
}, [conversationList, setConversationList, isClearConversationList, clearConversationListFalse])
const onPinnedMoreLoaded = useCallback(({ data: conversations, has_more }: any) => {
setHasPinnedMore(has_more)
if (isClearPinnedConversationList) {
setPinnedConversationList(conversations)
@@ -142,9 +144,9 @@ const Main: FC<IMainProps> = ({
else {
setPinnedConversationList([...pinnedConversationList, ...conversations])
}
}
}, [pinnedConversationList, setPinnedConversationList, isClearPinnedConversationList, clearPinnedConversationListFalse])
const [controlUpdateConversationList, setControlUpdateConversationList] = useState(0)
const noticeUpdateList = () => {
const noticeUpdateList = useCallback(() => {
setHasMore(true)
clearConversationListTrue()
@@ -152,25 +154,25 @@ const Main: FC<IMainProps> = ({
clearPinnedConversationListTrue()
setControlUpdateConversationList(Date.now())
}
const handlePin = async (id: string) => {
}, [clearConversationListTrue, clearPinnedConversationListTrue])
const handlePin = useCallback(async (id: string) => {
await pinConversation(isInstalledApp, installedAppInfo?.id, id)
notify({ type: 'success', message: t('common.api.success') })
noticeUpdateList()
}
}, [isInstalledApp, installedAppInfo?.id, t, notify, noticeUpdateList])
const handleUnpin = async (id: string) => {
const handleUnpin = useCallback(async (id: string) => {
await unpinConversation(isInstalledApp, installedAppInfo?.id, id)
notify({ type: 'success', message: t('common.api.success') })
noticeUpdateList()
}
}, [isInstalledApp, installedAppInfo?.id, t, notify, noticeUpdateList])
const [isShowConfirm, { setTrue: showConfirm, setFalse: hideConfirm }] = useBoolean(false)
const [toDeleteConversationId, setToDeleteConversationId] = useState('')
const handleDelete = (id: string) => {
const handleDelete = useCallback((id: string) => {
setToDeleteConversationId(id)
hideSidebar() // mobile
showConfirm()
}
}, [hideSidebar, showConfirm])
const didDelete = async () => {
await delConversation(isInstalledApp, installedAppInfo?.id, toDeleteConversationId)
@@ -186,17 +188,51 @@ const Main: FC<IMainProps> = ({
const [speechToTextConfig, setSpeechToTextConfig] = useState<SpeechToTextConfig | null>(null)
const [textToSpeechConfig, setTextToSpeechConfig] = useState<TextToSpeechConfig | null>(null)
const [citationConfig, setCitationConfig] = useState<CitationConfig | null>(null)
const [chatList, setChatList, getChatList] = useGetState<IChatItem[]>([])
const chatListDomRef = useRef<HTMLDivElement>(null)
const [isResponsing, { setTrue: setResponsingTrue, setFalse: setResponsingFalse }] = useBoolean(false)
const [abortController, setAbortController] = useState<AbortController | null>(null)
const [conversationIdChangeBecauseOfNew, setConversationIdChangeBecauseOfNew, getConversationIdChangeBecauseOfNew] = useGetState(false)
const [isChatStarted, { setTrue: setChatStarted, setFalse: setChatNotStarted }] = useBoolean(false)
const handleStartChat = (inputs: Record<string, any>) => {
const conversationIntroduction = currConversationInfo?.introduction || ''
const createNewChat = useCallback(async () => {
// if new chat is already exist, do not create new chat
abortController?.abort()
setResponsingFalse()
if (conversationList.some(item => item.id === '-1'))
return
setConversationList(produce(conversationList, (draft) => {
draft.unshift({
id: '-1',
name: t('share.chat.newChatDefaultName'),
inputs: newConversationInputs,
introduction: conversationIntroduction,
})
}))
}, [
abortController,
setResponsingFalse,
setConversationList,
conversationList,
newConversationInputs,
conversationIntroduction,
t,
])
const handleStartChat = useCallback((inputs: Record<string, any>) => {
createNewChat()
setConversationIdChangeBecauseOfNew(true)
setCurrInputs(inputs)
setChatStarted()
// parse variables in introduction
setChatList(generateNewChatListWithOpenstatement('', inputs))
}
}, [
createNewChat,
setConversationIdChangeBecauseOfNew,
setCurrInputs,
setChatStarted,
setChatList,
])
const hasSetInputs = (() => {
if (!isNewConversation)
return true
@@ -205,7 +241,6 @@ const Main: FC<IMainProps> = ({
})()
const conversationName = currConversationInfo?.name || t('share.chat.newChatDefaultName') as string
const conversationIntroduction = currConversationInfo?.introduction || ''
const [controlChatUpdateAllConversation, setControlChatUpdateAllConversation] = useState(0)
// onData change thought (the produce obj). https://github.com/immerjs/immer/issues/576
@@ -293,7 +328,18 @@ const Main: FC<IMainProps> = ({
}
useEffect(handleConversationSwitch, [currConversationId, inited])
const handleConversationIdChange = (id: string) => {
/*
* chat info. chat is under conversation.
*/
useEffect(() => {
// scroll to bottom
if (chatListDomRef.current)
chatListDomRef.current.scrollTop = chatListDomRef.current.scrollHeight
}, [chatList, currConversationId])
// user can not edit inputs if user had send message
const canEditInpus = !chatList.some(item => item.isAnswer === false) && isNewConversation
const handleConversationIdChange = useCallback((id: string) => {
if (id === '-1') {
createNewChat()
setConversationIdChangeBecauseOfNew(true)
@@ -305,36 +351,14 @@ const Main: FC<IMainProps> = ({
setCurrConversationId(id, appId)
setIsShowSuggestion(false)
hideSidebar()
}
/*
* chat info. chat is under conversation.
*/
const [chatList, setChatList, getChatList] = useGetState<IChatItem[]>([])
const chatListDomRef = useRef<HTMLDivElement>(null)
useEffect(() => {
// scroll to bottom
if (chatListDomRef.current)
chatListDomRef.current.scrollTop = chatListDomRef.current.scrollHeight
}, [chatList, currConversationId])
// user can not edit inputs if user had send message
const canEditInpus = !chatList.some(item => item.isAnswer === false) && isNewConversation
const createNewChat = async () => {
// if new chat is already exist, do not create new chat
abortController?.abort()
setResponsingFalse()
if (conversationList.some(item => item.id === '-1'))
return
setConversationList(produce(conversationList, (draft) => {
draft.unshift({
id: '-1',
name: t('share.chat.newChatDefaultName'),
inputs: newConversationInputs,
introduction: conversationIntroduction,
})
}))
}
}, [
appId,
createNewChat,
hideSidebar,
setCurrConversationId,
setIsShowSuggestion,
setConversationIdChangeBecauseOfNew,
])
// sometime introduction is not applied to state
const generateNewChatListWithOpenstatement = (introduction?: string, inputs?: Record<string, any> | null) => {
@@ -446,14 +470,11 @@ const Main: FC<IMainProps> = ({
})()
}, [])
const [isResponsing, { setTrue: setResponsingTrue, setFalse: setResponsingFalse }] = useBoolean(false)
const [abortController, setAbortController] = useState<AbortController | null>(null)
const { notify } = useContext(ToastContext)
const logError = (message: string) => {
const logError = useCallback((message: string) => {
notify({ type: 'error', message })
}
}, [notify])
const checkCanSend = () => {
const checkCanSend = useCallback(() => {
if (currConversationId !== '-1')
return true
@@ -480,10 +501,9 @@ const Main: FC<IMainProps> = ({
return false
}
return !hasEmptyInput
}
}, [currConversationId, currInputs, promptConfig, t, logError])
const [controlFocus, setControlFocus] = useState(0)
const [isShowSuggestion, setIsShowSuggestion] = useState(false)
const doShowSuggestion = isShowSuggestion && !isResponsing
const [openingSuggestedQuestions, setOpeningSuggestedQuestions] = useState<string[]>([])
const [messageTaskId, setMessageTaskId] = useState('')
@@ -755,7 +775,7 @@ const Main: FC<IMainProps> = ({
}, isInstalledApp, installedAppInfo?.id)
}
const handleFeedback = async (messageId: string, feedback: Feedbacktype) => {
const handleFeedback = useCallback(async (messageId: string, feedback: Feedbacktype) => {
await updateFeedback({ url: `/messages/${messageId}/feedbacks`, body: { rating: feedback.rating } }, isInstalledApp, installedAppInfo?.id)
const newChatList = chatList.map((item) => {
if (item.id === messageId) {
@@ -768,7 +788,19 @@ const Main: FC<IMainProps> = ({
})
setChatList(newChatList)
notify({ type: 'success', message: t('common.api.success') })
}
}, [isInstalledApp, installedAppInfo?.id, chatList, t, notify, setChatList])
const handleListChanged = useCallback((list: ConversationItem[]) => {
setConversationList(list)
setControlChatUpdateAllConversation(Date.now())
}, [setConversationList, setControlChatUpdateAllConversation])
const handlePinnedListChanged = useCallback((list: ConversationItem[]) => {
setPinnedConversationList(list)
setControlChatUpdateAllConversation(Date.now())
}, [setPinnedConversationList, setControlChatUpdateAllConversation])
const handleStartChatOnSidebar = useCallback(() => {
handleConversationIdChange('-1')
}, [handleConversationIdChange])
const renderSidebar = () => {
if (!appId || !siteInfo || !promptConfig)
@@ -776,16 +808,10 @@ const Main: FC<IMainProps> = ({
return (
<Sidebar
list={conversationList}
onListChanged={(list) => {
setConversationList(list)
setControlChatUpdateAllConversation(Date.now())
}}
onListChanged={handleListChanged}
isClearConversationList={isClearConversationList}
pinnedList={pinnedConversationList}
onPinnedListChanged={(list) => {
setPinnedConversationList(list)
setControlChatUpdateAllConversation(Date.now())
}}
onPinnedListChanged={handlePinnedListChanged}
isClearPinnedConversationList={isClearPinnedConversationList}
onMoreLoaded={onMoreLoaded}
onPinnedMoreLoaded={onPinnedMoreLoaded}
@@ -801,11 +827,17 @@ const Main: FC<IMainProps> = ({
onUnpin={handleUnpin}
controlUpdateList={controlUpdateConversationList}
onDelete={handleDelete}
onStartChat={() => handleConversationIdChange('-1')}
onStartChat={handleStartChatOnSidebar}
/>
)
}
const handleAbortResponsing = useCallback(async () => {
await stopChatMessageResponding(appId, messageTaskId, isInstalledApp, installedAppInfo?.id)
setHasStopResponded(true)
setResponsingFalse()
}, [appId, messageTaskId, isInstalledApp, installedAppInfo?.id])
if (appUnavailable)
return <AppUnavailable isUnknwonReason={isUnknwonReason} />
@@ -824,7 +856,7 @@ const Main: FC<IMainProps> = ({
icon_background={siteInfo.icon_background}
isMobile={isMobile}
onShowSideBar={showSidebar}
onCreateNewChat={() => handleConversationIdChange('-1')}
onCreateNewChat={handleStartChatOnSidebar}
/>
)}
@@ -884,11 +916,7 @@ const Main: FC<IMainProps> = ({
onFeedback={handleFeedback}
isResponsing={isResponsing}
canStopResponsing={!!messageTaskId && isResponsingConIsCurrCon}
abortResponsing={async () => {
await stopChatMessageResponding(appId, messageTaskId, isInstalledApp, installedAppInfo?.id)
setHasStopResponded(true)
setResponsingFalse()
}}
abortResponsing={handleAbortResponsing}
checkCanSend={checkCanSend}
controlFocus={controlFocus}
isShowSuggestion={doShowSuggestion}

View File

@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react'
import React, { useCallback, useEffect, useState } from 'react'
import type { FC } from 'react'
import { useTranslation } from 'react-i18next'
import {
@@ -76,6 +76,13 @@ const Sidebar: FC<ISidebarProps> = ({
checkHasPinned()
}, [controlUpdateList])
const handleUnpin = useCallback((id: string) => {
onUnpin(id)
}, [onUnpin])
const handlePin = useCallback((id: string) => {
onPin(id)
}, [onPin])
const maxListHeight = (isInstalledApp) ? 'max-h-[30vh]' : 'max-h-[40vh]'
return (
@@ -119,7 +126,7 @@ const Sidebar: FC<ISidebarProps> = ({
onMoreLoaded={onPinnedMoreLoaded}
isNoMore={isPinnedNoMore}
isPinned={true}
onPinChanged={id => onUnpin(id)}
onPinChanged={handleUnpin}
controlUpdate={controlUpdateList + 1}
onDelete={onDelete}
/>
@@ -142,7 +149,7 @@ const Sidebar: FC<ISidebarProps> = ({
onMoreLoaded={onMoreLoaded}
isNoMore={isNoMore}
isPinned={false}
onPinChanged={id => onPin(id)}
onPinChanged={handlePin}
controlUpdate={controlUpdateList + 1}
onDelete={onDelete}
/>