Skip to content

Commit

Permalink
feat: add optimistic update on new message (#1764)
Browse files Browse the repository at this point in the history
  • Loading branch information
mamadoudicko authored Nov 30, 2023
1 parent 35bd472 commit 13b174b
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 30 deletions.
3 changes: 1 addition & 2 deletions frontend/app/chat/[chatId]/hooks/useChat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,8 @@ export const useChat = () => {
prompt_id: currentPromptId ?? undefined,
};

await addStreamQuestion(currentChatId, chatQuestion);

callback?.();
await addStreamQuestion(currentChatId, chatQuestion);

if (shouldUpdateUrl) {
router.replace(`/chat/${currentChatId}`);
Expand Down
9 changes: 8 additions & 1 deletion frontend/app/chat/[chatId]/hooks/useHandleStream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ export const useHandleStream = () => {
const { updateStreamingHistory } = useChatContext();

const handleStream = async (
reader: ReadableStreamDefaultReader<Uint8Array>
reader: ReadableStreamDefaultReader<Uint8Array>,
onFirstChunk: () => void
): Promise<void> => {
const decoder = new TextDecoder("utf-8");
let isFirstChunk = true;

const handleStreamRecursively = async () => {
const { done, value } = await reader.read();
Expand All @@ -18,6 +20,11 @@ export const useHandleStream = () => {
return;
}

if (isFirstChunk) {
isFirstChunk = false;
onFirstChunk();
}

const dataStrings = decoder
.decode(value)
.trim()
Expand Down
16 changes: 13 additions & 3 deletions frontend/app/chat/[chatId]/hooks/useQuestion.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { useTranslation } from "react-i18next";

import { useChatContext } from "@/lib/context";
import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";
import { useFetch, useToast } from "@/lib/hooks";

import { useHandleStream } from "./useHandleStream";
import { ChatQuestion } from "../types";
import { generatePlaceHolderMessage } from "../utils/generatePlaceHolderMessage";

interface UseChatService {
addStreamQuestion: (
Expand All @@ -20,6 +22,7 @@ export const useQuestion = (): UseChatService => {
const { t } = useTranslation(["chat"]);
const { publish } = useToast();
const { handleStream } = useHandleStream();
const { removeMessage, updateStreamingHistory } = useChatContext();

const handleFetchError = async (response: Response) => {
if (response.status === 429) {
Expand All @@ -36,8 +39,6 @@ export const useQuestion = (): UseChatService => {
variant: "danger",
text: errorMessage.detail,
});

return;
};

const addStreamQuestion = async (
Expand All @@ -48,6 +49,13 @@ export const useQuestion = (): UseChatService => {
"Content-Type": "application/json",
Accept: "text/event-stream",
};

const placeHolderMessage = generatePlaceHolderMessage({
user_message: chatQuestion.question ?? "",
chat_id: chatId,
});
updateStreamingHistory(placeHolderMessage);

const body = JSON.stringify(chatQuestion);

try {
Expand All @@ -66,7 +74,9 @@ export const useQuestion = (): UseChatService => {
throw new Error(t("resposeBodyNull", { ns: "chat" }));
}

await handleStream(response.body.getReader());
await handleStream(response.body.getReader(), () =>
removeMessage(placeHolderMessage.message_id)
);
} catch (error) {
publish({
variant: "danger",
Expand Down
23 changes: 23 additions & 0 deletions frontend/app/chat/[chatId]/utils/generatePlaceHolderMessage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ChatMessage } from "../types";

type GeneratePlaceHolderMessageProps = {
user_message: string;
chat_id: string;
};

export const generatePlaceHolderMessage = ({
user_message,
chat_id,
}: GeneratePlaceHolderMessageProps): ChatMessage => {
const message_id = new Date().getTime().toString();
const message_time = new Date().toISOString();
const assistant = "";

return {
message_id,
message_time,
assistant,
chat_id,
user_message,
};
};
25 changes: 5 additions & 20 deletions frontend/lib/context/ChatProvider/ChatProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@ export const ChatProvider = ({
const [messages, setMessages] = useState<ChatMessage[]>([]);
const [notifications, setNotifications] = useState<Notification[]>([]);

const addToHistory = (message: ChatMessage) => {
setMessages((prevHistory) => [...prevHistory, message]);
};

const updateStreamingHistory = (streamedChat: ChatMessage): void => {
setMessages((prevHistory: ChatMessage[]) => {
const updatedHistory = prevHistory.find(
Expand All @@ -38,30 +34,19 @@ export const ChatProvider = ({
});
};

const updateHistory = (chat: ChatMessage): void => {
setMessages((prevHistory: ChatMessage[]) => {
const updatedHistory = prevHistory.find(
(item) => item.message_id === chat.message_id
)
? prevHistory.map((item: ChatMessage) =>
item.message_id === chat.message_id
? { ...item, assistant: chat.assistant }
: item
)
: [...prevHistory, chat];

return updatedHistory;
});
const removeMessage = (id: string): void => {
setMessages((prevHistory: ChatMessage[]) =>
prevHistory.filter((item) => item.message_id !== id)
);
};

return (
<ChatContext.Provider
value={{
messages,
setMessages,
addToHistory,
updateHistory,
updateStreamingHistory,
removeMessage,
notifications,
setNotifications,
}}
Expand Down
3 changes: 1 addition & 2 deletions frontend/lib/context/ChatProvider/mocks/ChatProviderMock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,10 @@ export const ChatProviderMock = ({
value={{
messages: [],
setMessages: () => void 0,
addToHistory: () => void 0,
updateHistory: () => void 0,
updateStreamingHistory: () => void 0,
notifications: [],
setNotifications: () => void 0,
removeMessage: () => void 0,
}}
>
{children}
Expand Down
3 changes: 1 addition & 2 deletions frontend/lib/context/ChatProvider/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@ export type ChatConfig = {
export type ChatContextProps = {
messages: ChatMessage[];
setMessages: (history: ChatMessage[]) => void;
addToHistory: (message: ChatMessage) => void;
updateHistory: (chat: ChatMessage) => void;
updateStreamingHistory: (streamedChat: ChatMessage) => void;
notifications: Notification[];
setNotifications: (notifications: Notification[]) => void;
removeMessage: (id: string) => void;
};

0 comments on commit 13b174b

Please sign in to comment.