| 
					
				 | 
			
			
				@@ -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,25 +328,9 @@ const Main: FC<IMainProps> = ({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   useEffect(handleConversationSwitch, [currConversationId, inited]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  const handleConversationIdChange = (id: string) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    if (id === '-1') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      createNewChat() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      setConversationIdChangeBecauseOfNew(true) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      setConversationIdChangeBecauseOfNew(false) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    // trigger handleConversationSwitch 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    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) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -319,22 +338,27 @@ const Main: FC<IMainProps> = ({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   }, [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, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    })) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const handleConversationIdChange = useCallback((id: string) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (id === '-1') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      createNewChat() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      setConversationIdChangeBecauseOfNew(true) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      setConversationIdChangeBecauseOfNew(false) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // trigger handleConversationSwitch 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    setCurrConversationId(id, appId) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    setIsShowSuggestion(false) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    hideSidebar() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }, [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    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} 
			 |