Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified tools/server/public/index.html.gz
Binary file not shown.
3 changes: 3 additions & 0 deletions tools/server/webui/src/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring);
--breakpoint-3xl: 120rem; /* 1920px */
--breakpoint-4xl: 150rem; /* 2400px */
--breakpoint-5xl: 180rem; /* 2880px */
}

@layer base {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
ChatFormHelperText,
ChatFormTextarea
} from '$lib/components/app';
import { MAX_WIDTH_CLASSES, DEFAULT_MAX_WIDTH_CLASS } from '$lib/constants/width-classes';
import { INPUT_CLASSES } from '$lib/constants/input-classes';
import { config } from '$lib/stores/settings.svelte';
import { FileTypeCategory, MimeTypeApplication } from '$lib/enums/files';
Expand Down Expand Up @@ -62,6 +63,9 @@
let previousIsLoading = $state(isLoading);
let recordingSupported = $state(false);
let textareaRef: ChatFormTextarea | undefined = $state(undefined);
let maxWidthClass = $derived(
currentConfig.responsiveChatWidth ? MAX_WIDTH_CLASSES : DEFAULT_MAX_WIDTH_CLASS
);

function getAcceptStringForFileType(fileType: FileTypeCategory): string {
switch (fileType) {
Expand Down Expand Up @@ -230,7 +234,7 @@

<form
onsubmit={handleSubmit}
class="{INPUT_CLASSES} border-radius-bottom-none mx-auto max-w-[48rem] overflow-hidden rounded-3xl backdrop-blur-md {className}"
class="{INPUT_CLASSES} border-radius-bottom-none mx-auto {maxWidthClass} overflow-hidden rounded-3xl backdrop-blur-md {className}"
>
<ChatAttachmentsList
bind:uploadedFiles
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import { modelName as serverModelName } from '$lib/stores/server.svelte';
import { copyToClipboard } from '$lib/utils/copy';
import type { ApiChatCompletionToolCall } from '$lib/types/api';
import { MAX_WIDTH_CLASSES, DEFAULT_MAX_WIDTH_CLASS } from '$lib/constants/width-classes';

interface Props {
class?: string;
Expand Down Expand Up @@ -101,6 +102,10 @@
return serverModel;
});

let maxWidthClass = $derived(
config().responsiveChatWidth ? MAX_WIDTH_CLASSES : DEFAULT_MAX_WIDTH_CLASS
);

function handleCopyModel() {
const model = displayedModel();

Expand Down Expand Up @@ -174,7 +179,7 @@
{/if}

{#if message?.role === 'assistant' && isLoading() && !message?.content?.trim()}
<div class="mt-6 w-full max-w-[48rem]" in:fade>
<div class="mt-6 w-full {maxWidthClass}" in:fade>
<div class="processing-container">
<span class="processing-text">
{processingState.getProcessingMessage()}
Expand Down Expand Up @@ -220,7 +225,7 @@
</div>
{:else if message.role === 'assistant'}
{#if config().disableReasoningFormat}
<pre class="raw-output">{messageContent || ''}</pre>
<pre class="raw-output {maxWidthClass}">{messageContent || ''}</pre>
{:else}
<MarkdownContent content={messageContent || ''} />
{/if}
Expand Down Expand Up @@ -375,7 +380,6 @@

.raw-output {
width: 100%;
max-width: 48rem;
margin-top: 1.5rem;
padding: 1rem 1.25rem;
border-radius: 1rem;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
editAssistantMessage,
regenerateMessageWithBranching
} from '$lib/stores/chat.svelte';
import { config } from '$lib/stores/settings.svelte';
import { getMessageSiblings } from '$lib/utils/branching';
import { MAX_WIDTH_CLASSES, DEFAULT_MAX_WIDTH_CLASS } from '$lib/constants/width-classes';

interface Props {
class?: string;
Expand All @@ -21,6 +23,10 @@

let allConversationMessages = $state<DatabaseMessage[]>([]);

let maxWidthClass = $derived(
config().responsiveChatWidth ? MAX_WIDTH_CLASSES : DEFAULT_MAX_WIDTH_CLASS
);

function refreshAllMessages() {
const conversation = activeConversation();

Expand Down Expand Up @@ -103,7 +109,7 @@
<div class="flex h-full flex-col space-y-10 pt-16 md:pt-24 {className}" style="height: auto; ">
{#each displayMessages as { message, siblingInfo } (message.id)}
<ChatMessage
class="mx-auto w-full max-w-[48rem]"
class="mx-auto w-full {maxWidthClass}"
{message}
{siblingInfo}
onDelete={handleDeleteMessage}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@
import { slotsService } from '$lib/services/slots';
import { isLoading, activeMessages, activeConversation } from '$lib/stores/chat.svelte';
import { config } from '$lib/stores/settings.svelte';
import { MAX_WIDTH_CLASSES, DEFAULT_MAX_WIDTH_CLASS } from '$lib/constants/width-classes';

const processingState = useProcessingState();

let isCurrentConversationLoading = $derived(isLoading());
let processingDetails = $derived(processingState.getProcessingDetails());
let showSlotsInfo = $derived(isCurrentConversationLoading || config().keepStatsVisible);
let maxWidthClass = $derived(
config().responsiveChatWidth ? MAX_WIDTH_CLASSES : DEFAULT_MAX_WIDTH_CLASS
);

// Track loading state reactively by checking if conversation ID is in loading conversations array
$effect(() => {
Expand Down Expand Up @@ -77,7 +81,7 @@
</script>

<div class="chat-processing-info-container pointer-events-none" class:visible={showSlotsInfo}>
<div class="chat-processing-info-content">
<div class="chat-processing-info-content {maxWidthClass}">
{#each processingDetails as detail (detail)}
<span class="chat-processing-info-detail pointer-events-auto">{detail}</span>
{/each}
Expand Down Expand Up @@ -108,7 +112,6 @@
align-items: center;
gap: 1rem;
justify-content: center;
max-width: 48rem;
margin: 0 auto;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
ConfirmationDialog
} from '$lib/components/app';
import * as AlertDialog from '$lib/components/ui/alert-dialog';
import { config } from '$lib/stores/settings.svelte';
import { MAX_WIDTH_CLASSES, DEFAULT_MAX_WIDTH_CLASS } from '$lib/constants/width-classes';
import {
AUTO_SCROLL_AT_BOTTOM_THRESHOLD,
AUTO_SCROLL_INTERVAL,
Expand Down Expand Up @@ -85,6 +87,10 @@

let isCurrentConversationLoading = $derived(isLoading());

let maxWidthClass = $derived(
config().responsiveChatWidth ? MAX_WIDTH_CLASSES : DEFAULT_MAX_WIDTH_CLASS
);

async function handleDeleteConfirm() {
const conversation = activeConversation();
if (conversation) {
Expand Down Expand Up @@ -302,7 +308,7 @@
<ChatProcessingInfo />

{#if serverWarning()}
<ChatScreenWarning class="pointer-events-auto mx-auto max-w-[48rem] px-4" />
<ChatScreenWarning class="pointer-events-auto mx-auto {maxWidthClass} px-4" />
{/if}

<div class="conversation-chat-form pointer-events-auto rounded-t-3xl pb-4">
Expand Down Expand Up @@ -333,7 +339,7 @@
ondrop={handleDrop}
role="main"
>
<div class="w-full max-w-[48rem] px-4">
<div class="w-full {maxWidthClass} px-4">
<div class="mb-8 text-center" in:fade={{ duration: 300 }}>
<h1 class="mb-2 text-3xl font-semibold tracking-tight">llama.cpp</h1>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@
{ value: 'dark', label: 'Dark', icon: Moon }
]
},
{
key: 'responsiveChatWidth',
label: 'Responsive chat width',
type: 'checkbox'
},
{
key: 'showMessageStats',
label: 'Show message generation statistics',
Expand Down
3 changes: 3 additions & 0 deletions tools/server/webui/src/lib/constants/settings-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export const SETTING_CONFIG_DEFAULT: Record<string, string | number | boolean> =
showToolCalls: false,
disableReasoningFormat: false,
keepStatsVisible: false,
responsiveChatWidth: false,
showMessageStats: true,
askForTitleConfirmation: false,
pasteLongTextToFileLen: 2500,
Expand Down Expand Up @@ -86,6 +87,8 @@ export const SETTING_CONFIG_INFO: Record<string, string> = {
disableReasoningFormat:
'Show raw LLM output without backend parsing and frontend Markdown rendering to inspect streaming across different models.',
keepStatsVisible: 'Keep processing statistics visible after generation finishes.',
responsiveChatWidth:
'Enable responsive chat width that adapts to your screen size. When disabled, uses a fixed width optimized for readability.',
showMessageStats:
'Display generation statistics (tokens/second, token count, duration) below each assistant message.',
askForTitleConfirmation:
Expand Down
4 changes: 4 additions & 0 deletions tools/server/webui/src/lib/constants/width-classes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const MAX_WIDTH_CLASSES =
'max-w-[48rem] md:max-w-[60rem] xl:max-w-[70rem] 2xl:max-w-[80rem] 3xl:max-w-[90rem] 4xl:max-w-[100rem] 5xl:max-w-[150rem]';

export const DEFAULT_MAX_WIDTH_CLASS = 'max-w-[48rem]';