mirror of
https://github.com/Mintplex-Labs/anything-llm.git
synced 2024-11-19 04:30:10 +01:00
Make streaming behavior more natural (#2336)
* fix scrolling behavior + add cursor to streaming chats * lint * linting --------- Co-authored-by: timothycarambat <rambat1010@gmail.com>
This commit is contained in:
parent
12b8af4654
commit
d75fee0c07
@ -20,13 +20,16 @@ export default function ChatHistory({
|
||||
regenerateAssistantMessage,
|
||||
hasAttachments = false,
|
||||
}) {
|
||||
const lastScrollTopRef = useRef(0);
|
||||
const { user } = useUser();
|
||||
const { threadSlug = null } = useParams();
|
||||
const { showing, showModal, hideModal } = useManageWorkspaceModal();
|
||||
const [isAtBottom, setIsAtBottom] = useState(true);
|
||||
const chatHistoryRef = useRef(null);
|
||||
const [textSize, setTextSize] = useState("normal");
|
||||
const [isUserScrolling, setIsUserScrolling] = useState(false);
|
||||
const showScrollbar = Appearance.getSettings()?.showScrollbar || false;
|
||||
const isStreaming = history[history.length - 1]?.animate;
|
||||
|
||||
const getTextSizeClass = (size) => {
|
||||
switch (size) {
|
||||
@ -58,35 +61,44 @@ export default function ChatHistory({
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (isAtBottom) scrollToBottom();
|
||||
}, [history]);
|
||||
if (!isUserScrolling && (isAtBottom || isStreaming)) {
|
||||
scrollToBottom(false); // Use instant scroll for auto-scrolling
|
||||
}
|
||||
}, [history, isAtBottom, isStreaming, isUserScrolling]);
|
||||
|
||||
const handleScroll = (e) => {
|
||||
const { scrollTop, scrollHeight, clientHeight } = e.target;
|
||||
const isBottom = scrollHeight - scrollTop === clientHeight;
|
||||
|
||||
// Detect if this is a user-initiated scroll
|
||||
if (Math.abs(scrollTop - lastScrollTopRef.current) > 10) {
|
||||
setIsUserScrolling(!isBottom);
|
||||
}
|
||||
|
||||
const handleScroll = () => {
|
||||
const diff =
|
||||
chatHistoryRef.current.scrollHeight -
|
||||
chatHistoryRef.current.scrollTop -
|
||||
chatHistoryRef.current.clientHeight;
|
||||
// Fuzzy margin for what qualifies as "bottom". Stronger than straight comparison since that may change over time.
|
||||
const isBottom = diff <= 10;
|
||||
setIsAtBottom(isBottom);
|
||||
lastScrollTopRef.current = scrollTop;
|
||||
};
|
||||
|
||||
const debouncedScroll = debounce(handleScroll, 100);
|
||||
|
||||
useEffect(() => {
|
||||
function watchScrollEvent() {
|
||||
if (!chatHistoryRef.current) return null;
|
||||
const chatHistoryElement = chatHistoryRef.current;
|
||||
if (!chatHistoryElement) return null;
|
||||
const chatHistoryElement = chatHistoryRef.current;
|
||||
if (chatHistoryElement) {
|
||||
chatHistoryElement.addEventListener("scroll", debouncedScroll);
|
||||
return () =>
|
||||
chatHistoryElement.removeEventListener("scroll", debouncedScroll);
|
||||
}
|
||||
watchScrollEvent();
|
||||
}, []);
|
||||
|
||||
const scrollToBottom = () => {
|
||||
const scrollToBottom = (smooth = false) => {
|
||||
if (chatHistoryRef.current) {
|
||||
chatHistoryRef.current.scrollTo({
|
||||
top: chatHistoryRef.current.scrollHeight,
|
||||
behavior: "smooth",
|
||||
|
||||
// Smooth is on when user clicks the button but disabled during auto scroll
|
||||
// We must disable this during auto scroll because it causes issues with
|
||||
// detecting when we are at the bottom of the chat.
|
||||
...(smooth ? { behavior: "smooth" } : {}),
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -197,6 +209,7 @@ export default function ChatHistory({
|
||||
}`}
|
||||
id="chat-history"
|
||||
ref={chatHistoryRef}
|
||||
onScroll={handleScroll}
|
||||
>
|
||||
{history.map((props, index) => {
|
||||
const isLastBotReply =
|
||||
@ -251,12 +264,14 @@ export default function ChatHistory({
|
||||
{!isAtBottom && (
|
||||
<div className="fixed bottom-40 right-10 md:right-20 z-50 cursor-pointer animate-pulse">
|
||||
<div className="flex flex-col items-center">
|
||||
<div className="p-1 rounded-full border border-white/10 bg-white/10 hover:bg-white/20 hover:text-white">
|
||||
<ArrowDown
|
||||
weight="bold"
|
||||
className="text-white/60 w-5 h-5"
|
||||
onClick={scrollToBottom}
|
||||
/>
|
||||
<div
|
||||
className="p-1 rounded-full border border-white/10 bg-white/10 hover:bg-white/20 hover:text-white"
|
||||
onClick={() => {
|
||||
scrollToBottom(true);
|
||||
setIsUserScrolling(false);
|
||||
}}
|
||||
>
|
||||
<ArrowDown weight="bold" className="text-white/60 w-5 h-5" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user