(null);
+ useEffect(() => {
+ if (msg.content=== null) {
+ messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
+ }
+ }, [msg.content]);
const timings = useMemo(
() =>
msg.timings
@@ -235,6 +241,7 @@ export default function ChatMessage({
)}
+
>
)}
diff --git a/examples/server/webui/src/components/ChatScreen.tsx b/examples/server/webui/src/components/ChatScreen.tsx
index ca8e29f0..28cc3d56 100644
--- a/examples/server/webui/src/components/ChatScreen.tsx
+++ b/examples/server/webui/src/components/ChatScreen.tsx
@@ -120,7 +120,7 @@ export default function ChatScreen() {
// reset to latest node when conversation changes
setCurrNodeId(-1);
// scroll to bottom when conversation changes
- scrollToBottom(false, 1);
+ // scrollToBottom(false, 1);
}, [currConvId]);
const onChunk: CallbackGeneratedChunk = (currLeafNodeId?: Message['id']) => {
@@ -140,8 +140,8 @@ export default function ChatScreen() {
return;
textarea.setValue('');
- scrollToBottom(false);
setCurrNodeId(-1);
+ scrollToBottom(false);
// get the last message node
const lastMsgNodeId = messages.at(-1)?.msg.id ?? null;
const successSendMsg=await sendMessage(
@@ -252,7 +252,7 @@ export default function ChatScreen() {
>
{
// copy the local config to prevent direct mutation
- const newConfig: typeof CONFIG_DEFAULT = JSON.parse(
+ const newConfig: typeof CONFIG_DEFAULT = {
+ ...CONFIG_DEFAULT,
+ ...JSON.parse(
JSON.stringify(localConfig)
- );
+ )};
// validate the config
for (const key in newConfig) {
+ if (!isValidKey(key)) {
+ console.log(`Unknown default type for key ${key}`);
+ continue;
+ }
const value = newConfig[key as SettKey];
const mustBeBoolean = isBoolean(CONFIG_DEFAULT[key as SettKey]);
const mustBeString = isString(CONFIG_DEFAULT[key as SettKey]);
@@ -591,7 +601,6 @@ export default function SettingDialog({
toast.error(`Unknown default type for key ${key}`);
}
}
- if (isDev) console.log('Saving config', newConfig);
saveConfig(newConfig);
onClose();
};
diff --git a/examples/server/webui/src/components/useChatScroll.tsx b/examples/server/webui/src/components/useChatScroll.tsx
index 25ea0223..5e955eb4 100644
--- a/examples/server/webui/src/components/useChatScroll.tsx
+++ b/examples/server/webui/src/components/useChatScroll.tsx
@@ -1,5 +1,7 @@
import React, { useEffect } from 'react';
-import { throttle } from '../utils/misc';
+//import { throttle } from '../utils/misc';
+
+let autoScrollPaused = false;
export const scrollToBottom = (requiresNearBottom: boolean, delay?: number) => {
const mainScrollElem = document.getElementById('main-scroll');
@@ -9,26 +11,50 @@ export const scrollToBottom = (requiresNearBottom: boolean, delay?: number) => {
mainScrollElem.scrollTop -
mainScrollElem.clientHeight;
if (!requiresNearBottom || spaceToBottom < 100) {
- setTimeout(
- () => mainScrollElem.scrollTo({ top: mainScrollElem.scrollHeight }),
- delay ?? 80
- );
+ if (!autoScrollPaused) {
+ setTimeout(
+ () => mainScrollElem.scrollTo({
+ top: mainScrollElem.scrollHeight,
+ behavior: 'smooth'
+ }),
+ delay ?? 80
+ );
+ }
}
};
-const scrollToBottomThrottled = throttle(scrollToBottom, 80);
+//const scrollToBottomThrottled = throttle(scrollToBottom, 80);
export function useChatScroll(msgListRef: React.RefObject) {
useEffect(() => {
if (!msgListRef.current) return;
const resizeObserver = new ResizeObserver((_) => {
- scrollToBottomThrottled(true, 10);
+ // Remove throttle but keep the near-bottom logic
+ scrollToBottom(true, 10);
});
+ const mainScrollElem = document.getElementById('main-scroll');
+ if (!mainScrollElem) return;
+
+ // Initialize handleWheel event listener to detect user scrolling actions
+ const handleWheel = (event: WheelEvent) => {
+ if (event.deltaY < 0) {
+ // User scrolled up
+ autoScrollPaused = true;
+ } else {
+ // User scrolled down
+ autoScrollPaused = false;
+ }
+ };
+ // Add event listener for wheel events
+ mainScrollElem.addEventListener('wheel', handleWheel);
+
resizeObserver.observe(msgListRef.current);
+ // Observe the msgListRef element for size changes
return () => {
resizeObserver.disconnect();
+ mainScrollElem.removeEventListener('wheel', handleWheel);
};
}, [msgListRef]);
-}
+}
\ No newline at end of file
diff --git a/examples/server/webui/src/utils/app.context.tsx b/examples/server/webui/src/utils/app.context.tsx
index a1545de0..e2b7d98b 100644
--- a/examples/server/webui/src/utils/app.context.tsx
+++ b/examples/server/webui/src/utils/app.context.tsx
@@ -133,13 +133,17 @@ export const AppContextProvider = ({
const setPending = (convId: string, pendingMsg: PendingMessage | null) => {
// if pendingMsg is null, remove the key from the object
if (!pendingMsg) {
- setPendingMessages((prev) => {
- const newState = { ...prev };
- delete newState[convId];
- return newState;
- });
+ setTimeout(() => {
+ setPendingMessages((prev) => {
+ const newState = { ...prev };
+ delete newState[convId];
+ return newState;
+ });
+ }, 100); // Adjust delay as needed
} else {
- setPendingMessages((prev) => ({ ...prev, [convId]: pendingMsg }));
+ setTimeout(() => {
+ setPendingMessages((prev) => ({ ...prev, [convId]: pendingMsg }));
+ }, 100);
}
};
@@ -157,7 +161,6 @@ export const AppContextProvider = ({
////////////////////////////////////////////////////////////////////////
// public functions
-
const isGenerating = (convId: string) => !!pendingMessages[convId];
const generateMessage = async (
@@ -378,7 +381,7 @@ export const AppContextProvider = ({
const currMsgId = now;
let model_name:string='';
- await getServerProps(BASE_URL)
+ await getServerProps(BASE_URL, config.apiKey)
.then((props) => {
console.debug('Server props:', props);
model_name = props.model_name;
@@ -433,7 +436,7 @@ export const AppContextProvider = ({
const currMsgId = now;
let model_name:string='';
- await getServerProps(BASE_URL)
+ await getServerProps(BASE_URL, config.apiKey)
.then((props) => {
console.debug('Server props:', props);
model_name = props.model_name;
diff --git a/examples/server/webui/src/utils/storage.ts b/examples/server/webui/src/utils/storage.ts
index c710ecc0..2550d9ab 100644
--- a/examples/server/webui/src/utils/storage.ts
+++ b/examples/server/webui/src/utils/storage.ts
@@ -125,9 +125,10 @@ const StorageUtils = {
async createConversation(name: string): Promise {
const now = Date.now();
const msgId = now;
+ const config = StorageUtils.getConfig();
let model_name:string = '';
//window.alert(BASE_URL);
- await getServerProps(BASE_URL)
+ await getServerProps(BASE_URL, config.apiKey)
.then((props) => {
console.debug('Server props:', props);
model_name = props.model_name;