|
@@ -52,12 +52,17 @@
|
|
export let className = 'w-[32rem]';
|
|
export let className = 'w-[32rem]';
|
|
export let triggerClassName = 'text-lg';
|
|
export let triggerClassName = 'text-lg';
|
|
|
|
|
|
|
|
+ let tagsContainerElement;
|
|
|
|
+
|
|
let show = false;
|
|
let show = false;
|
|
|
|
+ let tags = [];
|
|
|
|
|
|
let selectedModel = '';
|
|
let selectedModel = '';
|
|
$: selectedModel = items.find((item) => item.value === value) ?? '';
|
|
$: selectedModel = items.find((item) => item.value === value) ?? '';
|
|
|
|
|
|
let searchValue = '';
|
|
let searchValue = '';
|
|
|
|
+ let selectedTag = '';
|
|
|
|
+
|
|
let ollamaVersion = null;
|
|
let ollamaVersion = null;
|
|
|
|
|
|
let selectedModelIdx = 0;
|
|
let selectedModelIdx = 0;
|
|
@@ -79,10 +84,23 @@
|
|
);
|
|
);
|
|
|
|
|
|
$: filteredItems = searchValue
|
|
$: filteredItems = searchValue
|
|
- ? fuse.search(searchValue).map((e) => {
|
|
|
|
- return e.item;
|
|
|
|
- })
|
|
|
|
- : items;
|
|
|
|
|
|
+ ? fuse
|
|
|
|
+ .search(searchValue)
|
|
|
|
+ .map((e) => {
|
|
|
|
+ return e.item;
|
|
|
|
+ })
|
|
|
|
+ .filter((item) => {
|
|
|
|
+ if (selectedTag === '') {
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ return item.model?.info?.meta?.tags?.map((tag) => tag.name).includes(selectedTag);
|
|
|
|
+ })
|
|
|
|
+ : items.filter((item) => {
|
|
|
|
+ if (selectedTag === '') {
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ return item.model?.info?.meta?.tags?.map((tag) => tag.name).includes(selectedTag);
|
|
|
|
+ });
|
|
|
|
|
|
const pullModelHandler = async () => {
|
|
const pullModelHandler = async () => {
|
|
const sanitizedModelTag = searchValue.trim().replace(/^ollama\s+(run|pull)\s+/, '');
|
|
const sanitizedModelTag = searchValue.trim().replace(/^ollama\s+(run|pull)\s+/, '');
|
|
@@ -214,6 +232,11 @@
|
|
|
|
|
|
onMount(async () => {
|
|
onMount(async () => {
|
|
ollamaVersion = await getOllamaVersion(localStorage.token).catch((error) => false);
|
|
ollamaVersion = await getOllamaVersion(localStorage.token).catch((error) => false);
|
|
|
|
+
|
|
|
|
+ if (items) {
|
|
|
|
+ tags = items.flatMap((item) => item.model?.info?.meta?.tags ?? []);
|
|
|
|
+ tags = [...new Set(tags)].map((tag) => tag.name).sort();
|
|
|
|
+ }
|
|
});
|
|
});
|
|
|
|
|
|
const cancelModelPullHandler = async (model: string) => {
|
|
const cancelModelPullHandler = async (model: string) => {
|
|
@@ -298,10 +321,43 @@
|
|
/>
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
- <hr class="border-gray-100 dark:border-gray-850" />
|
|
|
|
|
|
+ <hr class="border-gray-100 dark:border-gray-800" />
|
|
{/if}
|
|
{/if}
|
|
|
|
|
|
- <div class="px-3 my-2 max-h-64 overflow-y-auto scrollbar-hidden group">
|
|
|
|
|
|
+ <div class="px-3 my-2 max-h-64 overflow-y-auto scrollbar-hidden group relative">
|
|
|
|
+ {#if tags}
|
|
|
|
+ <div class=" flex w-full sticky">
|
|
|
|
+ <div
|
|
|
|
+ class="flex gap-1 scrollbar-none overflow-x-auto w-fit text-center text-sm font-medium rounded-full bg-transparent px-1.5 pb-0.5"
|
|
|
|
+ bind:this={tagsContainerElement}
|
|
|
|
+ >
|
|
|
|
+ <button
|
|
|
|
+ class="min-w-fit outline-none p-1.5 {selectedTag === ''
|
|
|
|
+ ? ''
|
|
|
|
+ : 'text-gray-300 dark:text-gray-600 hover:text-gray-700 dark:hover:text-white'} transition"
|
|
|
|
+ on:click={() => {
|
|
|
|
+ selectedTag = '';
|
|
|
|
+ }}
|
|
|
|
+ >
|
|
|
|
+ {$i18n.t('All')}
|
|
|
|
+ </button>
|
|
|
|
+
|
|
|
|
+ {#each tags as tag}
|
|
|
|
+ <button
|
|
|
|
+ class="min-w-fit outline-none p-1.5 {selectedTag === tag
|
|
|
|
+ ? ''
|
|
|
|
+ : 'text-gray-300 dark:text-gray-600 hover:text-gray-700 dark:hover:text-white'} transition"
|
|
|
|
+ on:click={() => {
|
|
|
|
+ selectedTag = tag;
|
|
|
|
+ }}
|
|
|
|
+ >
|
|
|
|
+ {tag}
|
|
|
|
+ </button>
|
|
|
|
+ {/each}
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ {/if}
|
|
|
|
+
|
|
{#each filteredItems as item, index}
|
|
{#each filteredItems as item, index}
|
|
<button
|
|
<button
|
|
aria-label="model-item"
|
|
aria-label="model-item"
|
|
@@ -441,11 +497,13 @@
|
|
{/if}
|
|
{/if}
|
|
|
|
|
|
{#if !$mobile && (item?.model?.info?.meta?.tags ?? []).length > 0}
|
|
{#if !$mobile && (item?.model?.info?.meta?.tags ?? []).length > 0}
|
|
- <div class="flex gap-0.5 self-center items-center h-full translate-y-[0.5px]">
|
|
|
|
|
|
+ <div
|
|
|
|
+ class="flex gap-0.5 self-center items-center h-full translate-y-[0.5px] overflow-x-auto scrollbar-none"
|
|
|
|
+ >
|
|
{#each item.model?.info?.meta.tags as tag}
|
|
{#each item.model?.info?.meta.tags as tag}
|
|
- <Tooltip content={tag.name}>
|
|
|
|
|
|
+ <Tooltip content={tag.name} className="flex-shrink-0">
|
|
<div
|
|
<div
|
|
- class=" text-xs font-bold px-1 rounded-sm uppercase line-clamp-1 bg-gray-500/20 text-gray-700 dark:text-gray-200"
|
|
|
|
|
|
+ class=" text-xs font-bold px-1 rounded-sm uppercase bg-gray-500/20 text-gray-700 dark:text-gray-200"
|
|
>
|
|
>
|
|
{tag.name}
|
|
{tag.name}
|
|
</div>
|
|
</div>
|
|
@@ -575,7 +633,7 @@
|
|
</div>
|
|
</div>
|
|
|
|
|
|
{#if showTemporaryChatControl}
|
|
{#if showTemporaryChatControl}
|
|
- <hr class="border-gray-100 dark:border-gray-850" />
|
|
|
|
|
|
+ <hr class="border-gray-100 dark:border-gray-800" />
|
|
|
|
|
|
<div class="flex items-center mx-2 my-2">
|
|
<div class="flex items-center mx-2 my-2">
|
|
<button
|
|
<button
|