mirror of
https://github.com/ggml-org/llama.cpp.git
synced 2026-10-02 10:57:33 -05:00
ui : refine the model pane and the manager filters
The pane no longer says the server withholds data: it says the metadata and the chat template appear once the model is loaded, and the template block grows with its content instead of scrolling inside a fixed box. The pane ends with a Delete this model from disk action, confirmed by the same dialog the table row uses and hovering like a destructive dropdown entry. The filter toggles list only the modalities the models at hand actually carry, and starting a new chat from the pane closes the dialog. Assisted-by: pi
This commit is contained in:
@@ -225,7 +225,8 @@
|
||||
async function useInNewChat(option: ModelOption): Promise<void> {
|
||||
await modelsStore.selectModelById(option.id);
|
||||
await conversationsStore.openNewChat();
|
||||
// the chat is behind the dialog, so it takes focus once the dialog is out of the way
|
||||
// the chat is behind the dialog: close it, then let the composer take focus
|
||||
uiStore.manageModelsOpen = false;
|
||||
uiStore.requestComposerFocus();
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -9,11 +9,14 @@
|
||||
FILTER_TRIGGER_CLASS,
|
||||
MODALITY_FLAG_KEYS,
|
||||
MODALITY_ICONS,
|
||||
MODALITY_KEYS,
|
||||
MODALITY_LABELS,
|
||||
MODALITY_ORDER,
|
||||
type ModalityKey
|
||||
} from '$lib/constants';
|
||||
import { ModelCapability } from '$lib/enums';
|
||||
import { modelsStore } from '$lib/stores';
|
||||
import { SvelteSet } from 'svelte/reactivity';
|
||||
|
||||
interface Props {
|
||||
/** Capabilities a model must have every one of. */
|
||||
@@ -45,16 +48,34 @@
|
||||
value
|
||||
}));
|
||||
|
||||
const MODALITY_TOGGLES = MODALITY_ORDER.map((modality) => ({
|
||||
icon: MODALITY_ICONS[modality],
|
||||
label: MODALITY_LABELS[modality],
|
||||
value: MODALITY_FLAG_KEYS[modality]
|
||||
}));
|
||||
// only the modalities the models at hand actually carry: a toggle for something
|
||||
// none of them supports could only ever empty the table
|
||||
let detectedModalities = $derived.by(() => {
|
||||
const keys = new SvelteSet<ModalityKey>();
|
||||
|
||||
for (const option of modelsStore.models) {
|
||||
for (const key of MODALITY_KEYS) {
|
||||
if (option.modalities?.[key]) keys.add(key);
|
||||
}
|
||||
}
|
||||
|
||||
return keys;
|
||||
});
|
||||
let modalityToggles = $derived(
|
||||
MODALITY_ORDER.filter((modality) => detectedModalities.has(MODALITY_FLAG_KEYS[modality])).map(
|
||||
(modality) => ({
|
||||
icon: MODALITY_ICONS[modality],
|
||||
label: MODALITY_LABELS[modality],
|
||||
value: MODALITY_FLAG_KEYS[modality]
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
// one group holds what a model can do and what it can accept
|
||||
const TOGGLES = [...CAPABILITY_TOGGLES, ...MODALITY_TOGGLES];
|
||||
let toggles = $derived([...CAPABILITY_TOGGLES, ...modalityToggles]);
|
||||
const CAPABILITY_VALUES = new Set<string>(CAPABILITY_TOGGLES.map((entry) => entry.value));
|
||||
const MODALITY_VALUES = new Set<string>(MODALITY_TOGGLES.map((entry) => entry.value));
|
||||
// every flag value, so a choice made before a model disappeared still round-trips
|
||||
const MODALITY_VALUES = new Set<string>(MODALITY_KEYS);
|
||||
|
||||
// the group holds one flat list, so a change splits back into the two filters
|
||||
function setToggles(values: string[]): void {
|
||||
@@ -93,7 +114,7 @@
|
||||
value={[...capabilities, ...modalities]}
|
||||
variant="outline"
|
||||
>
|
||||
{#each TOGGLES as toggle (toggle.value)}
|
||||
{#each toggles as toggle (toggle.value)}
|
||||
<ToggleGroup.Item
|
||||
aria-label={toggle.label}
|
||||
class={FILTER_TOGGLE_ITEM_CLASS}
|
||||
|
||||
+26
-1
@@ -1,8 +1,11 @@
|
||||
<script lang="ts">
|
||||
import ModelsManagerModelConfigurationHeader from './ModelsManagerModelConfigurationHeader.svelte';
|
||||
import ModelsManagerModelConfigurationInformation from './ModelsManagerModelConfigurationInformation.svelte';
|
||||
import { Trash2 } from '@lucide/svelte';
|
||||
import { DialogConfirmDownload } from '$lib/components/app/dialogs';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { MODEL_ID, SETTINGS_KEYS } from '$lib/constants';
|
||||
import { ServerModelStatus } from '$lib/enums';
|
||||
import { ModelDownloadConfirmAction, ServerModelStatus } from '$lib/enums';
|
||||
import { HuggingFaceService } from '$lib/services';
|
||||
import { modelsStore, settingsStore } from '$lib/stores';
|
||||
import type { HfModelDetailInfo } from '$lib/types/huggingface';
|
||||
@@ -17,6 +20,9 @@
|
||||
|
||||
let { onClose, onToggleLoad, onUseInNewChat, option }: Props = $props();
|
||||
|
||||
// the same removal the table row offers, confirmed by the same dialog
|
||||
let deleteOpen = $state(false);
|
||||
|
||||
// the props cache is a plain Map, so the read has to name its version to stay reactive
|
||||
let serverProps = $derived.by(() => {
|
||||
void modelsStore.props.cacheVersion;
|
||||
@@ -69,5 +75,24 @@
|
||||
|
||||
<div class="min-h-0 flex-1 overflow-y-auto py-4 pl-4">
|
||||
<ModelsManagerModelConfigurationInformation hub={hubDetails} {option} {serverProps} />
|
||||
|
||||
<div class="mt-4 border-t border-border/30 pt-3 pb-2">
|
||||
<Button
|
||||
class="w-full justify-start gap-2 text-destructive hover:bg-destructive/10 hover:text-destructive dark:hover:bg-destructive/20"
|
||||
onclick={() => (deleteOpen = true)}
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
>
|
||||
<Trash2 class="h-4 w-4" />
|
||||
Delete this model from disk
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<DialogConfirmDownload
|
||||
action={ModelDownloadConfirmAction.DELETE}
|
||||
onClose={() => (deleteOpen = false)}
|
||||
open={deleteOpen}
|
||||
repoWithTag={option.model}
|
||||
/>
|
||||
</div>
|
||||
|
||||
+5
-3
@@ -162,7 +162,9 @@
|
||||
{/each}
|
||||
|
||||
{#if visibleRows.length === 0}
|
||||
<p class="py-2.5 text-sm text-muted-foreground">This model reports no metadata.</p>
|
||||
<p class="py-2.5 text-sm text-muted-foreground">
|
||||
The model reports its metadata once it is loaded.
|
||||
</p>
|
||||
{/if}
|
||||
|
||||
{#if modalities.length > 0}
|
||||
@@ -188,8 +190,8 @@
|
||||
{/snippet}
|
||||
|
||||
<pre
|
||||
class="mt-1 max-h-48 overflow-auto rounded-md bg-muted/50 p-2 text-xs whitespace-pre-wrap">{serverProps?.chat_template ??
|
||||
class="mt-1 rounded-md bg-muted/50 p-2 text-xs whitespace-pre-wrap">{serverProps?.chat_template ??
|
||||
gguf?.chat_template ??
|
||||
'Not reported by the server.'}</pre>
|
||||
'Shown once the model is loaded.'}</pre>
|
||||
</CollapsibleSection>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user