Skip to content

Commit

Permalink
Implement auto scroll when stream message (#2839)
Browse files Browse the repository at this point in the history
After trying a bunch of methods I found this is the easiest way to do
it. Other approaches are way more complicated.
Also found this lib https://github.com/compulim/react-scroll-to-bottom
OAI also uses it, but it doesn't support SSR and unmaintained for years.
This solution is not really reliable, if you paste a prompt with many
lines (4 or above), it doesn't work. It would be if someone can patch
the `react-scroll-to-bottom` to support SSR.
  • Loading branch information
notmd authored Apr 27, 2023
1 parent af8f08b commit f1da07a
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 5 deletions.
5 changes: 2 additions & 3 deletions inference/worker/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,8 @@ def text_to_events(text: str, seed: int | None = None, pause: float = 0.0):


def lorem_events(seed):
sentence = lorem.sentence()
time.sleep(1)
yield from text_to_events(sentence, seed=seed, pause=0.5)
sentence = lorem.paragraph()
yield from text_to_events(sentence, seed=seed, pause=0.2)


ws_lock = threading.Lock()
Expand Down
47 changes: 45 additions & 2 deletions website/src/components/Chat/ChatConversation.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { Box, useBoolean, useToast } from "@chakra-ui/react";
import { memo, useCallback, useRef, useState } from "react";
import { KeyboardEvent, memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
import { UseFormGetValues } from "react-hook-form";
import SimpleBar from "simplebar-react";
import { useMessageVote } from "src/hooks/chat/useMessageVote";
Expand Down Expand Up @@ -201,6 +201,8 @@ export const ChatConversation = memo(function ChatConversation({ chatId, getConf
[createAndFetchAssistantMessage, isSending, setIsSending]
);

const { messagesEndRef, scrollableNodeProps } = useAutoScroll(messages, streamedResponse);

return (
<Box
pt="4"
Expand All @@ -219,7 +221,8 @@ export const ChatConversation = memo(function ChatConversation({ chatId, getConf
}}
>
<SimpleBar
style={{ padding: "4px 0", maxHeight: "100%", height: "100%", minHeight: "0" }}
scrollableNodeProps={scrollableNodeProps}
style={{ maxHeight: "100%", height: "100%", minHeight: "0" }}
classNames={{
contentEl: "space-y-4 mx-4 flex flex-col overflow-y-auto items-center",
}}
Expand All @@ -233,9 +236,49 @@ export const ChatConversation = memo(function ChatConversation({ chatId, getConf
onEditPromtp={handleEditPrompt}
></ChatConversationTree>
{isSending && streamedResponse && <PendingMessageEntry isAssistant content={streamedResponse} />}
<div ref={messagesEndRef} style={{ height: 0 }}></div>
</SimpleBar>
<ChatForm ref={inputRef} isSending={isSending} onSubmit={sendPrompterMessage} queueInfo={queueInfo}></ChatForm>
<ChatWarning />
</Box>
);
});

const useAutoScroll = (messages: InferenceMessage[], streamedResponse: string) => {
const enableAutoScroll = useRef(true);
const messagesEndRef = useRef<HTMLDivElement>(null);
const chatContainerRef = useRef<HTMLDivElement>(null);
const handleOnScroll = useCallback(() => {
const container = chatContainerRef.current;
if (!container) {
return;
}

const isEnable = Math.abs(container.scrollHeight - container.scrollTop - container.clientHeight) < 10;
enableAutoScroll.current = isEnable;
}, []);

useEffect(() => {
if (!enableAutoScroll.current) {
return;
}

messagesEndRef.current.scrollIntoView({ behavior: "smooth" });
}, [messages, streamedResponse]);

const scrollableNodeProps = useMemo(
() => ({
ref: chatContainerRef,
onWheel: handleOnScroll,
onKeyDown: (e: KeyboardEvent) => {
if (e.key === "ArrowUp" || e.key === "ArrowDown") {
handleOnScroll();
}
},
onTouchMove: handleOnScroll,
}),
[handleOnScroll]
);

return { messagesEndRef, scrollableNodeProps };
};

0 comments on commit f1da07a

Please sign in to comment.