浏览代码

feat: model tag support

Timothy J. Baek 11 月之前
父节点
当前提交
eca20b1b2c

+ 1 - 1
src/lib/components/common/Banner.svelte

@@ -39,7 +39,7 @@
 {#if !dismissed}
 {#if !dismissed}
 	{#if mounted}
 	{#if mounted}
 		<div
 		<div
-			class=" top-0 left-0 right-0 p-2 mx-4 px-3 flex justify-center items-center relative rounded-xl border border-gray-100 dark:border-gray-850 text-gray-800 dark:text-gary-100 bg-white dark:bg-gray-900 backdrop-blur-xl z-40"
+			class=" top-0 left-0 right-0 p-2 mx-4 px-3 flex justify-center items-center relative rounded-xl border border-gray-50 dark:border-gray-850 text-gray-800 dark:text-gary-100 bg-white dark:bg-gray-900 backdrop-blur-xl z-40"
 			transition:fade={{ delay: 100, duration: 300 }}
 			transition:fade={{ delay: 100, duration: 300 }}
 		>
 		>
 			<div class=" flex flex-col md:flex-row md:items-center flex-1 text-sm w-fit gap-1.5">
 			<div class=" flex flex-col md:flex-row md:items-center flex-1 text-sm w-fit gap-1.5">

+ 1 - 0
src/lib/components/common/Dropdown.svelte

@@ -14,6 +14,7 @@
 	onOpenChange={(state) => {
 	onOpenChange={(state) => {
 		dispatch('change', state);
 		dispatch('change', state);
 	}}
 	}}
+	typeahead={false}
 >
 >
 	<DropdownMenu.Trigger>
 	<DropdownMenu.Trigger>
 		<slot />
 		<slot />

+ 1 - 1
src/lib/components/common/Tags.svelte

@@ -11,7 +11,7 @@
 	export let addTag: Function;
 	export let addTag: Function;
 </script>
 </script>
 
 
-<div class="flex flex-row flex-wrap gap-0.5 line-clamp-1">
+<div class="flex flex-row flex-wrap gap-1 line-clamp-1">
 	<TagList
 	<TagList
 		{tags}
 		{tags}
 		on:delete={(e) => {
 		on:delete={(e) => {

+ 20 - 18
src/lib/components/common/Tags/TagInput.svelte

@@ -22,26 +22,12 @@
 	};
 	};
 </script>
 </script>
 
 
-<div class="flex space-x-1 pl-1.5">
+<div class="flex {showTagInput ? 'flex-row-reverse' : ''}">
 	{#if showTagInput}
 	{#if showTagInput}
 		<div class="flex items-center">
 		<div class="flex items-center">
-			<button type="button" on:click={addTagHandler}>
-				<svg
-					xmlns="http://www.w3.org/2000/svg"
-					viewBox="0 0 16 16"
-					fill="currentColor"
-					class="w-3 h-3"
-				>
-					<path
-						fill-rule="evenodd"
-						d="M12.416 3.376a.75.75 0 0 1 .208 1.04l-5 7.5a.75.75 0 0 1-1.154.114l-3-3a.75.75 0 0 1 1.06-1.06l2.353 2.353 4.493-6.74a.75.75 0 0 1 1.04-.207Z"
-						clip-rule="evenodd"
-					/>
-				</svg>
-			</button>
 			<input
 			<input
 				bind:value={tagName}
 				bind:value={tagName}
-				class=" pl-2 cursor-pointer self-center text-xs h-fit bg-transparent outline-none line-clamp-1 w-[5.5rem]"
+				class=" px-2 cursor-pointer self-center text-xs h-fit bg-transparent outline-none line-clamp-1 w-[5.5rem]"
 				placeholder={$i18n.t('Add a tag')}
 				placeholder={$i18n.t('Add a tag')}
 				list="tagOptions"
 				list="tagOptions"
 				on:keydown={(event) => {
 				on:keydown={(event) => {
@@ -55,11 +41,27 @@
 					<option value={tag.name} />
 					<option value={tag.name} />
 				{/each}
 				{/each}
 			</datalist>
 			</datalist>
+
+			<button type="button" on:click={addTagHandler}>
+				<svg
+					xmlns="http://www.w3.org/2000/svg"
+					viewBox="0 0 16 16"
+					fill="currentColor"
+					stroke-width="2"
+					class="w-3 h-3"
+				>
+					<path
+						fill-rule="evenodd"
+						d="M12.416 3.376a.75.75 0 0 1 .208 1.04l-5 7.5a.75.75 0 0 1-1.154.114l-3-3a.75.75 0 0 1 1.06-1.06l2.353 2.353 4.493-6.74a.75.75 0 0 1 1.04-.207Z"
+						clip-rule="evenodd"
+					/>
+				</svg>
+			</button>
 		</div>
 		</div>
 	{/if}
 	{/if}
 
 
 	<button
 	<button
-		class=" cursor-pointer self-center p-0.5 space-x-1 flex h-fit items-center dark:hover:bg-gray-700 rounded-full transition border dark:border-gray-600 border-dashed"
+		class=" cursor-pointer self-center p-0.5 flex h-fit items-center dark:hover:bg-gray-700 rounded-full transition border dark:border-gray-600 border-dashed"
 		type="button"
 		type="button"
 		on:click={() => {
 		on:click={() => {
 			showTagInput = !showTagInput;
 			showTagInput = !showTagInput;
@@ -80,6 +82,6 @@
 	</button>
 	</button>
 
 
 	{#if label && !showTagInput}
 	{#if label && !showTagInput}
-		<span class="text-xs pl-1.5 self-center">{label}</span>
+		<span class="text-xs pl-2 self-center">{label}</span>
 	{/if}
 	{/if}
 </div>
 </div>

+ 4 - 3
src/lib/components/common/Tags/TagList.svelte

@@ -7,22 +7,23 @@
 
 
 {#each tags as tag}
 {#each tags as tag}
 	<div
 	<div
-		class="px-2 py-0.5 space-x-1 flex h-fit items-center rounded-full transition border dark:border-gray-800 dark:text-white"
+		class="px-2 py-[0.5px] gap-0.5 flex justify-between h-fit items-center rounded-full transition border dark:border-gray-800 dark:text-white"
 	>
 	>
 		<div class=" text-[0.7rem] font-medium self-center line-clamp-1">
 		<div class=" text-[0.7rem] font-medium self-center line-clamp-1">
 			{tag.name}
 			{tag.name}
 		</div>
 		</div>
 		<button
 		<button
-			class=" m-auto self-center cursor-pointer"
+			class="h-full flex self-center cursor-pointer"
 			on:click={() => {
 			on:click={() => {
 				dispatch('delete', tag.name);
 				dispatch('delete', tag.name);
 			}}
 			}}
+			type="button"
 		>
 		>
 			<svg
 			<svg
 				xmlns="http://www.w3.org/2000/svg"
 				xmlns="http://www.w3.org/2000/svg"
 				viewBox="0 0 16 16"
 				viewBox="0 0 16 16"
 				fill="currentColor"
 				fill="currentColor"
-				class="w-3 h-3"
+				class="size-3 m-auto self-center translate-y-[0.3px] translate-x-[3px]"
 			>
 			>
 				<path
 				<path
 					d="M5.28 4.22a.75.75 0 0 0-1.06 1.06L6.94 8l-2.72 2.72a.75.75 0 1 0 1.06 1.06L8 9.06l2.72 2.72a.75.75 0 1 0 1.06-1.06L9.06 8l2.72-2.72a.75.75 0 0 0-1.06-1.06L8 6.94 5.28 4.22Z"
 					d="M5.28 4.22a.75.75 0 0 0-1.06 1.06L6.94 8l-2.72 2.72a.75.75 0 1 0 1.06 1.06L8 9.06l2.72 2.72a.75.75 0 1 0 1.06-1.06L9.06 8l2.72-2.72a.75.75 0 0 0-1.06-1.06L8 6.94 5.28 4.22Z"

+ 59 - 11
src/routes/(app)/workspace/models/create/+page.svelte

@@ -10,6 +10,7 @@
 
 
 	import AdvancedParams from '$lib/components/chat/Settings/Advanced/AdvancedParams.svelte';
 	import AdvancedParams from '$lib/components/chat/Settings/Advanced/AdvancedParams.svelte';
 	import Checkbox from '$lib/components/common/Checkbox.svelte';
 	import Checkbox from '$lib/components/common/Checkbox.svelte';
+	import Tags from '$lib/components/common/Tags.svelte';
 
 
 	const i18n = getContext('i18n');
 	const i18n = getContext('i18n');
 
 
@@ -262,7 +263,7 @@
 				<button
 				<button
 					class=" {info.meta.profile_image_url
 					class=" {info.meta.profile_image_url
 						? ''
 						? ''
-						: 'p-6'} rounded-full dark:bg-gray-700 border border-dashed border-gray-200"
+						: 'p-4'} rounded-full dark:bg-gray-700 border border-dashed border-gray-200 flex items-center"
 					type="button"
 					type="button"
 					on:click={() => {
 					on:click={() => {
 						filesInputElement.click();
 						filesInputElement.click();
@@ -272,7 +273,7 @@
 						<img
 						<img
 							src={info.meta.profile_image_url}
 							src={info.meta.profile_image_url}
 							alt="modelfile profile"
 							alt="modelfile profile"
-							class=" rounded-full w-20 h-20 object-cover"
+							class=" rounded-full size-16 object-cover"
 						/>
 						/>
 					{:else}
 					{:else}
 						<svg
 						<svg
@@ -338,18 +339,40 @@
 			</div>
 			</div>
 		</div>
 		</div>
 
 
-		<div class="my-2">
-			<div class=" text-sm font-semibold mb-2">{$i18n.t('Description')}</div>
+		<div class="my-1">
+			<div class="flex w-full justify-between items-center mb-1">
+				<div class=" self-center text-sm font-semibold">{$i18n.t('Description')}</div>
 
 
-			<div>
+				<button
+					class="p-1 text-xs flex rounded transition"
+					type="button"
+					on:click={() => {
+						if (info.meta.description === null) {
+							info.meta.description = '';
+						} else {
+							info.meta.description = null;
+						}
+					}}
+				>
+					{#if info.meta.description === null}
+						<span class="ml-2 self-center">{$i18n.t('Default')}</span>
+					{:else}
+						<span class="ml-2 self-center">{$i18n.t('Custom')}</span>
+					{/if}
+				</button>
+			</div>
+
+			{#if info.meta.description !== null}
 				<input
 				<input
 					class="px-3 py-1.5 text-sm w-full bg-transparent border dark:border-gray-600 outline-none rounded-lg"
 					class="px-3 py-1.5 text-sm w-full bg-transparent border dark:border-gray-600 outline-none rounded-lg"
 					placeholder={$i18n.t('Add a short description about what this model does')}
 					placeholder={$i18n.t('Add a short description about what this model does')}
 					bind:value={info.meta.description}
 					bind:value={info.meta.description}
 				/>
 				/>
-			</div>
+			{/if}
 		</div>
 		</div>
 
 
+		<hr class=" dark:border-gray-850 my-1" />
+
 		<div class="my-2">
 		<div class="my-2">
 			<div class="flex w-full justify-between">
 			<div class="flex w-full justify-between">
 				<div class=" self-center text-sm font-semibold">{$i18n.t('Model Params')}</div>
 				<div class=" self-center text-sm font-semibold">{$i18n.t('Model Params')}</div>
@@ -401,7 +424,9 @@
 			</div>
 			</div>
 		</div>
 		</div>
 
 
-		<div class="my-2">
+		<hr class=" dark:border-gray-850 my-1" />
+
+		<div class="my-1">
 			<div class="flex w-full justify-between items-center">
 			<div class="flex w-full justify-between items-center">
 				<div class="flex w-full justify-between items-center">
 				<div class="flex w-full justify-between items-center">
 					<div class=" self-center text-sm font-semibold">{$i18n.t('Prompt suggestions')}</div>
 					<div class=" self-center text-sm font-semibold">{$i18n.t('Prompt suggestions')}</div>
@@ -491,8 +516,8 @@
 			{/if}
 			{/if}
 		</div>
 		</div>
 
 
-		<div class="my-2">
-			<div class="flex w-full justify-between">
+		<div class="my-1">
+			<div class="flex w-full justify-between mb-1">
 				<div class=" self-center text-sm font-semibold">{$i18n.t('Capabilities')}</div>
 				<div class=" self-center text-sm font-semibold">{$i18n.t('Capabilities')}</div>
 			</div>
 			</div>
 			<div class="flex flex-col">
 			<div class="flex flex-col">
@@ -505,7 +530,7 @@
 							}}
 							}}
 						/>
 						/>
 
 
-						<div class=" py-1.5 text-sm w-full capitalize">
+						<div class=" py-0.5 text-sm w-full capitalize">
 							{$i18n.t(capability)}
 							{$i18n.t(capability)}
 						</div>
 						</div>
 					</div>
 					</div>
@@ -513,7 +538,30 @@
 			</div>
 			</div>
 		</div>
 		</div>
 
 
-		<div class="my-2 text-gray-500">
+		<div class="my-1">
+			<div class="flex w-full justify-between items-center">
+				<div class=" self-center text-sm font-semibold">{$i18n.t('Tags')}</div>
+			</div>
+
+			<div class="mt-2">
+				<Tags
+					tags={info?.meta?.tags ?? []}
+					deleteTag={(tagName) => {
+						info.meta.tags = info.meta.tags.filter((tag) => tag.name !== tagName);
+					}}
+					addTag={(tagName) => {
+						console.log(tagName);
+						if (!(info?.meta?.tags ?? null)) {
+							info.meta.tags = [{ name: tagName }];
+						} else {
+							info.meta.tags = [...info.meta.tags, { name: tagName }];
+						}
+					}}
+				/>
+			</div>
+		</div>
+
+		<div class="my-2 text-gray-300 dark:text-gray-700">
 			<div class="flex w-full justify-between mb-2">
 			<div class="flex w-full justify-between mb-2">
 				<div class=" self-center text-sm font-semibold">{$i18n.t('JSON Preview')}</div>
 				<div class=" self-center text-sm font-semibold">{$i18n.t('JSON Preview')}</div>
 
 

+ 69 - 20
src/routes/(app)/workspace/models/edit/+page.svelte

@@ -13,6 +13,7 @@
 	import AdvancedParams from '$lib/components/chat/Settings/Advanced/AdvancedParams.svelte';
 	import AdvancedParams from '$lib/components/chat/Settings/Advanced/AdvancedParams.svelte';
 	import { getModels } from '$lib/apis';
 	import { getModels } from '$lib/apis';
 	import Checkbox from '$lib/components/common/Checkbox.svelte';
 	import Checkbox from '$lib/components/common/Checkbox.svelte';
+	import Tags from '$lib/components/common/Tags.svelte';
 
 
 	const i18n = getContext('i18n');
 	const i18n = getContext('i18n');
 
 
@@ -44,7 +45,8 @@
 		meta: {
 		meta: {
 			profile_image_url: '/favicon.png',
 			profile_image_url: '/favicon.png',
 			description: '',
 			description: '',
-			suggestion_prompts: null
+			suggestion_prompts: null,
+			tags: []
 		},
 		},
 		params: {
 		params: {
 			system: ''
 			system: ''
@@ -223,26 +225,26 @@
 			<div class="flex justify-center my-4">
 			<div class="flex justify-center my-4">
 				<div class="self-center">
 				<div class="self-center">
 					<button
 					<button
-						class=" {info?.meta?.profile_image_url
+						class=" {info.meta.profile_image_url
 							? ''
 							? ''
-							: 'p-6'} rounded-full dark:bg-gray-700 border border-dashed border-gray-200"
+							: 'p-4'} rounded-full dark:bg-gray-700 border border-dashed border-gray-200 flex items-center"
 						type="button"
 						type="button"
 						on:click={() => {
 						on:click={() => {
 							filesInputElement.click();
 							filesInputElement.click();
 						}}
 						}}
 					>
 					>
-						{#if info?.meta?.profile_image_url}
+						{#if info.meta.profile_image_url}
 							<img
 							<img
-								src={info?.meta?.profile_image_url}
+								src={info.meta.profile_image_url}
 								alt="modelfile profile"
 								alt="modelfile profile"
-								class=" rounded-full w-20 h-20 object-cover"
+								class=" rounded-full size-16 object-cover"
 							/>
 							/>
 						{:else}
 						{:else}
 							<svg
 							<svg
 								xmlns="http://www.w3.org/2000/svg"
 								xmlns="http://www.w3.org/2000/svg"
 								viewBox="0 0 24 24"
 								viewBox="0 0 24 24"
 								fill="currentColor"
 								fill="currentColor"
-								class="w-8"
+								class="size-8"
 							>
 							>
 								<path
 								<path
 									fill-rule="evenodd"
 									fill-rule="evenodd"
@@ -255,9 +257,9 @@
 				</div>
 				</div>
 			</div>
 			</div>
 
 
-			<div class="my-2 flex space-x-2">
+			<div class="mt-2 my-1 flex space-x-2">
 				<div class="flex-1">
 				<div class="flex-1">
-					<div class=" text-sm font-semibold mb-2">{$i18n.t('Name')}*</div>
+					<div class=" text-sm font-semibold mb-1">{$i18n.t('Name')}*</div>
 
 
 					<div>
 					<div>
 						<input
 						<input
@@ -270,7 +272,7 @@
 				</div>
 				</div>
 
 
 				<div class="flex-1">
 				<div class="flex-1">
-					<div class=" text-sm font-semibold mb-2">{$i18n.t('Model ID')}*</div>
+					<div class=" text-sm font-semibold mb-1">{$i18n.t('Model ID')}*</div>
 
 
 					<div>
 					<div>
 						<input
 						<input
@@ -285,8 +287,8 @@
 			</div>
 			</div>
 
 
 			{#if model.preset}
 			{#if model.preset}
-				<div class="my-2">
-					<div class=" text-sm font-semibold mb-2">{$i18n.t('Base Model (From)')}</div>
+				<div class="my-1">
+					<div class=" text-sm font-semibold mb-1">{$i18n.t('Base Model (From)')}</div>
 
 
 					<div>
 					<div>
 						<select
 						<select
@@ -304,18 +306,40 @@
 				</div>
 				</div>
 			{/if}
 			{/if}
 
 
-			<div class="my-2">
-				<div class=" text-sm font-semibold mb-2">{$i18n.t('Description')}</div>
+			<div class="my-1">
+				<div class="flex w-full justify-between items-center">
+					<div class=" self-center text-sm font-semibold">{$i18n.t('Description')}</div>
+
+					<button
+						class="p-1 text-xs flex rounded transition"
+						type="button"
+						on:click={() => {
+							if (info.meta.description === null) {
+								info.meta.description = '';
+							} else {
+								info.meta.description = null;
+							}
+						}}
+					>
+						{#if info.meta.description === null}
+							<span class="ml-2 self-center">{$i18n.t('Default')}</span>
+						{:else}
+							<span class="ml-2 self-center">{$i18n.t('Custom')}</span>
+						{/if}
+					</button>
+				</div>
 
 
-				<div>
+				{#if info.meta.description !== null}
 					<input
 					<input
-						class="px-3 py-1.5 text-sm w-full bg-transparent border dark:border-gray-600 outline-none rounded-lg"
+						class="mt-1 px-3 py-1.5 text-sm w-full bg-transparent border dark:border-gray-600 outline-none rounded-lg"
 						placeholder={$i18n.t('Add a short description about what this model does')}
 						placeholder={$i18n.t('Add a short description about what this model does')}
 						bind:value={info.meta.description}
 						bind:value={info.meta.description}
 					/>
 					/>
-				</div>
+				{/if}
 			</div>
 			</div>
 
 
+			<hr class=" dark:border-gray-850 my-1" />
+
 			<div class="my-2">
 			<div class="my-2">
 				<div class="flex w-full justify-between">
 				<div class="flex w-full justify-between">
 					<div class=" self-center text-sm font-semibold">{$i18n.t('Model Params')}</div>
 					<div class=" self-center text-sm font-semibold">{$i18n.t('Model Params')}</div>
@@ -369,7 +393,9 @@
 				</div>
 				</div>
 			</div>
 			</div>
 
 
-			<div class="my-2">
+			<hr class=" dark:border-gray-850 my-1" />
+
+			<div class="my-1">
 				<div class="flex w-full justify-between items-center">
 				<div class="flex w-full justify-between items-center">
 					<div class="flex w-full justify-between items-center">
 					<div class="flex w-full justify-between items-center">
 						<div class=" self-center text-sm font-semibold">{$i18n.t('Prompt suggestions')}</div>
 						<div class=" self-center text-sm font-semibold">{$i18n.t('Prompt suggestions')}</div>
@@ -459,7 +485,7 @@
 				{/if}
 				{/if}
 			</div>
 			</div>
 
 
-			<div class="my-2">
+			<div class="my-1">
 				<div class="flex w-full justify-between mb-1">
 				<div class="flex w-full justify-between mb-1">
 					<div class=" self-center text-sm font-semibold">{$i18n.t('Capabilities')}</div>
 					<div class=" self-center text-sm font-semibold">{$i18n.t('Capabilities')}</div>
 				</div>
 				</div>
@@ -481,7 +507,30 @@
 				</div>
 				</div>
 			</div>
 			</div>
 
 
-			<div class="my-2 text-gray-500">
+			<div class="my-1">
+				<div class="flex w-full justify-between items-center">
+					<div class=" self-center text-sm font-semibold">{$i18n.t('Tags')}</div>
+				</div>
+
+				<div class="mt-2">
+					<Tags
+						tags={info?.meta?.tags ?? []}
+						deleteTag={(tagName) => {
+							info.meta.tags = info.meta.tags.filter((tag) => tag.name !== tagName);
+						}}
+						addTag={(tagName) => {
+							console.log(tagName);
+							if (!(info?.meta?.tags ?? null)) {
+								info.meta.tags = [{ name: tagName }];
+							} else {
+								info.meta.tags = [...info.meta.tags, { name: tagName }];
+							}
+						}}
+					/>
+				</div>
+			</div>
+
+			<div class="my-2 text-gray-300 dark:text-gray-700">
 				<div class="flex w-full justify-between mb-2">
 				<div class="flex w-full justify-between mb-2">
 					<div class=" self-center text-sm font-semibold">{$i18n.t('JSON Preview')}</div>
 					<div class=" self-center text-sm font-semibold">{$i18n.t('JSON Preview')}</div>