open-webui/src/lib/components/workspace/Models/Knowledge/Selector.svelte

158 lines
4.2 KiB
Svelte
Raw Normal View History

2024-06-10 00:17:35 +00:00
<script lang="ts">
2024-10-05 02:24:36 +00:00
import Fuse from 'fuse.js';
2024-06-10 00:17:35 +00:00
import { DropdownMenu } from 'bits-ui';
2024-10-02 06:21:33 +00:00
import { onMount, getContext, createEventDispatcher } from 'svelte';
2024-06-10 00:17:35 +00:00
import { flyAndScale } from '$lib/utils/transitions';
2024-10-02 05:45:04 +00:00
import { knowledge } from '$lib/stores';
2024-06-10 00:17:35 +00:00
import Dropdown from '$lib/components/common/Dropdown.svelte';
2025-06-25 17:42:18 +00:00
import Search from '$lib/components/icons/Search.svelte';
2024-06-10 00:17:35 +00:00
const i18n = getContext('i18n');
2024-10-02 06:21:33 +00:00
const dispatch = createEventDispatcher();
2024-06-10 00:17:35 +00:00
export let onClose: Function = () => {};
2024-10-05 02:24:36 +00:00
let query = '';
2024-06-10 00:17:35 +00:00
let items = [];
2024-10-05 02:24:36 +00:00
let filteredItems = [];
let fuse = null;
$: if (fuse) {
filteredItems = query
? fuse.search(query).map((e) => {
return e.item;
})
: items;
}
2024-06-10 00:17:35 +00:00
onMount(() => {
2024-10-02 06:21:33 +00:00
let legacy_documents = $knowledge.filter((item) => item?.meta?.document);
let legacy_collections =
legacy_documents.length > 0
? [
{
name: 'All Documents',
legacy: true,
type: 'collection',
2024-10-02 13:19:09 +00:00
description: 'Deprecated (legacy collection), please create a new knowledge base.',
2024-10-02 06:21:33 +00:00
title: $i18n.t('All Documents'),
collection_names: legacy_documents.map((item) => item.id)
},
...legacy_documents
.reduce((a, item) => {
return [...new Set([...a, ...(item?.meta?.tags ?? []).map((tag) => tag.name)])];
}, [])
.map((tag) => ({
name: tag,
legacy: true,
type: 'collection',
2024-10-02 13:19:09 +00:00
description: 'Deprecated (legacy collection), please create a new knowledge base.',
2024-10-02 06:21:33 +00:00
collection_names: legacy_documents
.filter((item) => (item?.meta?.tags ?? []).map((tag) => tag.name).includes(tag))
.map((item) => item.id)
}))
]
: [];
2024-06-10 00:17:35 +00:00
2024-10-04 23:43:41 +00:00
items = [...$knowledge, ...legacy_collections].map((item) => {
return {
...item,
2024-10-05 02:32:33 +00:00
...(item?.legacy || item?.meta?.legacy || item?.meta?.document ? { legacy: true } : {}),
type: item?.meta?.document ? 'document' : 'collection'
2024-10-04 23:43:41 +00:00
};
});
2024-10-05 02:24:36 +00:00
fuse = new Fuse(items, {
keys: ['name', 'description']
});
2024-06-10 00:17:35 +00:00
});
</script>
<Dropdown
on:change={(e) => {
if (e.detail === false) {
onClose();
2024-10-05 02:24:36 +00:00
query = '';
2024-06-10 00:17:35 +00:00
}
}}
>
<slot />
<div slot="content">
<DropdownMenu.Content
2024-10-02 06:21:33 +00:00
class="w-full max-w-80 rounded-lg px-1 py-1.5 border border-gray-300/30 dark:border-gray-700/50 z-50 bg-white dark:bg-gray-850 dark:text-white shadow-lg"
2024-06-10 00:17:35 +00:00
sideOffset={8}
side="bottom"
2024-06-10 00:55:23 +00:00
align="start"
2024-06-10 00:17:35 +00:00
transition={flyAndScale}
>
2024-10-05 02:24:36 +00:00
<div class=" flex w-full space-x-2 py-0.5 px-2">
<div class="flex flex-1">
<div class=" self-center ml-1 mr-3">
2025-06-25 17:42:18 +00:00
<Search class="w-5 h-5" />
2024-10-05 02:24:36 +00:00
</div>
<input
2025-02-16 03:27:25 +00:00
class=" w-full text-sm pr-4 py-1 rounded-r-xl outline-hidden bg-transparent"
2024-10-05 02:24:36 +00:00
bind:value={query}
placeholder={$i18n.t('Search Knowledge')}
/>
</div>
</div>
<hr class=" border-gray-50 dark:border-gray-700 my-1.5" />
<div class="max-h-48 overflow-y-scroll">
{#if filteredItems.length === 0}
2024-06-10 00:55:23 +00:00
<div class="text-center text-sm text-gray-500 dark:text-gray-400">
2024-10-02 06:21:33 +00:00
{$i18n.t('No knowledge found')}
2024-06-10 00:55:23 +00:00
</div>
{:else}
2024-10-05 02:24:36 +00:00
{#each filteredItems as item}
2024-06-10 00:55:23 +00:00
<DropdownMenu.Item
class="flex gap-2.5 items-center px-3 py-2 text-sm cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
on:click={() => {
2024-10-02 06:21:33 +00:00
dispatch('select', item);
2024-06-10 00:55:23 +00:00
}}
>
<div class="flex items-center">
<div class="flex flex-col">
2024-10-02 06:21:33 +00:00
<div class=" w-fit mb-0.5">
{#if item.legacy}
<div
2025-02-16 03:27:25 +00:00
class="bg-gray-500/20 text-gray-700 dark:text-gray-200 rounded-sm uppercase text-xs font-bold px-1"
2024-10-02 06:21:33 +00:00
>
Legacy
</div>
{:else if item?.meta?.document}
<div
2025-02-16 03:27:25 +00:00
class="bg-gray-500/20 text-gray-700 dark:text-gray-200 rounded-sm uppercase text-xs font-bold px-1"
2024-10-02 06:21:33 +00:00
>
Document
</div>
{:else}
<div
2025-02-16 03:27:25 +00:00
class="bg-green-500/20 text-green-700 dark:text-green-200 rounded-sm uppercase text-xs font-bold px-1"
2024-10-02 06:21:33 +00:00
>
Collection
</div>
{/if}
2024-06-10 00:55:23 +00:00
</div>
2024-06-10 00:17:35 +00:00
2024-06-10 00:55:23 +00:00
<div class="line-clamp-1 font-medium pr-0.5">
{item.name}
</div>
2024-06-10 00:17:35 +00:00
</div>
</div>
2024-06-10 00:55:23 +00:00
</DropdownMenu.Item>
{/each}
{/if}
2024-06-10 00:17:35 +00:00
</div>
</DropdownMenu.Content>
</div>
</Dropdown>