This commit is contained in:
Timothy Jaeryang Baek
2026-06-29 12:16:05 -05:00
parent 6fd8c599c1
commit c89fd237b8
3 changed files with 65 additions and 36 deletions
@@ -22,11 +22,12 @@
export let selectedModelIdx: number = -1;
export let item: any = {};
export let index: number = -1;
export let value: string = '';
export let value: string | null = '';
export let unloadModelHandler: (modelValue: string) => void = () => {};
export let pinModelHandler: (modelId: string) => void = () => {};
export let deleteModelHandler: (model: any) => void = () => {};
export let selectionOnly = false;
export let onClick: () => void = () => {};
@@ -237,7 +238,7 @@
</div>
<div class="ml-auto pl-2 pr-1 flex items-center gap-1.5 shrink-0">
{#if $user?.role === 'admin' && item.model.loaded}
{#if !selectionOnly && $user?.role === 'admin' && item.model.loaded}
<Tooltip
content={`${$i18n.t('Eject')}`}
className="flex-shrink-0 group-hover/item:opacity-100 opacity-0 "
@@ -256,27 +257,29 @@
</Tooltip>
{/if}
<ModelItemMenu
bind:show={showMenu}
model={item.model}
{pinModelHandler}
{deleteModelHandler}
copyLinkHandler={() => {
copyLinkHandler(item.model);
}}
>
<button
aria-label={`${$i18n.t('More Options')}`}
class="flex"
on:click={(e) => {
e.preventDefault();
e.stopPropagation();
showMenu = !showMenu;
{#if !selectionOnly}
<ModelItemMenu
bind:show={showMenu}
model={item.model}
{pinModelHandler}
{deleteModelHandler}
copyLinkHandler={() => {
copyLinkHandler(item.model);
}}
>
<EllipsisHorizontal />
</button>
</ModelItemMenu>
<button
aria-label={`${$i18n.t('More Options')}`}
class="flex"
on:click={(e) => {
e.preventDefault();
e.stopPropagation();
showMenu = !showMenu;
}}
>
<EllipsisHorizontal />
</button>
</ModelItemMenu>
{/if}
{#if value === item.value}
<div>
@@ -42,10 +42,11 @@
const dispatch = createEventDispatcher();
export let id = '';
export let value = '';
export let value: string | null = '';
export let placeholder = $i18n.t('Select a model');
export let searchEnabled = true;
export let searchPlaceholder = $i18n.t('Search a model');
export let selectionOnly = false;
export let items: {
label: string;
@@ -398,7 +399,7 @@
}
});
$: if (show) {
$: if (show && !selectionOnly) {
setOllamaVersion();
}
@@ -742,6 +743,7 @@
{pinModelHandler}
{unloadModelHandler}
{deleteModelHandler}
{selectionOnly}
onClick={() => {
value = item.value;
selectedModelIdx = index;
@@ -754,7 +756,7 @@
</div>
{/if}
{#if !(searchValue.trim() in $MODEL_DOWNLOAD_POOL) && searchValue && ollamaVersion && $user?.role === 'admin'}
{#if !selectionOnly && !(searchValue.trim() in $MODEL_DOWNLOAD_POOL) && searchValue && ollamaVersion && $user?.role === 'admin'}
<Tooltip
content={$i18n.t(`Pull "{{searchValue}}" from Ollama.com`, {
searchValue: searchValue
@@ -776,7 +778,7 @@
</Tooltip>
{/if}
{#each Object.keys($MODEL_DOWNLOAD_POOL) as model}
{#each selectionOnly ? [] : Object.keys($MODEL_DOWNLOAD_POOL) as model}
<div
class="flex w-full justify-between font-medium select-none rounded-button py-2 pl-3 pr-1.5 text-sm text-gray-700 dark:text-gray-100 outline-hidden transition-all duration-75 rounded-xl cursor-pointer data-highlighted:bg-muted"
>
@@ -13,6 +13,7 @@
import { getVoices } from '$lib/apis/audio';
import AdvancedParams from '$lib/components/chat/Settings/Advanced/AdvancedParams.svelte';
import ModelSelector from '$lib/components/chat/ModelSelector/Selector.svelte';
import Tags from '$lib/components/common/Tags.svelte';
import Knowledge from '$lib/components/workspace/Models/Knowledge.svelte';
import ToolsSelector from '$lib/components/workspace/Models/ToolsSelector.svelte';
@@ -112,6 +113,25 @@
export let suggestionTags: { name: string }[] = [];
let voices: { id: string; name?: string }[] = [];
const getBaseModelItems = (models: any[] = []) => {
const currentModelId = (model as any)?.id;
return models
.filter(
(baseModel) =>
(!currentModelId || baseModel.id !== currentModelId) &&
!baseModel?.preset &&
baseModel?.owned_by !== 'arena' &&
!(baseModel?.direct ?? false) &&
(!(baseModel?.info?.meta?.hidden ?? false) || baseModel.id === info.base_model_id)
)
.map((baseModel) => ({
value: baseModel.id,
label: baseModel.name,
model: baseModel
}));
};
const loadSuggestionTags = async () => {
const res: string[] = await (preset ? getModelTags : getBaseModelTags)(
localStorage.token
@@ -144,6 +164,13 @@
return;
}
if (preset && !info.base_model_id) {
toast.error($i18n.t('Base Model is required.'));
loading = false;
return;
}
if (knowledge.some((item) => item.status === 'uploading')) {
toast.error($i18n.t('Please wait until all files are uploaded.'));
loading = false;
@@ -619,19 +646,16 @@
</div>
<div>
<select
class="text-sm w-full bg-transparent outline-hidden"
<ModelSelector
id="workspace-base-model"
placeholder={$i18n.t('Select a base model (e.g. llama3, gpt-4o)')}
searchPlaceholder={$i18n.t('Search a model')}
items={getBaseModelItems($models)}
className="w-[32rem]"
triggerClassName="text-sm"
selectionOnly
bind:value={info.base_model_id}
required
>
<option value={null} class=" text-gray-900"
>{$i18n.t('Select a base model')}</option
>
{#each $models.filter((m) => (model ? m.id !== model.id : true) && !m?.preset && m?.owned_by !== 'arena' && !(m?.direct ?? false) && (!(m?.info?.meta?.hidden ?? false) || m.id === info.base_model_id)) as model}
<option value={model.id} class=" text-gray-900">{model.name}</option>
{/each}
</select>
/>
</div>
</div>
{/if}