webui: minor settings reorganization and add disable autoscroll option (#17452)
* webui: added a dedicated 'Display' settings section that groups visualization options * webui: added a Display setting to toggle automatic chat scrolling * chore: update webui build output
This commit is contained in:
parent
96ac5a2329
commit
0c7220db56
Binary file not shown.
|
|
@ -29,6 +29,7 @@
|
||||||
sendMessage,
|
sendMessage,
|
||||||
stopGeneration
|
stopGeneration
|
||||||
} from '$lib/stores/chat.svelte';
|
} from '$lib/stores/chat.svelte';
|
||||||
|
import { config } from '$lib/stores/settings.svelte';
|
||||||
import {
|
import {
|
||||||
supportsVision,
|
supportsVision,
|
||||||
supportsAudio,
|
supportsAudio,
|
||||||
|
|
@ -47,6 +48,7 @@
|
||||||
|
|
||||||
let { showCenteredEmpty = false } = $props();
|
let { showCenteredEmpty = false } = $props();
|
||||||
|
|
||||||
|
let disableAutoScroll = $derived(Boolean(config().disableAutoScroll));
|
||||||
let autoScrollEnabled = $state(true);
|
let autoScrollEnabled = $state(true);
|
||||||
let chatScrollContainer: HTMLDivElement | undefined = $state();
|
let chatScrollContainer: HTMLDivElement | undefined = $state();
|
||||||
let dragCounter = $state(0);
|
let dragCounter = $state(0);
|
||||||
|
|
@ -149,7 +151,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleScroll() {
|
function handleScroll() {
|
||||||
if (!chatScrollContainer) return;
|
if (disableAutoScroll || !chatScrollContainer) return;
|
||||||
|
|
||||||
const { scrollTop, scrollHeight, clientHeight } = chatScrollContainer;
|
const { scrollTop, scrollHeight, clientHeight } = chatScrollContainer;
|
||||||
const distanceFromBottom = scrollHeight - scrollTop - clientHeight;
|
const distanceFromBottom = scrollHeight - scrollTop - clientHeight;
|
||||||
|
|
@ -194,8 +196,10 @@
|
||||||
const extras = result?.extras;
|
const extras = result?.extras;
|
||||||
|
|
||||||
// Enable autoscroll for user-initiated message sending
|
// Enable autoscroll for user-initiated message sending
|
||||||
|
if (!disableAutoScroll) {
|
||||||
userScrolledUp = false;
|
userScrolledUp = false;
|
||||||
autoScrollEnabled = true;
|
autoScrollEnabled = true;
|
||||||
|
}
|
||||||
await sendMessage(message, extras);
|
await sendMessage(message, extras);
|
||||||
scrollChatToBottom();
|
scrollChatToBottom();
|
||||||
|
|
||||||
|
|
@ -241,6 +245,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function scrollChatToBottom(behavior: ScrollBehavior = 'smooth') {
|
function scrollChatToBottom(behavior: ScrollBehavior = 'smooth') {
|
||||||
|
if (disableAutoScroll) return;
|
||||||
|
|
||||||
chatScrollContainer?.scrollTo({
|
chatScrollContainer?.scrollTo({
|
||||||
top: chatScrollContainer?.scrollHeight,
|
top: chatScrollContainer?.scrollHeight,
|
||||||
behavior
|
behavior
|
||||||
|
|
@ -248,14 +254,27 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
afterNavigate(() => {
|
afterNavigate(() => {
|
||||||
|
if (!disableAutoScroll) {
|
||||||
setTimeout(() => scrollChatToBottom('instant'), INITIAL_SCROLL_DELAY);
|
setTimeout(() => scrollChatToBottom('instant'), INITIAL_SCROLL_DELAY);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
|
if (!disableAutoScroll) {
|
||||||
setTimeout(() => scrollChatToBottom('instant'), INITIAL_SCROLL_DELAY);
|
setTimeout(() => scrollChatToBottom('instant'), INITIAL_SCROLL_DELAY);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
|
if (disableAutoScroll) {
|
||||||
|
autoScrollEnabled = false;
|
||||||
|
if (scrollInterval) {
|
||||||
|
clearInterval(scrollInterval);
|
||||||
|
scrollInterval = undefined;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (isCurrentConversationLoading && autoScrollEnabled) {
|
if (isCurrentConversationLoading && autoScrollEnabled) {
|
||||||
scrollInterval = setInterval(scrollChatToBottom, AUTO_SCROLL_INTERVAL);
|
scrollInterval = setInterval(scrollChatToBottom, AUTO_SCROLL_INTERVAL);
|
||||||
} else if (scrollInterval) {
|
} else if (scrollInterval) {
|
||||||
|
|
@ -289,9 +308,11 @@
|
||||||
class="mb-16 md:mb-24"
|
class="mb-16 md:mb-24"
|
||||||
messages={activeMessages()}
|
messages={activeMessages()}
|
||||||
onUserAction={() => {
|
onUserAction={() => {
|
||||||
|
if (!disableAutoScroll) {
|
||||||
userScrolledUp = false;
|
userScrolledUp = false;
|
||||||
autoScrollEnabled = true;
|
autoScrollEnabled = true;
|
||||||
scrollChatToBottom();
|
scrollChatToBottom();
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
Settings,
|
Settings,
|
||||||
Funnel,
|
Funnel,
|
||||||
AlertTriangle,
|
AlertTriangle,
|
||||||
Brain,
|
|
||||||
Code,
|
Code,
|
||||||
Monitor,
|
Monitor,
|
||||||
Sun,
|
Sun,
|
||||||
|
|
@ -58,6 +57,33 @@
|
||||||
label: 'Paste long text to file length',
|
label: 'Paste long text to file length',
|
||||||
type: 'input'
|
type: 'input'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'enableContinueGeneration',
|
||||||
|
label: 'Enable "Continue" button',
|
||||||
|
type: 'checkbox',
|
||||||
|
isExperimental: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'pdfAsImage',
|
||||||
|
label: 'Parse PDF as image',
|
||||||
|
type: 'checkbox'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'askForTitleConfirmation',
|
||||||
|
label: 'Ask for confirmation before changing conversation title',
|
||||||
|
type: 'checkbox'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Display',
|
||||||
|
icon: Monitor,
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
key: 'showThoughtInProgress',
|
||||||
|
label: 'Show thought in progress',
|
||||||
|
type: 'checkbox'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'showMessageStats',
|
key: 'showMessageStats',
|
||||||
label: 'Show message generation statistics',
|
label: 'Show message generation statistics',
|
||||||
|
|
@ -79,25 +105,14 @@
|
||||||
type: 'checkbox'
|
type: 'checkbox'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'enableContinueGeneration',
|
key: 'disableAutoScroll',
|
||||||
label: 'Enable "Continue" button',
|
label: 'Disable automatic scroll',
|
||||||
type: 'checkbox',
|
|
||||||
isExperimental: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'pdfAsImage',
|
|
||||||
label: 'Parse PDF as image',
|
|
||||||
type: 'checkbox'
|
type: 'checkbox'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'renderUserContentAsMarkdown',
|
key: 'renderUserContentAsMarkdown',
|
||||||
label: 'Render user content as Markdown',
|
label: 'Render user content as Markdown',
|
||||||
type: 'checkbox'
|
type: 'checkbox'
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'askForTitleConfirmation',
|
|
||||||
label: 'Ask for confirmation before changing conversation title',
|
|
||||||
type: 'checkbox'
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
@ -208,17 +223,6 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
title: 'Reasoning',
|
|
||||||
icon: Brain,
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
key: 'showThoughtInProgress',
|
|
||||||
label: 'Show thought in progress',
|
|
||||||
type: 'checkbox'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: 'Import/Export',
|
title: 'Import/Export',
|
||||||
icon: Database,
|
icon: Database,
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ export const SETTING_CONFIG_DEFAULT: Record<string, string | number | boolean> =
|
||||||
pasteLongTextToFileLen: 2500,
|
pasteLongTextToFileLen: 2500,
|
||||||
pdfAsImage: false,
|
pdfAsImage: false,
|
||||||
showModelInfo: false,
|
showModelInfo: false,
|
||||||
|
disableAutoScroll: false,
|
||||||
renderUserContentAsMarkdown: false,
|
renderUserContentAsMarkdown: false,
|
||||||
modelSelectorEnabled: false,
|
modelSelectorEnabled: false,
|
||||||
// make sure these default values are in sync with `common.h`
|
// make sure these default values are in sync with `common.h`
|
||||||
|
|
@ -93,6 +94,8 @@ export const SETTING_CONFIG_INFO: Record<string, string> = {
|
||||||
'Ask for confirmation before automatically changing conversation title when editing the first message.',
|
'Ask for confirmation before automatically changing conversation title when editing the first message.',
|
||||||
pdfAsImage: 'Parse PDF as image instead of text (requires vision-capable model).',
|
pdfAsImage: 'Parse PDF as image instead of text (requires vision-capable model).',
|
||||||
showModelInfo: 'Display the model name used to generate each message below the message content.',
|
showModelInfo: 'Display the model name used to generate each message below the message content.',
|
||||||
|
disableAutoScroll:
|
||||||
|
'Disable automatic scrolling while messages stream so you can control the viewport position manually.',
|
||||||
renderUserContentAsMarkdown: 'Render user messages using markdown formatting in the chat.',
|
renderUserContentAsMarkdown: 'Render user messages using markdown formatting in the chat.',
|
||||||
modelSelectorEnabled:
|
modelSelectorEnabled:
|
||||||
'Enable the model selector in the chat input to choose the inference model. Sends the associated model field in API requests.',
|
'Enable the model selector in the chat input to choose the inference model. Sends the associated model field in API requests.',
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue