let filteredOptions = $derived(filterModelOptions(options, searchTerm));
let groupedFilteredOptions = $derived(
- groupModelOptions(filteredOptions, modelsStore.favouriteModelIds, (m) =>
+ groupModelOptions(filteredOptions, modelsStore.favoriteModelIds, (m) =>
modelsStore.isModelLoaded(m)
)
);
{@const { option, flatIndex } = item}
{@const isSelected = currentModel === option.model || activeId === option.id}
{@const isHighlighted = flatIndex === highlightedIndex}
- {@const isFav = modelsStore.favouriteModelIds.has(option.model)}
+ {@const isFav = modelsStore.favoriteModelIds.has(option.model)}
<ModelsSelectorOption
{option}
{#snippet defaultOption(item: ModelItem, showOrgName: boolean)}
{@const { option } = item}
{@const isSelected = currentModel === option.model || activeId === option.id}
- {@const isFav = modelsStore.favouriteModelIds.has(option.model)}
+ {@const isFav = modelsStore.favoriteModelIds.has(option.model)}
<ModelsSelectorOption
{option}
{/each}
{/if}
-{#if groups.favourites.length > 0}
- <p class={sectionHeaderClass}>Favourite models</p>
- {#each groups.favourites as item (`fav-${item.option.id}`)}
+{#if groups.favorites.length > 0}
+ <p class={sectionHeaderClass}>Favorite models</p>
+ {#each groups.favorites as item (`fav-${item.option.id}`)}
{@render render(item, true)}
{/each}
{/if}
});
let isOperationInProgress = $derived(modelsStore.isModelOperationInProgress(option.model));
let isFailed = $derived(serverStatus === ServerModelStatus.FAILED);
- let isLoaded = $derived(serverStatus === ServerModelStatus.LOADED && !isOperationInProgress);
+ let isSleeping = $derived(serverStatus === ServerModelStatus.SLEEPING);
+ let isLoaded = $derived(
+ (serverStatus === ServerModelStatus.LOADED || isSleeping) && !isOperationInProgress
+ );
let isLoading = $derived(serverStatus === ServerModelStatus.LOADING || isOperationInProgress);
</script>
<ActionIcon
iconSize="h-2.5 w-2.5"
icon={HeartOff}
- tooltip="Remove from favourites"
+ tooltip="Remove from favorites"
class="h-3 w-3 hover:text-foreground"
- onclick={() => modelsStore.toggleFavourite(option.model)}
+ onclick={() => modelsStore.toggleFavorite(option.model)}
/>
{:else}
<ActionIcon
iconSize="h-2.5 w-2.5"
icon={Heart}
- tooltip="Add to favourites"
+ tooltip="Add to favorites"
class="h-3 w-3 hover:text-foreground"
- onclick={() => modelsStore.toggleFavourite(option.model)}
+ onclick={() => modelsStore.toggleFavorite(option.model)}
/>
{/if}
/>
</div>
</div>
+ {:else if isSleeping}
+ <div class="flex w-4 items-center justify-center">
+ <span class="h-2 w-2 rounded-full bg-orange-400 group-hover:hidden"></span>
+
+ <div class="hidden group-hover:flex">
+ <ActionIcon
+ iconSize="h-2.5 w-2.5"
+ icon={PowerOff}
+ tooltip="Unload model"
+ class="h-3 w-3 text-red-500 hover:text-red-600"
+ onclick={(e) => {
+ e?.stopPropagation();
+ modelsStore.unloadModel(option.model);
+ }}
+ />
+ </div>
+ </div>
{:else if isLoaded}
<div class="flex w-4 items-center justify-center">
<span class="h-2 w-2 rounded-full bg-green-500 group-hover:hidden"></span>
let filteredOptions = $derived(filterModelOptions(options, searchTerm));
let groupedFilteredOptions = $derived(
- groupModelOptions(filteredOptions, modelsStore.favouriteModelIds, (m) =>
+ groupModelOptions(filteredOptions, modelsStore.favoriteModelIds, (m) =>
modelsStore.isModelLoaded(m)
)
);
/**
* **ModelsSelectorList** - Grouped model options list
*
- * Renders grouped model options (loaded, favourites, available) with section
+ * Renders grouped model options (loaded, favorites, available) with section
* headers and org subgroups. Shared between ModelsSelector and ModelsSelectorSheet
* to avoid template duplication.
*
/**
* **ModelsSelectorOption** - Single model option row
*
- * Renders a single model option with selection state, favourite toggle,
+ * Renders a single model option with selection state, favorite toggle,
* load/unload actions, status indicators, and an info button.
* Used inside ModelsSelectorList or directly in custom render snippets.
*/
export interface GroupedModelOptions {
loaded: ModelItem[];
- favourites: ModelItem[];
+ favorites: ModelItem[];
available: OrgGroup[];
}
export function groupModelOptions(
filteredOptions: ModelOption[],
- favouriteIds: Set<string>,
+ favoriteIds: Set<string>,
isModelLoaded: (model: string) => boolean
): GroupedModelOptions {
// Loaded models
}
}
- // Favourites (excluding loaded)
+ // Favorites (excluding loaded)
const loadedModelIds = new Set(loaded.map((item) => item.option.model));
- const favourites: ModelItem[] = [];
+ const favorites: ModelItem[] = [];
for (let i = 0; i < filteredOptions.length; i++) {
if (
- favouriteIds.has(filteredOptions[i].model) &&
+ favoriteIds.has(filteredOptions[i].model) &&
!loadedModelIds.has(filteredOptions[i].model)
) {
- favourites.push({ option: filteredOptions[i], flatIndex: i });
+ favorites.push({ option: filteredOptions[i], flatIndex: i });
}
}
- // Available models grouped by org (excluding loaded and favourites)
+ // Available models grouped by org (excluding loaded and favorites)
const available: OrgGroup[] = [];
const orgGroups = new SvelteMap<string, ModelItem[]>();
for (let i = 0; i < filteredOptions.length; i++) {
const option = filteredOptions[i];
- if (loadedModelIds.has(option.model) || favouriteIds.has(option.model)) continue;
+ if (loadedModelIds.has(option.model) || favoriteIds.has(option.model)) continue;
const key = option.parsedId?.orgName ?? '';
if (!orgGroups.has(key)) orgGroups.set(key, []);
available.push({ orgName: orgName || null, items });
}
- return { loaded, favourites, available };
+ return { loaded, favorites, available };
}
export const CONFIG_LOCALSTORAGE_KEY = 'LlamaCppWebui.config';
export const USER_OVERRIDES_LOCALSTORAGE_KEY = 'LlamaCppWebui.userOverrides';
-export const FAVOURITE_MODELS_LOCALSTORAGE_KEY = 'LlamaCppWebui.favouriteModels';
+export const FAVORITE_MODELS_LOCALSTORAGE_KEY = 'LlamaCppWebui.favoriteModels';
export const MCP_DEFAULT_ENABLED_LOCALSTORAGE_KEY = 'LlamaCppWebui.mcpDefaultEnabled';
UNLOADED = 'unloaded',
LOADING = 'loading',
LOADED = 'loaded',
+ SLEEPING = 'sleeping',
FAILED = 'failed'
}
import {
MODEL_PROPS_CACHE_TTL_MS,
MODEL_PROPS_CACHE_MAX_ENTRIES,
- FAVOURITE_MODELS_LOCALSTORAGE_KEY
+ FAVORITE_MODELS_LOCALSTORAGE_KEY
} from '$lib/constants';
/**
private modelUsage = $state<Map<string, SvelteSet<string>>>(new Map());
private modelLoadingStates = new SvelteMap<string, boolean>();
- favouriteModelIds = $state<Set<string>>(this.loadFavouritesFromStorage());
+ favoriteModelIds = $state<Set<string>>(this.loadFavoritesFromStorage());
/**
* Model-specific props cache with TTL
get loadedModelIds(): string[] {
return this.routerModels
- .filter((m) => m.status.value === ServerModelStatus.LOADED)
+ .filter(
+ (m) =>
+ m.status.value === ServerModelStatus.LOADED ||
+ m.status.value === ServerModelStatus.SLEEPING
+ )
.map((m) => m.id);
}
isModelLoaded(modelId: string): boolean {
const model = this.routerModels.find((m) => m.id === modelId);
- return model?.status.value === ServerModelStatus.LOADED || false;
+ return (
+ model?.status.value === ServerModelStatus.LOADED ||
+ model?.status.value === ServerModelStatus.SLEEPING ||
+ false
+ );
}
isModelOperationInProgress(modelId: string): boolean {
/**
*
*
- * Favourites
+ * Favorites
*
*
*/
- isFavourite(modelId: string): boolean {
- return this.favouriteModelIds.has(modelId);
+ isFavorite(modelId: string): boolean {
+ return this.favoriteModelIds.has(modelId);
}
- toggleFavourite(modelId: string): void {
- const next = new SvelteSet(this.favouriteModelIds);
+ toggleFavorite(modelId: string): void {
+ const next = new SvelteSet(this.favoriteModelIds);
if (next.has(modelId)) {
next.delete(modelId);
next.add(modelId);
}
- this.favouriteModelIds = next;
+ this.favoriteModelIds = next;
try {
- localStorage.setItem(FAVOURITE_MODELS_LOCALSTORAGE_KEY, JSON.stringify([...next]));
+ localStorage.setItem(FAVORITE_MODELS_LOCALSTORAGE_KEY, JSON.stringify([...next]));
} catch {
- toast.error('Failed to save favourite models to local storage');
+ toast.error('Failed to save favorite models to local storage');
}
}
- private loadFavouritesFromStorage(): Set<string> {
+ private loadFavoritesFromStorage(): Set<string> {
try {
- const raw = localStorage.getItem(FAVOURITE_MODELS_LOCALSTORAGE_KEY);
+ const raw = localStorage.getItem(FAVORITE_MODELS_LOCALSTORAGE_KEY);
return raw ? new Set(JSON.parse(raw) as string[]) : new Set();
} catch {
- toast.error('Failed to load favourite models from local storage');
+ toast.error('Failed to load favorite models from local storage');
return new Set();
}
export const propsCacheVersion = () => modelsStore.propsCacheVersion;
export const singleModelName = () => modelsStore.singleModelName;
export const selectedModelContextSize = () => modelsStore.selectedModelContextSize;
-export const favouriteModelIds = () => modelsStore.favouriteModelIds;
+export const favoriteModelIds = () => modelsStore.favoriteModelIds;
* Model status object from /models endpoint
*/
export interface ApiModelStatus {
- /** Status value: loaded, unloaded, loading, failed */
+ /** Status value: loaded, unloaded, loading, sleeping, failed */
value: ServerModelStatus;
/** Command line arguments used when loading (only for loaded models) */
args?: string[];