Timothy J. Baek 7 mēneši atpakaļ
vecāks
revīzija
7f51ef1838

+ 48 - 10
src/lib/components/chat/MessageInput/Commands/Knowledge.svelte

@@ -14,6 +14,7 @@
 	const dispatch = createEventDispatcher();
 	let selectedIdx = 0;
 
+	let items = [];
 	let fuse = null;
 
 	let filteredItems = [];
@@ -22,7 +23,7 @@
 			? fuse.search(command).map((e) => {
 					return e.item;
 				})
-			: $knowledge;
+			: items;
 	}
 
 	$: if (command) {
@@ -71,7 +72,38 @@
 	};
 
 	onMount(() => {
-		fuse = new Fuse($knowledge, {
+		let legacy_documents = $knowledge.filter((item) => item?.meta?.document);
+		let legacy_collections =
+			legacy_documents.length > 0
+				? [
+						{
+							name: 'All Documents',
+							legacy: true,
+							type: 'collection',
+							description: 'Deprecated (legacy collection), please use the new knowledge base.',
+							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',
+								description: 'Deprecated (legacy collection), please use the new knowledge base.',
+								collection_names: legacy_documents
+									.filter((item) => (item?.meta?.tags ?? []).map((tag) => tag.name).includes(tag))
+									.map((item) => item.id)
+							}))
+					]
+				: [];
+
+		items = [...$knowledge, ...legacy_collections];
+
+		fuse = new Fuse(items, {
 			keys: ['name', 'description']
 		});
 	});
@@ -107,27 +139,33 @@
 							on:focus={() => {}}
 						>
 							<div class=" font-medium text-black dark:text-gray-100 flex items-center gap-1">
