mirror of
https://github.com/ggml-org/llama.cpp.git
synced 2026-10-01 02:17:42 -05:00
ui : manage backends in their own dialog
Assisted-by: pi:llama.cpp/DeepSeek-V4.1-Flash
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
<script lang="ts">
|
||||
import { SettingsBackends } from '$lib/components/app/backends';
|
||||
import { Logo } from '$lib/components/app/misc';
|
||||
import * as Dialog from '$lib/components/ui/dialog';
|
||||
|
||||
interface Props {
|
||||
open?: boolean;
|
||||
onOpenChange?: (open: boolean) => void;
|
||||
}
|
||||
|
||||
let { onOpenChange, open = $bindable(false) }: Props = $props();
|
||||
|
||||
function handleOpenChange(value: boolean) {
|
||||
open = value;
|
||||
onOpenChange?.(value);
|
||||
}
|
||||
</script>
|
||||
|
||||
<Dialog.Root onOpenChange={handleOpenChange} {open}>
|
||||
<Dialog.Content class="md:max-h-[80vh]! md:w-[calc(100vw-4rem)]! md:max-w-164! flex flex-col">
|
||||
<Dialog.Header>
|
||||
<Dialog.Title class="flex items-center gap-2">
|
||||
<Logo class="h-5 w-5" style="--size: 1.25rem" />
|
||||
|
||||
<span>Backends</span>
|
||||
</Dialog.Title>
|
||||
|
||||
<Dialog.Description>
|
||||
Endpoints this UI can talk to. The built-in backend is the llama.cpp server serving it.
|
||||
</Dialog.Description>
|
||||
</Dialog.Header>
|
||||
|
||||
<SettingsBackends class="mt-4 overflow-y-auto" />
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
@@ -106,6 +106,7 @@ export { default as DialogExportSettings } from './DialogExportSettings.svelte';
|
||||
* />
|
||||
* ```
|
||||
*/
|
||||
export { default as DialogBackends } from './DialogBackends.svelte';
|
||||
export { default as DialogConfirmation } from './DialogConfirmation.svelte';
|
||||
|
||||
/**
|
||||
|
||||
@@ -244,7 +244,7 @@
|
||||
>
|
||||
<MODEL_SELECTOR_ICON class="h-3.5 w-3.5 shrink-0" />
|
||||
|
||||
<span class="flex min-w-0 items-center gap-1">
|
||||
<span class="flex min-w-0 items-center gap-0.5">
|
||||
{#if selectedOption}
|
||||
<ModelId
|
||||
class="min-w-0 overflow-hidden"
|
||||
@@ -364,16 +364,17 @@
|
||||
</div>
|
||||
|
||||
{#snippet footer()}
|
||||
<!-- Sticky actions footer: reasoning effort panel.
|
||||
Sticks to the bottom of the content scrollport. -->
|
||||
<!-- Sticky actions footer: backends, then the reasoning effort
|
||||
panel. Sticks to the bottom of the content scrollport. -->
|
||||
|
||||
<ModelsSelectorReasoningPanel inMenu />
|
||||
|
||||
<div
|
||||
class="px-1.5"
|
||||
class="flex flex-col px-1.5"
|
||||
onfocusin={clearHighlight}
|
||||
onmouseenter={clearHighlight}
|
||||
role="none"
|
||||
>
|
||||
<ModelsSelectorReasoningPanel inMenu />
|
||||
</div>
|
||||
></div>
|
||||
{/snippet}
|
||||
</DropdownMenuSearchable>
|
||||
</DropdownMenu.Content>
|
||||
|
||||
@@ -204,7 +204,7 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="px-2 pb-1">
|
||||
<div class="flex flex-col px-2 pb-1">
|
||||
<ModelsSelectorReasoningPanel />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import { page } from '$app/state';
|
||||
import {
|
||||
ActionIcon,
|
||||
DialogBackends,
|
||||
DialogConversationRename,
|
||||
DialogModelsDiscover,
|
||||
DialogSettingsChat,
|
||||
@@ -94,6 +95,7 @@
|
||||
|
||||
let renameDialogOpen = $state(false);
|
||||
let settingsDialogOpen = $state(false);
|
||||
let backendsDialogOpen = $state(false);
|
||||
let modelsDiscoverOpen = $state(false);
|
||||
let renameTargetConversationId = $state<string | null>(null);
|
||||
let renameDraft = $state('');
|
||||
@@ -391,6 +393,7 @@
|
||||
bind:searchQuery
|
||||
class="px-2"
|
||||
isExpandedMode={innerWidth > 768 ? uiStore.isSidebarExpanded : true}
|
||||
onBackendsClick={() => (backendsDialogOpen = true)}
|
||||
onDiscoverModelsClick={() => (modelsDiscoverOpen = true)}
|
||||
onNewChat={() => {
|
||||
if (deviceStore.isMobile) {
|
||||
@@ -455,6 +458,8 @@
|
||||
|
||||
<DialogSettingsChat bind:open={settingsDialogOpen} />
|
||||
|
||||
<DialogBackends bind:open={backendsDialogOpen} />
|
||||
|
||||
<DialogModelsDiscover bind:open={modelsDiscoverOpen} />
|
||||
|
||||
<style>
|
||||
|
||||
+30
-24
@@ -9,6 +9,7 @@
|
||||
ICON_STRIP_TRANSITION_DELAY_MULTIPLIER,
|
||||
ICON_STRIP_TRANSITION_DURATION,
|
||||
ROUTES,
|
||||
SETTINGS_KEYS,
|
||||
SIDEBAR_ACTIONS_ITEMS
|
||||
} from '$lib/constants';
|
||||
import { SidebarAction, TooltipSide } from '$lib/enums';
|
||||
@@ -25,8 +26,9 @@
|
||||
searchQuery: string;
|
||||
onSearchDeactivated?: () => void;
|
||||
onSearchClick?: () => void;
|
||||
onNewChat?: () => void;
|
||||
onBackendsClick?: () => void;
|
||||
onDiscoverModelsClick?: () => void;
|
||||
onNewChat?: () => void;
|
||||
onSettingsClick?: () => void;
|
||||
}
|
||||
|
||||
@@ -34,6 +36,7 @@
|
||||
class: className,
|
||||
isExpandedMode = false,
|
||||
isSearchModeActive = $bindable(false),
|
||||
onBackendsClick,
|
||||
onDiscoverModelsClick,
|
||||
onNewChat,
|
||||
onSearchClick,
|
||||
@@ -48,10 +51,9 @@
|
||||
|
||||
const isOnMobile = $derived(deviceStore.isMobile);
|
||||
|
||||
// Discover models is opt-in (General settings) and needs the router's
|
||||
// download endpoints; hide it when either gate is closed
|
||||
// discovery needs the local router's download endpoints
|
||||
const actionsItems = $derived(
|
||||
serverStore.localIsRouter && settingsStore.config.enableDiscoverModels
|
||||
serverStore.localIsRouter && settingsStore.config[SETTINGS_KEYS.ENABLE_DISCOVER_MODELS] === true
|
||||
? SIDEBAR_ACTIONS_ITEMS
|
||||
: SIDEBAR_ACTIONS_ITEMS.filter((item) => item.action !== SidebarAction.DISCOVER_MODELS)
|
||||
);
|
||||
@@ -129,16 +131,18 @@
|
||||
}
|
||||
: item.action === SidebarAction.DISCOVER_MODELS
|
||||
? () => onDiscoverModelsClick?.()
|
||||
: item.action === SidebarAction.SETTINGS
|
||||
? () => onSettingsClick?.()
|
||||
: item.route
|
||||
? () => {
|
||||
onNewChat?.();
|
||||
goto(item.route!);
|
||||
}
|
||||
: isSearchOnMobile
|
||||
? undefined
|
||||
: onSearchClick}
|
||||
: item.action === SidebarAction.BACKENDS
|
||||
? () => onBackendsClick?.()
|
||||
: item.action === SidebarAction.SETTINGS
|
||||
? () => onSettingsClick?.()
|
||||
: item.route
|
||||
? () => {
|
||||
onNewChat?.();
|
||||
goto(item.route!);
|
||||
}
|
||||
: isSearchOnMobile
|
||||
? undefined
|
||||
: onSearchClick}
|
||||
{@const itemTransition = {
|
||||
delay: !initialized ? i * ICON_STRIP_TRANSITION_DELAY_MULTIPLIER : 0,
|
||||
duration: ICON_STRIP_TRANSITION_DURATION,
|
||||
@@ -187,16 +191,18 @@
|
||||
}
|
||||
: item.action === SidebarAction.DISCOVER_MODELS
|
||||
? () => onDiscoverModelsClick?.()
|
||||
: item.action === SidebarAction.SETTINGS
|
||||
? () => onSettingsClick?.()
|
||||
: item.route
|
||||
? () => {
|
||||
onNewChat?.();
|
||||
goto(item.route!);
|
||||
}
|
||||
: isSearchOnMobile
|
||||
? undefined
|
||||
: onSearchClick}
|
||||
: item.action === SidebarAction.BACKENDS
|
||||
? () => onBackendsClick?.()
|
||||
: item.action === SidebarAction.SETTINGS
|
||||
? () => onSettingsClick?.()
|
||||
: item.route
|
||||
? () => {
|
||||
onNewChat?.();
|
||||
goto(item.route!);
|
||||
}
|
||||
: isSearchOnMobile
|
||||
? undefined
|
||||
: onSearchClick}
|
||||
{@const itemTransition = {
|
||||
delay: !initialized ? i * ICON_STRIP_TRANSITION_DELAY_MULTIPLIER : 0,
|
||||
duration: ICON_STRIP_TRANSITION_DURATION,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { RefreshCw } from '@lucide/svelte';
|
||||
import { SettingsBackends } from '$lib/components/app/backends';
|
||||
import {
|
||||
SettingsChatDesktopSidebar,
|
||||
SettingsChatFields,
|
||||
@@ -165,8 +164,6 @@
|
||||
<SettingsChatToolsTab />
|
||||
{:else if currentSection.slug === SETTINGS_SECTION_SLUGS.IMPORT_EXPORT}
|
||||
<SettingsChatImportExportTab />
|
||||
{:else if currentSection.slug === SETTINGS_SECTION_SLUGS.BACKENDS}
|
||||
<SettingsBackends />
|
||||
{:else if currentSection.fields}
|
||||
<div class="space-y-6">
|
||||
<SettingsChatFields
|
||||
|
||||
@@ -11,7 +11,6 @@ import {
|
||||
Monitor,
|
||||
Moon,
|
||||
PencilRuler,
|
||||
Server,
|
||||
SlidersVertical,
|
||||
Sun
|
||||
} from '@lucide/svelte';
|
||||
@@ -197,30 +196,6 @@ export const SETTINGS_REGISTRY: SettingsSectionEntry[] = [
|
||||
slug: SETTINGS_SECTION_SLUGS.GENERAL,
|
||||
title: SETTINGS_SECTION_TITLES.GENERAL
|
||||
},
|
||||
// Backends (non-UI config object)
|
||||
{
|
||||
icon: Server,
|
||||
settings: [
|
||||
{
|
||||
defaultValue: '[]',
|
||||
help: 'Configure external API backends as a JSON list. The local backend is always available.',
|
||||
key: SETTINGS_KEYS.BACKENDS,
|
||||
label: 'Backends',
|
||||
standaloneField: false,
|
||||
type: SettingsFieldType.INPUT
|
||||
},
|
||||
{
|
||||
defaultValue: true,
|
||||
help: 'Query the llama-server that serves this UI. Disable it when this UI runs standalone and talks to external backends only.',
|
||||
key: SETTINGS_KEYS.LOCAL_BACKEND_ENABLED,
|
||||
label: 'Local backend',
|
||||
standaloneField: false,
|
||||
type: SettingsFieldType.CHECKBOX
|
||||
}
|
||||
],
|
||||
slug: SETTINGS_SECTION_SLUGS.BACKENDS,
|
||||
title: SETTINGS_SECTION_TITLES.BACKENDS
|
||||
},
|
||||
// Display
|
||||
{
|
||||
icon: Monitor,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Package, PackageSearch, Search, Settings, SquarePen } from '@lucide/svelte';
|
||||
import { Package, PackageSearch, Search, Server, Settings, SquarePen } from '@lucide/svelte';
|
||||
import { SidebarAction, ToolSource } from '$lib/enums';
|
||||
import type { DesktopIconStripItem } from '$lib/types';
|
||||
|
||||
@@ -74,6 +74,11 @@ export const SIDEBAR_ACTIONS_ITEMS: DesktopIconStripItem[] = [
|
||||
icon: PackageSearch,
|
||||
tooltip: 'Discover models'
|
||||
},
|
||||
{
|
||||
action: SidebarAction.BACKENDS,
|
||||
icon: Server,
|
||||
tooltip: 'Backends'
|
||||
},
|
||||
{
|
||||
action: SidebarAction.SETTINGS,
|
||||
icon: Settings,
|
||||
|
||||
@@ -23,6 +23,7 @@ export enum ScrollCarouselVariant {
|
||||
* Sidebar icon strip actions handled directly by the sidebar.
|
||||
*/
|
||||
export enum SidebarAction {
|
||||
BACKENDS = 'backends',
|
||||
DISCOVER_MODELS = 'discover-models',
|
||||
NEW_CHAT = 'new-chat',
|
||||
SETTINGS = 'settings'
|
||||
|
||||
Reference in New Issue
Block a user