From 8a22b17e1b48fc35877851d95379c8a68e1a8f8f Mon Sep 17 00:00:00 2001 From: gray Date: Wed, 18 Dec 2024 10:08:59 +0800 Subject: [PATCH] optimize chat --- src/FE/apis/clientApis.ts | 11 +- src/FE/pages/home/_actions/chat.actions.ts | 8 +- src/FE/pages/home/_actions/message.actions.ts | 13 +- src/FE/pages/home/_components/Chat/Chat.tsx | 140 +++++++++--------- .../pages/home/_components/Chat/ChatInput.tsx | 9 +- .../home/_components/Home/HomeContent.tsx | 67 ++++++--- .../home/_components/Sidebar/Sidebar.tsx | 4 +- src/FE/pages/home/_contexts/home.context.tsx | 3 + src/FE/pages/home/_reducers/chat.reducer.ts | 10 ++ .../pages/home/_reducers/message.reducer.ts | 17 ++- src/FE/types/chatMessage.ts | 28 ++-- src/FE/types/clientApis.ts | 2 +- src/FE/utils/message.ts | 2 +- 13 files changed, 186 insertions(+), 128 deletions(-) diff --git a/src/FE/apis/clientApis.ts b/src/FE/apis/clientApis.ts index 0cbcb0b6..c90b8173 100644 --- a/src/FE/apis/clientApis.ts +++ b/src/FE/apis/clientApis.ts @@ -1,6 +1,6 @@ import { useFetch } from '@/hooks/useFetch'; -import { calculateMessages } from '@/utils/message'; +import { formatMessages } from '@/utils/message'; import { AdminModelDto, PostPromptParams } from '@/types/adminApis'; import { ChatMessage } from '@/types/chatMessage'; @@ -33,9 +33,7 @@ export const changeUserPassword = (params: PostUserPassword) => { export const getUserMessages = (chatId: string): Promise => { const fetchService = useFetch(); - return fetchService.get(`/api/messages/${chatId}`).then((data: any) => { - return calculateMessages(data) as any; - }); + return fetchService.get(`/api/messages/${chatId}`); }; export const getChatsByPaging = ( @@ -68,6 +66,11 @@ export const deleteChats = (id: string) => { return fetchService.delete(`/api/user/chats/${id}`); }; +export const stopChat = (id: string) => { + const fetchService = useFetch(); + return fetchService.post(`/api/chats/stop/${id}`); +}; + export const getCsrfToken = (): Promise<{ csrfToken: string }> => { const fetchServer = useFetch(); return fetchServer.get('/api/auth/csrf'); diff --git a/src/FE/pages/home/_actions/chat.actions.ts b/src/FE/pages/home/_actions/chat.actions.ts index ae6dec0c..cfc6ae84 100644 --- a/src/FE/pages/home/_actions/chat.actions.ts +++ b/src/FE/pages/home/_actions/chat.actions.ts @@ -7,6 +7,7 @@ import { SetIsChatsLoadingType, SetMessageIsStreamingType, SetSelectedChatType, + SetStopIdsType, } from '../_reducers/chat.reducer'; export const setChats = (chats: SetChatsType): ChatAction => ({ @@ -39,8 +40,13 @@ export const setMessageIsStreaming = ( export const setIsChatsLoading = ( isChatsLoading: SetIsChatsLoadingType, ): ChatAction => ({ - type: ChatActionTypes.SET_MESSAGE_IS_STREAMING, + type: ChatActionTypes.SET_IS_CHATS_LOADING, payload: isChatsLoading, }); +export const setStopIds = (stopIds: SetStopIdsType): ChatAction => ({ + type: ChatActionTypes.SET_STOP_IDS, + payload: stopIds, +}); + export default function () {} diff --git a/src/FE/pages/home/_actions/message.actions.ts b/src/FE/pages/home/_actions/message.actions.ts index ecb16818..e60f5bc3 100644 --- a/src/FE/pages/home/_actions/message.actions.ts +++ b/src/FE/pages/home/_actions/message.actions.ts @@ -4,14 +4,23 @@ import { SetCurrentMessageIdType, SetCurrentMessagesType, SetLastMessageIdType, - SetMessagesType, + SetSelectedMessagesType, } from '../_reducers/message.reducer'; -export const setMessages = (messages: SetMessagesType): MessageAction => ({ +export const setMessages = ( + messages: SetSelectedMessagesType, +): MessageAction => ({ type: MessageActionTypes.SET_MESSAGES, payload: messages, }); +export const setSelectedMessages = ( + selectedMessages: SetSelectedMessagesType, +): MessageAction => ({ + type: MessageActionTypes.SET_SELECTED_MESSAGES, + payload: selectedMessages, +}); + export const setCurrentMessages = ( currentMessages: SetCurrentMessagesType, ): MessageAction => ({ diff --git a/src/FE/pages/home/_components/Chat/Chat.tsx b/src/FE/pages/home/_components/Chat/Chat.tsx index 5cdd4daa..696c6bb0 100644 --- a/src/FE/pages/home/_components/Chat/Chat.tsx +++ b/src/FE/pages/home/_components/Chat/Chat.tsx @@ -11,26 +11,29 @@ import toast from 'react-hot-toast'; import useTranslation from '@/hooks/useTranslation'; import { getApiUrl } from '@/utils/common'; +import { formatMessages, getSelectMessages } from '@/utils/message'; import { throttle } from '@/utils/throttle'; import { getUserSession } from '@/utils/user'; import { ChatBody, Content, ContentRequest, Message, Role } from '@/types/chat'; +import { SseResponseKind, SseResponseLine } from '@/types/chatMessage'; import { Prompt } from '@/types/prompt'; import ChangeModel from '@/components/ChangeModel/ChangeModel'; import TemperatureSlider from '@/components/TemperatureSlider/TemperatureSlider'; -import { setMessageIsStreaming } from '../../_actions/chat.actions'; +import { setMessageIsStreaming, setStopIds } from '../../_actions/chat.actions'; import { setCurrentMessages, + setLastMessageId, setMessages, + setSelectedMessages, } from '../../_actions/message.actions'; import { setSelectedModel } from '../../_actions/model.actions'; import { setEnableSearch, setPrompt, setTemperature, - setUserModelConfig, } from '../../_actions/userModelConfig.actions'; import HomeContext from '../../_contexts/home.context'; import ModeToggle from '../ModeToggle/ModeToggle'; @@ -41,9 +44,8 @@ import ModelSelect from './ModelSelect'; import NoModel from './NoModel'; import SystemPrompt from './SystemPrompt'; -import { getChat, putUserChatModel } from '@/apis/clientApis'; +import { putUserChatModel } from '@/apis/clientApis'; import { cn } from '@/lib/utils'; -import { SseResponseKind, SseResponseLine } from '@/types/chatMessage'; const Chat = memo(() => { const { t } = useTranslation(); @@ -59,6 +61,7 @@ const Chat = memo(() => { chatError, messageIsStreaming, + messages, selectMessages, currentChatMessageId, currentMessages, @@ -73,10 +76,9 @@ const Chat = memo(() => { handleStartChat, handleChatIsError, handleUpdateChatStatus, - handleUpdateChats, + handleStopChats, handleUpdateSelectMessage, - handleUpdateCurrentMessage, hasModel, chatDispatch, messageDispatch, @@ -89,8 +91,6 @@ const Chat = memo(() => { const messagesEndRef = useRef(null); const chatContainerRef = useRef(null); - const stopConversationRef = useRef(false); - const getSelectMessagesLast = () => { const selectMessageLength = selectMessages.length - 1; const lastMessage = { ...selectMessages[selectMessageLength] }; @@ -104,32 +104,37 @@ const Chat = memo(() => { isRegenerate: boolean, modelId?: number, ) => { - const isChatEmpty = selectMessages.length === 0; handleUpdateChatStatus(false); let selectChatId = selectChat?.id; - let selectMessageList = [...selectMessages]; + let newMessages = [...messages]; + let newSelectedMessages = [...selectMessages]; let assistantParentId = messageId; if (!selectChatId) { const newChat = await handleCreateNewChat(); selectChatId = newChat.id; } let selectedMessageId = messageId; + const MESSAGE_TEMP_ID = 'userMessageTempId'; if (messageId && isRegenerate) { - const messageIndex = selectMessageList.findIndex( + const messageIndex = newSelectedMessages.findIndex( (x) => x.id === messageId, ); - selectMessageList.splice(messageIndex + 1, selectMessageList.length); + newSelectedMessages.splice( + messageIndex + 1, + newSelectedMessages.length, + ); } else { - const messageTempId = 'userMessageTempId'; - assistantParentId = messageTempId; - selectedMessageId = messageTempId; - const parentMessage = selectMessageList.find((x) => x.id == messageId); - parentMessage && parentMessage?.childrenIds.unshift(messageTempId); - const parentMessageIndex = selectMessageList.findIndex( + assistantParentId = MESSAGE_TEMP_ID; + selectedMessageId = MESSAGE_TEMP_ID; + const parentMessage = newSelectedMessages.find( + (x) => x.id == messageId, + ); + parentMessage && parentMessage?.childrenIds?.unshift(MESSAGE_TEMP_ID); + const parentMessageIndex = newSelectedMessages.findIndex( (x) => x.id == messageId, ); const newUserMessage = { - id: messageTempId, + id: MESSAGE_TEMP_ID, role: 'user' as Role, parentId: messageId, childrenIds: [], @@ -142,24 +147,25 @@ const Chat = memo(() => { }; let removeCount = -1; if (parentMessageIndex !== -1) - removeCount = selectMessageList.length - 1; + removeCount = newSelectedMessages.length - 1; if (!messageId) { - removeCount = selectMessageList.length; + removeCount = newSelectedMessages.length; messageDispatch( setCurrentMessages([...currentMessages, newUserMessage]), ); } - selectMessageList.splice( + newSelectedMessages.splice( parentMessageIndex + 1, removeCount, newUserMessage, ); + newMessages.push(newUserMessage); } - const assistantMessageTempId = 'assistantMessageTempId'; + const ASSISTANT_MESSAGE_TEMP_ID = 'assistantMessageTempId'; const newAssistantMessage = { - id: assistantMessageTempId, + id: ASSISTANT_MESSAGE_TEMP_ID, role: 'assistant' as Role, parentId: assistantParentId, childrenIds: [], @@ -174,11 +180,12 @@ const Chat = memo(() => { outputPrice: 0, }; - selectMessageList.push(newAssistantMessage); + newSelectedMessages.push(newAssistantMessage); + newMessages.push(newAssistantMessage); handleStartChat( - selectMessageList, + newSelectedMessages, selectedMessageId, - assistantMessageTempId, + ASSISTANT_MESSAGE_TEMP_ID, ); const messageContent: ContentRequest = { @@ -202,14 +209,12 @@ const Chat = memo(() => { }; let body = JSON.stringify(chatBody); - const controller = new AbortController(); const response = await fetch(`${getApiUrl()}/api/chats`, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${getUserSession()}`, }, - signal: controller.signal, body, }); @@ -225,22 +230,22 @@ const Chat = memo(() => { return; } - let errorChat = false; + let isErrorChat = false; let text = ''; const reader = data.getReader(); const decoder = new TextDecoder(); let buffer = ''; function setSelectMessages(content: Content) { - let lastMessages = selectMessageList[selectMessageList.length - 1]; + let lastMessages = newSelectedMessages[newSelectedMessages.length - 1]; lastMessages = { ...lastMessages, content, }; - selectMessageList.splice(-1, 1, lastMessages); + newSelectedMessages.splice(-1, 1, lastMessages); - messageDispatch(setMessages([...selectMessageList])); + messageDispatch(setSelectedMessages([...newSelectedMessages])); } async function* processBuffer() { while (true) { @@ -271,49 +276,40 @@ const Chat = memo(() => { const value: SseResponseLine = JSON.parse(message); if (value.k === SseResponseKind.StopId) { - const stopId = value.r; - console.log('stopId', stopId); - } - else if (value.k === SseResponseKind.Segment) { + chatDispatch(setStopIds([value.r])); + } else if (value.k === SseResponseKind.Segment) { text += value.r; setSelectMessages({ text }); - } - else if (value.k === SseResponseKind.Error) { // error - errorChat = true; - handleUpdateChatStatus(errorChat); - controller.abort(); + } else if (value.k === SseResponseKind.Error) { + isErrorChat = true; + handleUpdateChatStatus(isErrorChat); + handleStopChats(); setSelectMessages({ text, error: value.r }); - break; - } - else if (value.k === SseResponseKind.End) { - console.log('End', value.r); - } - if (stopConversationRef.current === true) { - controller.abort(); - break; - } - } - - if (isChatEmpty) { - setTimeout(async () => { - const data = await getChat(selectChatId); - const _chats = chats.map((x) => { - if (x.id === data.id) { - return data; + } else if (value.k === SseResponseKind.End) { + const { requestMessage, responseMessage } = value.r; + newMessages = newMessages.map((m) => { + if (requestMessage && m.id === MESSAGE_TEMP_ID) { + m = { ...m, ...requestMessage }; + } + if (m.id === ASSISTANT_MESSAGE_TEMP_ID) { + m = { ...m, ...responseMessage }; } - return x; + return m; }); - userModelConfigDispatch(setUserModelConfig(data.userModelConfig)); - handleUpdateChats(_chats); - }, 100); + const messageList = formatMessages(newMessages); + messageDispatch(setMessages(newMessages)); + messageDispatch(setCurrentMessages(messageList)); + const lastMessage = messageList[messageList.length - 1]; + const selectMessageList = getSelectMessages( + messageList, + lastMessage.id, + ); + messageDispatch(setSelectedMessages(selectMessageList)); + messageDispatch(setLastMessageId(lastMessage.id)); + } } chatDispatch(setMessageIsStreaming(false)); - !errorChat && - setTimeout(() => { - handleUpdateCurrentMessage(selectChatId); - }, 200); - stopConversationRef.current = false; }, [ prompt, @@ -325,7 +321,6 @@ const Chat = memo(() => { currentMessages, selectMessages, selectModel, - stopConversationRef, ], ); @@ -480,10 +475,10 @@ const Chat = memo(() => { (x) => x === current.id, )} parentId={current.parentId} - childrenIds={current.childrenIds} + childrenIds={current.childrenIds!} parentChildrenIds={parentChildrenIds} - assistantChildrenIds={current.assistantChildrenIds} - assistantCurrentSelectIndex={current.assistantChildrenIds.findIndex( + assistantChildrenIds={current.assistantChildrenIds!} + assistantCurrentSelectIndex={current.assistantChildrenIds!.findIndex( (x) => x === current.id, )} lastMessageId={lastMessage.id} @@ -530,7 +525,6 @@ const Chat = memo(() => { {hasModel() && ( { const { lastMessage } = getSelectMessagesLast(); handleSend(message, lastMessage?.id, false); diff --git a/src/FE/pages/home/_components/Chat/ChatInput.tsx b/src/FE/pages/home/_components/Chat/ChatInput.tsx index e8948ec6..32db7aa0 100644 --- a/src/FE/pages/home/_components/Chat/ChatInput.tsx +++ b/src/FE/pages/home/_components/Chat/ChatInput.tsx @@ -43,7 +43,6 @@ interface Props { onChangePrompt: (prompt: Prompt) => void; model: AdminModelDto; showScrollDownButton: boolean; - stopConversationRef: MutableRefObject; } const ChatInput = ({ @@ -51,12 +50,12 @@ const ChatInput = ({ onScrollDownClick, onChangePrompt, showScrollDownButton, - stopConversationRef, }: Props) => { const { t } = useTranslation(); const { state: { selectModel, messageIsStreaming, prompts, selectChat, chatError }, + handleStopChats, } = useContext(HomeContext); const textareaRef = useRef(null); @@ -124,10 +123,6 @@ const ChatInput = ({ } }; - const handleStopChat = () => { - stopConversationRef.current = true; - }; - const handleKeyDown = (e: KeyboardEvent) => { if (showPromptList) { if (e.key === 'ArrowDown') { @@ -335,7 +330,7 @@ const ChatInput = ({ > {messageIsStreaming ? ( ) : ( diff --git a/src/FE/pages/home/_components/Home/HomeContent.tsx b/src/FE/pages/home/_components/Home/HomeContent.tsx index 03f942f2..b52c1951 100644 --- a/src/FE/pages/home/_components/Home/HomeContent.tsx +++ b/src/FE/pages/home/_components/Home/HomeContent.tsx @@ -10,7 +10,7 @@ import { getStorageChatId, setStorageChatId, } from '@/utils/chats'; -import { getSelectMessages } from '@/utils/message'; +import { formatMessages, getSelectMessages } from '@/utils/message'; import { getStorageModelId, setStorageModelId } from '@/utils/model'; import { formatPrompt } from '@/utils/promptVariable'; import { getSettings } from '@/utils/settings'; @@ -28,12 +28,14 @@ import { setIsChatsLoading, setMessageIsStreaming, setSelectedChat, + setStopIds, } from '../../_actions/chat.actions'; import { setCurrentMessageId, setCurrentMessages, setLastMessageId, setMessages, + setSelectedMessages, } from '../../_actions/message.actions'; import { setModels, setSelectedModel } from '../../_actions/model.actions'; import { setPrompts } from '../../_actions/prompt.actions'; @@ -72,6 +74,7 @@ import { getUserModels, getUserPromptBrief, postChats, + stopChat, } from '@/apis/clientApis'; const HomeContent = () => { @@ -99,7 +102,7 @@ const HomeContent = () => { promptInitialState, ); - const { chats } = chatState; + const { chats, stopIds } = chatState; const { currentMessages } = messageState; const { models } = modelState; const { temperature } = userModelConfigState; @@ -164,6 +167,7 @@ const HomeContent = () => { chatDispatch(setChats([...chats])); chatDispatch(setSelectedChat(chat)); messageDispatch(setMessages([])); + messageDispatch(setSelectedMessages([])); messageDispatch(setCurrentMessages([])); return chat; }; @@ -183,7 +187,7 @@ const HomeContent = () => { currentMessageId: string, ) => { chatDispatch(setMessageIsStreaming(true)); - messageDispatch(setMessages(selectedMessages)); + messageDispatch(setSelectedMessages(selectedMessages)); messageDispatch(setLastMessageId(selectedMessageId)); messageDispatch(setCurrentMessageId(currentMessageId)); }; @@ -195,8 +199,9 @@ const HomeContent = () => { chatDispatch(setSelectedChat(data)); chatDispatch(setChatStatus(false)); - messageDispatch(setLastMessageId('')); messageDispatch(setMessages([])); + messageDispatch(setLastMessageId('')); + messageDispatch(setSelectedMessages([])); messageDispatch(setCurrentMessages([])); handleSelectModel(model!); router.push('#/' + data.id); @@ -206,13 +211,15 @@ const HomeContent = () => { const handleUpdateCurrentMessage = (chatId: string) => { getUserMessages(chatId).then((data) => { if (data.length > 0) { - messageDispatch(setCurrentMessages(data)); - const lastMessage = data[data.length - 1]; - const selectMessageList = getSelectMessages(data, lastMessage.id); - messageDispatch(setMessages(selectMessageList)); + messageDispatch(setMessages(data)); + const messages = formatMessages(data); + messageDispatch(setCurrentMessages(messages)); + const lastMessage = messages[messages.length - 1]; + const selectMessageList = getSelectMessages(messages, lastMessage.id); + messageDispatch(setSelectedMessages(selectMessageList)); messageDispatch(setLastMessageId(lastMessage.id)); } else { - messageDispatch(setMessages([])); + messageDispatch(setSelectedMessages([])); messageDispatch(setCurrentMessages([])); } }); @@ -236,21 +243,23 @@ const HomeContent = () => { selectModel && setStorageModelId(selectModel.modelId); getUserMessages(chat.id).then((data) => { if (data.length > 0) { - messageDispatch(setCurrentMessages(data)); - const lastMessage = data[data.length - 1]; - const selectMessageList = getSelectMessages(data, lastMessage.id); + messageDispatch(setMessages(data)); + const messages = formatMessages(data); + messageDispatch(setCurrentMessages(messages)); + const lastMessage = messages[messages.length - 1]; + const selectMessageList = getSelectMessages(messages, lastMessage.id); if (lastMessage.role !== 'assistant') { chatDispatch(setChatStatus(true)); selectMessageList.push(chatErrorMessage(lastMessage.id)); } - messageDispatch(setMessages(selectMessageList)); + messageDispatch(setSelectedMessages(selectMessageList)); messageDispatch(setLastMessageId(lastMessage.id)); clearUserModelConfig(); modelDispatch(setSelectedModel(selectModel)); } else { handleSelectModel(selectModel!); - messageDispatch(setMessages([])); + messageDispatch(setSelectedMessages([])); messageDispatch(setCurrentMessages([])); } }); @@ -260,7 +269,7 @@ const HomeContent = () => { const handleUpdateSelectMessage = (messageId: string) => { const selectMessageList = getSelectMessages(currentMessages, messageId); - messageDispatch(setMessages(selectMessageList)); + messageDispatch(setSelectedMessages(selectMessageList)); }; const hasModel = () => { @@ -278,18 +287,20 @@ const HomeContent = () => { getUserMessages(chat.id).then((data) => { if (data.length > 0) { - messageDispatch(setCurrentMessages(data)); - const lastMessage = data[data.length - 1]; - const selectMessageList = getSelectMessages(data, lastMessage.id); + messageDispatch(setMessages(data)); + const messages = formatMessages(data); + messageDispatch(setCurrentMessages(messages)); + const lastMessage = messages[messages.length - 1]; + const selectMessageList = getSelectMessages(messages, lastMessage.id); if (lastMessage.role !== 'assistant') { chatDispatch(setChatStatus(true)); selectMessageList.push(chatErrorMessage(lastMessage.id)); } - messageDispatch(setMessages(selectMessageList)); + messageDispatch(setSelectedMessages(selectMessageList)); messageDispatch(setLastMessageId(lastMessage.id)); } else { messageDispatch(setCurrentMessages([])); - messageDispatch(setMessages([])); + messageDispatch(setSelectedMessages([])); } const model = getChatModel(chatList, chat?.id, models) || @@ -331,13 +342,24 @@ const HomeContent = () => { chatDispatch(setChatStatus(false)); messageDispatch(setLastMessageId('')); - messageDispatch(setMessages([])); + messageDispatch(setSelectedMessages([])); messageDispatch(setCurrentMessages([])); modelDispatch(setSelectedModel(calcSelectModel(chats, models))); clearUserModelConfig(); }; + const handleStopChats = () => { + let p = [] as any[]; + stopIds.forEach((id) => { + p.push(stopChat(id)); + }); + Promise.all(p).then(() => { + chatDispatch(setChatStatus(false)); + chatDispatch(setStopIds([])); + }); + }; + const getChats = async ( params: GetChatsParams, modelList?: AdminModelDto[], @@ -382,7 +404,7 @@ const HomeContent = () => { } await getChats({ page: 1, pageSize: 50 }, modelList); - // chatDispatch(setIsChatsLoading(false)); + chatDispatch(setIsChatsLoading(false)); }); getUserPromptBrief().then((data) => { @@ -429,6 +451,7 @@ const HomeContent = () => { handleChatIsError, handleUpdateChatStatus, handleUpdateChats, + handleStopChats, handleCreateNewChat, handleSelectChat, diff --git a/src/FE/pages/home/_components/Sidebar/Sidebar.tsx b/src/FE/pages/home/_components/Sidebar/Sidebar.tsx index 4819ac2d..b1060dea 100644 --- a/src/FE/pages/home/_components/Sidebar/Sidebar.tsx +++ b/src/FE/pages/home/_components/Sidebar/Sidebar.tsx @@ -122,7 +122,9 @@ const Sidebar = ({ )}
- {items?.length > 0 &&
{itemComponent}
} + {items?.length > 0 && !isLoading && ( +
{itemComponent}
+ )} {IsNoDataRender()}
{footerComponent} diff --git a/src/FE/pages/home/_contexts/home.context.tsx b/src/FE/pages/home/_contexts/home.context.tsx index dacb0016..76c6afcf 100644 --- a/src/FE/pages/home/_contexts/home.context.tsx +++ b/src/FE/pages/home/_contexts/home.context.tsx @@ -33,6 +33,7 @@ export interface HomeInitialState { temperature: number | null; enableSearch: boolean | null; + messages: ChatMessage[]; selectMessages: ChatMessage[]; currentMessages: ChatMessage[]; selectMessageLastId: string; @@ -60,6 +61,7 @@ export const initialState: HomeInitialState = { temperature: null, enableSearch: null, + messages: [], selectMessages: [], selectMessageLastId: '', currentMessages: [], @@ -115,6 +117,7 @@ export interface HomeContextProps { params: HandleUpdateChatParams, ) => void; getChats: (params: GetChatsParams, models?: AdminModelDto[]) => void; + handleStopChats: () => void; } const HomeContext = createContext(undefined!); diff --git a/src/FE/pages/home/_reducers/chat.reducer.ts b/src/FE/pages/home/_reducers/chat.reducer.ts index 1c80b3af..f2dd4a29 100644 --- a/src/FE/pages/home/_reducers/chat.reducer.ts +++ b/src/FE/pages/home/_reducers/chat.reducer.ts @@ -12,6 +12,7 @@ export type SetChatPagingType = { export type SetMessageIsStreamingType = boolean; export type SetIsChatsLoadingType = boolean; +export type SetStopIdsType = string[]; interface ChatInitialState { chats: SetChatsType; @@ -20,6 +21,7 @@ interface ChatInitialState { chatsPaging: SetChatPagingType; messageIsStreaming: SetMessageIsStreamingType; isChatsLoading: SetIsChatsLoadingType; + stopIds: SetStopIdsType; } export const chatInitialState: ChatInitialState = { @@ -29,6 +31,7 @@ export const chatInitialState: ChatInitialState = { chatsPaging: { count: 0, page: 1, pageSize: 50 }, messageIsStreaming: false, isChatsLoading: false, + stopIds: [], }; export enum ChatActionTypes { @@ -39,6 +42,7 @@ export enum ChatActionTypes { SET_CHAT_PAGING = 'SET_CHAT_PAGING', SET_MESSAGE_IS_STREAMING = 'SET_MESSAGE_IS_STREAMING', SET_IS_CHATS_LOADING = 'SET_IS_CHATS_LOADING', + SET_STOP_IDS = 'SET_STOP_IDS', } export type ChatAction = @@ -54,6 +58,10 @@ export type ChatAction = | { type: ChatActionTypes.SET_IS_CHATS_LOADING; payload: SetIsChatsLoadingType; + } + | { + type: ChatActionTypes.SET_STOP_IDS; + payload: SetStopIdsType; }; export default function chatReducer( @@ -73,6 +81,8 @@ export default function chatReducer( return { ...state, messageIsStreaming: action.payload }; case ChatActionTypes.SET_IS_CHATS_LOADING: return { ...state, isChatsLoading: action.payload }; + case ChatActionTypes.SET_STOP_IDS: + return { ...state, stopIds: action.payload }; default: return state; } diff --git a/src/FE/pages/home/_reducers/message.reducer.ts b/src/FE/pages/home/_reducers/message.reducer.ts index 2dd7569c..edfd5085 100644 --- a/src/FE/pages/home/_reducers/message.reducer.ts +++ b/src/FE/pages/home/_reducers/message.reducer.ts @@ -1,18 +1,21 @@ import { ChatMessage } from '@/types/chatMessage'; export type SetMessagesType = ChatMessage[]; +export type SetSelectedMessagesType = ChatMessage[]; export type SetCurrentMessagesType = ChatMessage[]; export type SetLastMessageIdType = string; export type SetCurrentMessageIdType = string; interface MessageInitialState { - selectMessages: SetMessagesType; + messages: SetMessagesType; + selectMessages: SetSelectedMessagesType; currentMessages: SetCurrentMessagesType; selectMessageLastId: SetLastMessageIdType; currentChatMessageId: SetCurrentMessageIdType; } export const messageInitialState: MessageInitialState = { + messages: [], selectMessages: [], currentMessages: [], selectMessageLastId: '', @@ -21,13 +24,21 @@ export const messageInitialState: MessageInitialState = { export enum MessageActionTypes { SET_MESSAGES = 'SET_MESSAGES', + SET_SELECTED_MESSAGES = 'SET_SELECTED_MESSAGES', SET_CURRENT_MESSAGES = 'SET_CURRENT_MESSAGES', SET_LAST_MESSAGE_ID = 'SET_LAST_MESSAGE_ID', SET_CURRENT_MESSAGE_ID = 'SET_CURRENT_MESSAGE_ID', } export type MessageAction = - | { type: MessageActionTypes.SET_MESSAGES; payload: SetMessagesType } + | { + type: MessageActionTypes.SET_MESSAGES; + payload: SetMessagesType; + } + | { + type: MessageActionTypes.SET_SELECTED_MESSAGES; + payload: SetSelectedMessagesType; + } | { type: MessageActionTypes.SET_CURRENT_MESSAGES; payload: SetCurrentMessagesType; @@ -47,6 +58,8 @@ export default function messageReducer( ): MessageInitialState { switch (action.type) { case MessageActionTypes.SET_MESSAGES: + return { ...state, messages: action.payload }; + case MessageActionTypes.SET_SELECTED_MESSAGES: return { ...state, selectMessages: action.payload }; case MessageActionTypes.SET_CURRENT_MESSAGES: return { ...state, currentMessages: action.payload }; diff --git a/src/FE/types/chatMessage.ts b/src/FE/types/chatMessage.ts index 0ddc4475..3b92c80c 100644 --- a/src/FE/types/chatMessage.ts +++ b/src/FE/types/chatMessage.ts @@ -11,28 +11,28 @@ export enum SseResponseKind { // Discriminated unions for SseResponseLine interface SseResponseLineStopId { k: SseResponseKind.StopId; // Kind is StopId - r: string; // Result is a string + r: string; // Result is a string } interface SseResponseLineSegment { k: SseResponseKind.Segment; // Kind is Segment - r: string; // Result is a string + r: string; // Result is a string } interface SseResponseLineError { k: SseResponseKind.Error; // Kind is Error - r: string; // Result is a string + r: string; // Result is a string } interface SseResponseLineEnd { - k: SseResponseKind.End; // Kind is End - r: SseEndMessage; // Result is SseEndMessage + k: SseResponseKind.End; // Kind is End + r: SseEndMessage; // Result is SseEndMessage } // Definition of SseEndMessage interface SseEndMessage { - requestMessage: ChatMessage | null; // May be null - responseMessage: ChatMessage; // Required + requestMessage: ChatMessage | null; // May be null + responseMessage: ChatMessage; // Required } // Combined type for SseResponseLine @@ -45,8 +45,8 @@ export type SseResponseLine = export interface ChatMessage { id: string; parentId: string | null; - childrenIds: string[]; - assistantChildrenIds: string[]; + childrenIds?: string[]; + assistantChildrenIds?: string[]; role: Role; content: Content; modelName?: string; @@ -68,9 +68,9 @@ export interface MessageNode { assistantChildrenIds?: string[]; modelName?: string; role: Role; - inputTokens: number; - outputTokens: number; - reasoningTokens: number; - inputPrice: number; - outputPrice: number; + inputTokens?: number; + outputTokens?: number; + reasoningTokens?: number; + inputPrice?: number; + outputPrice?: number; } diff --git a/src/FE/types/clientApis.ts b/src/FE/types/clientApis.ts index 5c88e806..a2c50942 100644 --- a/src/FE/types/clientApis.ts +++ b/src/FE/types/clientApis.ts @@ -102,4 +102,4 @@ export interface GetUserApiKeyResult { updatedAt: string; lastUsedAt: string; modelCount: number; -} \ No newline at end of file +} diff --git a/src/FE/utils/message.ts b/src/FE/utils/message.ts index 9c228964..98a6fc0c 100644 --- a/src/FE/utils/message.ts +++ b/src/FE/utils/message.ts @@ -70,7 +70,7 @@ const findResponseMessageChildren = ( .map((node) => node.id); }; -export const calculateMessages = (nodes: MessageNode[]): MessageNode[] => { +export const formatMessages = (nodes: MessageNode[]): MessageNode[] => { return nodes.map((node) => ({ ...node, childrenIds: findUserMessageChildren(nodes, node.id).reverse(),