-								<div class="line-clamp-1">
-									{item.name}
-								</div>
-
-								{#if item?.meta?.document}
+								{#if item.legacy}
 									<div
-										class="bg-gray-500/20 text-gray-700 dark:text-gray-200 rounded uppercase text-xs px-1"
+										class="bg-gray-500/20 text-gray-700 dark:text-gray-200 rounded uppercase text-xs font-bold px-1"
+									>
+										Legacy
+									</div>
+								{:else if item?.meta?.document}
+									<div
+										class="bg-gray-500/20 text-gray-700 dark:text-gray-200 rounded uppercase text-xs font-bold px-1"
 									>
 										Document
 									</div>
 								{:else}
 									<div
-										class="bg-green-500/20 text-green-700 dark:text-green-200 rounded uppercase text-xs px-1"
+										class="bg-green-500/20 text-green-700 dark:text-green-200 rounded uppercase text-xs font-bold px-1"
 									>
 										Collection
 									</div>
 								{/if}
+
+								<div class="line-clamp-1">
+									{item.name}
+								</div>
 							</div>
 
 							<div class=" text-xs text-gray-600 dark:text-gray-100 line-clamp-1">
-								{item.description}
+								{item?.description}
 							</div>
 						</button>
 					{/each}

+ 5 - 1
src/lib/components/workspace/Knowledge.svelte

@@ -119,7 +119,11 @@
 			class=" flex space-x-4 cursor-pointer text-left w-full px-4 py-3 border border-gray-50 dark:border-gray-850 hover:bg-gray-50 dark:hover:bg-gray-850 rounded-xl"
 			on:click={() => {
 				if (item?.meta?.document) {
-					toast.error($i18n.t('Only collections can be edited, create a new knowledge instead.'));
+					toast.error(
+						$i18n.t(
+							'Only collections can be edited, create a new knowledge base to edit/add documents.'
+						)
+					);
 				} else {
 					goto(`/workspace/knowledge/${item.id}`);
 				}

+ 27 - 74
src/lib/components/workspace/Models/Knowledge.svelte

@@ -1,9 +1,9 @@
 <script lang="ts">
 	import { getContext } from 'svelte';
 	import Selector from './Knowledge/Selector.svelte';
+	import FileItem from '$lib/components/common/FileItem.svelte';
 
 	export let knowledge = [];
-
 	const i18n = getContext('i18n');
 </script>
 
@@ -13,91 +13,44 @@
 	</div>
 
 	<div class=" text-xs dark:text-gray-500">
-		{$i18n.t('To add documents here, upload them to the "Documents" workspace first.')}
+		{$i18n.t('To attach knowledge base here, add them to the "Knowledge" workspace first.')}
 	</div>
 
 	<div class="flex flex-col">
-		{#if knowledge.length > 0}
+		{#if knowledge?.length > 0}
 			<div class=" flex items-center gap-2 mt-2">
 				{#each knowledge as file, fileIdx}
-					<div class=" relative group">
-						<div
-							class="h-16 w-[15rem] flex items-center space-x-3 px-2.5 dark:bg-gray-600 rounded-xl border border-gray-200 dark:border-none"
-						>
-							<div class="p-2.5 bg-red-400 text-white rounded-lg">
-								{#if (file?.type ?? 'doc') === 'doc'}
-									<svg
-										xmlns="http://www.w3.org/2000/svg"
-										viewBox="0 0 24 24"
-										fill="currentColor"
-										class="size-6"
-									>
-										<path
-											fill-rule="evenodd"
-											d="M5.625 1.5c-1.036 0-1.875.84-1.875 1.875v17.25c0 1.035.84 1.875 1.875 1.875h12.75c1.035 0 1.875-.84 1.875-1.875V12.75A3.75 3.75 0 0 0 16.5 9h-1.875a1.875 1.875 0 0 1-1.875-1.875V5.25A3.75 3.75 0 0 0 9 1.5H5.625ZM7.5 15a.75.75 0 0 1 .75-.75h7.5a.75.75 0 0 1 0 1.5h-7.5A.75.75 0 0 1 7.5 15Zm.75 2.25a.75.75 0 0 0 0 1.5H12a.75.75 0 0 0 0-1.5H8.25Z"
-											clip-rule="evenodd"
-										/>
-										<path
-											d="M12.971 1.816A5.23 5.23 0 0 1 14.25 5.25v1.875c0 .207.168.375.375.375H16.5a5.23 5.23 0 0 1 3.434 1.279 9.768 9.768 0 0 0-6.963-6.963Z"
-										/>
-									</svg>
-								{:else if file.type === 'collection'}
-									<svg
-										xmlns="http://www.w3.org/2000/svg"
-										viewBox="0 0 24 24"
-										fill="currentColor"
-										class="size-6"
-									>
-										<path
-											d="M7.5 3.375c0-1.036.84-1.875 1.875-1.875h.375a3.75 3.75 0 0 1 3.75 3.75v1.875C13.5 8.161 14.34 9 15.375 9h1.875A3.75 3.75 0 0 1 21 12.75v3.375C21 17.16 20.16 18 19.125 18h-9.75A1.875 1.875 0 0 1 7.5 16.125V3.375Z"
-										/>
-										<path
-											d="M15 5.25a5.23 5.23 0 0 0-1.279-3.434 9.768 9.768 0 0 1 6.963 6.963A5.23 5.23 0 0 0 17.25 7.5h-1.875A.375.375 0 0 1 15 7.125V5.25ZM4.875 6H6v10.125A3.375 3.375 0 0 0 9.375 19.5H16.5v1.125c0 1.035-.84 1.875-1.875 1.875h-9.75A1.875 1.875 0 0 1 3 20.625V7.875C3 6.839 3.84 6 4.875 6Z"
-										/>
-									</svg>
-								{/if}
-							</div>
-
-							<div class="flex flex-col justify-center -space-y-0.5">
-								<div class=" dark:text-gray-100 text-sm font-medium line-clamp-1">
-									{file?.title ?? `#${file.name}`}
-								</div>
-
-								<div class=" text-gray-500 text-sm">{$i18n.t(file?.type ?? 'Document')}</div>
-							</div>
-						</div>
-
-						<div class=" absolute -top-1 -right-1">
-							<button
-								class=" bg-gray-400 text-white border border-white rounded-full group-hover:visible invisible transition"
-								type="button"
-								on:click={() => {
-									knowledge.splice(fileIdx, 1);
-									knowledge = knowledge;
-								}}
-							>
-								<svg
-									xmlns="http://www.w3.org/2000/svg"
-									viewBox="0 0 20 20"
-									fill="currentColor"
-									class="w-4 h-4"
-								>
-									<path
-										d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z"
-									/>
-								</svg>
-							</button>
-						</div>
-					</div>
+					<FileItem
+						{file}
+						dismissible
+						on:dismiss={(e) => {
+							knowledge = knowledge.filter((_, idx) => idx !== fileIdx);
+						}}
+					/>
 				{/each}
 			</div>
 		{/if}
 
 		<div class="flex flex-wrap text-sm font-medium gap-1.5 mt-2">
-			<Selector bind:knowledge>
+			<Selector
+				bind:knowledge
+				on:select={(e) => {
+					const item = e.detail;
+
+					if (!knowledge.find((k) => k.name === item.name)) {
+						knowledge = [
+							...knowledge,
+							{
+								...item,
+								type: item?.type ?? 'doc'
+							}
+						];
+					}
+				}}
+			>
 				<button
 					class=" px-3.5 py-1.5 font-medium hover:bg-black/5 dark:hover:bg-white/5 outline outline-1 outline-gray-300 dark:outline-gray-800 rounded-3xl"
-					type="button">{$i18n.t('Select Documents')}</button
+					type="button">{$i18n.t('Select Knowledge')}</button
 				>
 			</Selector>
 		</div>

+ 54 - 67
src/lib/components/workspace/Models/Knowledge/Selector.svelte

@@ -1,35 +1,48 @@
 <script lang="ts">
 	import { DropdownMenu } from 'bits-ui';
-	import { onMount, getContext } from 'svelte';
+	import { onMount, getContext, createEventDispatcher } from 'svelte';
 	import { flyAndScale } from '$lib/utils/transitions';
-
 	import { knowledge } from '$lib/stores';
 	import Dropdown from '$lib/components/common/Dropdown.svelte';
 
 	const i18n = getContext('i18n');
+	const dispatch = createEventDispatcher();
 
 	export let onClose: Function = () => {};
 
-	export let _knowledge = [];
-
 	let items = [];
 
 	onMount(() => {
-		let collections = [
-			...$knowledge
-				.reduce((a, e, i, arr) => {
-					return [...new Set([...a, ...(e?.content?.tags ?? []).map((tag) => tag.name)])];
-				}, [])
-				.map((tag) => ({
-					name: tag,
-					type: 'collection',
-					collection_names: $knowledge
-						.filter((doc) => (doc?.content?.tags ?? []).map((tag) => tag.name).includes(tag))
-						.map((doc) => doc.collection_name)
-				}))
-		];
+		let legacy_documents = $knowledge.filter((item) => item?.meta?.document);
+		let legacy_collections =
+			legacy_documents.length > 0
+				? [
+						{
+							name: 'All Documents',
+							legacy: true,
+							type: 'collection',
+							description: 'Deprecated (legacy collection), please use the new knowledge base.',
+							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',
+								description: 'Deprecated (legacy collection), please use the new knowledge base.',
+								collection_names: legacy_documents
+									.filter((item) => (item?.meta?.tags ?? []).map((tag) => tag.name).includes(tag))
+									.map((item) => item.id)
+							}))
+					]
+				: [];
 
-		items = [...collections, ...$knowledge];
+		items = [...$knowledge, ...legacy_collections];
 	});
 </script>
 
@@ -44,7 +57,7 @@
 
 	<div slot="content">
 		<DropdownMenu.Content
-			class="w-full max-w-[300px]  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"
+			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"
 			sideOffset={8}
 			side="bottom"
 			align="start"
@@ -53,64 +66,38 @@
 			<div class="max-h-[10rem] overflow-y-scroll">
 				{#if items.length === 0}
 					<div class="text-center text-sm text-gray-500 dark:text-gray-400">
-						{$i18n.t('No documents found')}
+						{$i18n.t('No knowledge found')}
 					</div>
 				{:else}
 					{#each items as item}
 						<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={() => {
-								if (!_knowledge.find((k) => k.name === item.name)) {
-									_knowledge = [
-										..._knowledge,
-										{
-											...item,
-											type: item?.type ?? 'doc'
-										}
-									];
-								}
+								dispatch('select', item);
 							}}
 						>
-							<div class="flex self-start">
-								{#if (item?.type ?? 'doc') === 'doc'}
-									<svg
-										xmlns="http://www.w3.org/2000/svg"
-										viewBox="0 0 24 24"
-										fill="currentColor"
-										class="w-4"
-									>
-										<path
-											fill-rule="evenodd"
-											d="M5.625 1.5c-1.036 0-1.875.84-1.875 1.875v17.25c0 1.035.84 1.875 1.875 1.875h12.75c1.035 0 1.875-.84 1.875-1.875V12.75A3.75 3.75 0 0 0 16.5 9h-1.875a1.875 1.875 0 0 1-1.875-1.875V5.25A3.75 3.75 0 0 0 9 1.5H5.625ZM7.5 15a.75.75 0 0 1 .75-.75h7.5a.75.75 0 0 1 0 1.5h-7.5A.75.75 0 0 1 7.5 15Zm.75 2.25a.75.75 0 0 0 0 1.5H12a.75.75 0 0 0 0-1.5H8.25Z"
-											clip-rule="evenodd"
-										/>
-										<path
-											d="M12.971 1.816A5.23 5.23 0 0 1 14.25 5.25v1.875c0 .207.168.375.375.375H16.5a5.23 5.23 0 0 1 3.434 1.279 9.768 9.768 0 0 0-6.963-6.963Z"
-										/>
-									</svg>
-								{:else if item.type === 'collection'}
-									<svg
-										xmlns="http://www.w3.org/2000/svg"
-										viewBox="0 0 24 24"
-										fill="currentColor"
-										class="size-4"
-									>
-										<path
-											d="M7.5 3.375c0-1.036.84-1.875 1.875-1.875h.375a3.75 3.75 0 0 1 3.75 3.75v1.875C13.5 8.161 14.34 9 15.375 9h1.875A3.75 3.75 0 0 1 21 12.75v3.375C21 17.16 20.16 18 19.125 18h-9.75A1.875 1.875 0 0 1 7.5 16.125V3.375Z"
-										/>
-										<path
-											d="M15 5.25a5.23 5.23 0 0 0-1.279-3.434 9.768 9.768 0 0 1 6.963 6.963A5.23 5.23 0 0 0 17.25 7.5h-1.875A.375.375 0 0 1 15 7.125V5.25ZM4.875 6H6v10.125A3.375 3.375 0 0 0 9.375 19.5H16.5v1.125c0 1.035-.84 1.875-1.875 1.875h-9.75A1.875 1.875 0 0 1 3 20.625V7.875C3 6.839 3.84 6 4.875 6Z"
-										/>
-									</svg>
-								{/if}
-							</div>
-
 							<div class="flex items-center">
 								<div class="flex flex-col">
-									<div
-										class=" w-fit text-xs font-bold px-1 rounded uppercase line-clamp-1 bg-gray-500/20 text-gray-700 dark:text-gray-200"
-									>
-										{item?.type ?? 'Document'}
+									<div class=" w-fit mb-0.5">
+										{#if item.legacy}
+											<div
+												class="bg-gray-500/20 text-gray-700 dark:text-gray-200 rounded uppercase text-xs font-bold px-1"
+											>
+												Legacy
+											</div>
+										{:else if item?.meta?.document}
+											<div
+												class="bg-gray-500/20 text-gray-700 dark:text-gray-200 rounded uppercase text-xs font-bold px-1"
+											>
+												Document
+											</div>
+										{:else}
+											<div
+												class="bg-green-500/20 text-green-700 dark:text-green-200 rounded uppercase text-xs font-bold px-1"
+											>
+												Collection
+											</div>
+										{/if}
 									</div>
 
 									<div class="line-clamp-1 font-medium pr-0.5">