Explorar o código

feat: chat controls integration

Timothy J. Baek hai 10 meses
pai
achega
30e2ec7544

+ 34 - 30
src/lib/components/chat/Chat.svelte

@@ -97,6 +97,8 @@
 		currentId: null
 		currentId: null
 	};
 	};
 
 
+	let params = {};
+
 	$: if (history.currentId !== null) {
 	$: if (history.currentId !== null) {
 		let _messages = [];
 		let _messages = [];
 
 
@@ -230,6 +232,7 @@
 			messages: {},
 			messages: {},
 			currentId: null
 			currentId: null
 		};
 		};
+		params = {};
 
 
 		if ($page.url.searchParams.get('models')) {
 		if ($page.url.searchParams.get('models')) {
 			selectedModels = $page.url.searchParams.get('models')?.split(',');
 			selectedModels = $page.url.searchParams.get('models')?.split(',');
@@ -299,11 +302,7 @@
 					await settings.set(JSON.parse(localStorage.getItem('settings') ?? '{}'));
 					await settings.set(JSON.parse(localStorage.getItem('settings') ?? '{}'));
 				}
 				}
 
 
-				await settings.set({
-					...$settings,
-					system: chatContent.system ?? $settings.system,
-					params: chatContent.options ?? $settings.params
-				});
+				params = chatContent?.params ?? {};
 
 
 				autoScroll = true;
 				autoScroll = true;
 				await tick();
 				await tick();
@@ -516,9 +515,7 @@
 					title: $i18n.t('New Chat'),
 					title: $i18n.t('New Chat'),
 					models: selectedModels,
 					models: selectedModels,
 					system: $settings.system ?? undefined,
 					system: $settings.system ?? undefined,
-					options: {
-						...($settings.params ?? {})
-					},
+					params: params,
 					messages: messages,
 					messages: messages,
 					history: history,
 					history: history,
 					tags: [],
 					tags: [],
@@ -616,11 +613,11 @@
 		scrollToBottom();
 		scrollToBottom();
 
 
 		const messagesBody = [
 		const messagesBody = [
-			$settings.system || (responseMessage?.userContext ?? null)
+			params?.system || $settings.system || (responseMessage?.userContext ?? null)
 				? {
 				? {
 						role: 'system',
 						role: 'system',
 						content: `${promptTemplate(
 						content: `${promptTemplate(
-							$settings?.system ?? '',
+							params?.system ?? $settings?.system ?? '',
 							$user.name,
 							$user.name,
 							$settings?.userLocation
 							$settings?.userLocation
 								? await getAndUpdateUserLocation(localStorage.token)
 								? await getAndUpdateUserLocation(localStorage.token)
@@ -705,15 +702,16 @@
 			model: model.id,
 			model: model.id,
 			messages: messagesBody,
 			messages: messagesBody,
 			options: {
 			options: {
-				...($settings.params ?? {}),
+				...(params ?? $settings.params ?? {}),
 				stop:
 				stop:
-					$settings?.params?.stop ?? undefined
-						? $settings.params.stop.map((str) =>
+					params?.stop ?? $settings?.params?.stop ?? undefined
+						? (params?.stop ?? $settings.params.stop).map((str) =>
 								decodeURIComponent(JSON.parse('"' + str.replace(/\"/g, '\\"') + '"'))
 								decodeURIComponent(JSON.parse('"' + str.replace(/\"/g, '\\"') + '"'))
 						  )
 						  )
 						: undefined,
 						: undefined,
-				num_predict: $settings?.params?.max_tokens ?? undefined,
-				repeat_penalty: $settings?.params?.frequency_penalty ?? undefined
+				num_predict: params?.max_tokens ?? $settings?.params?.max_tokens ?? undefined,
+				repeat_penalty:
+					params?.frequency_penalty ?? $settings?.params?.frequency_penalty ?? undefined
 			},
 			},
 			format: $settings.requestFormat ?? undefined,
 			format: $settings.requestFormat ?? undefined,
 			keep_alive: $settings.keepAlive ?? undefined,
 			keep_alive: $settings.keepAlive ?? undefined,
@@ -849,7 +847,8 @@
 					chat = await updateChatById(localStorage.token, _chatId, {
 					chat = await updateChatById(localStorage.token, _chatId, {
 						messages: messages,
 						messages: messages,
 						history: history,
 						history: history,
-						models: selectedModels
+						models: selectedModels,
+						params: params
 					});
 					});
 					await chats.set(await getChatList(localStorage.token));
 					await chats.set(await getChatList(localStorage.token));
 				}
 				}
@@ -959,11 +958,11 @@
 							  }
 							  }
 							: undefined,
 							: undefined,
 					messages: [
 					messages: [
-						$settings.system || (responseMessage?.userContext ?? null)
+						params?.system || $settings.system || (responseMessage?.userContext ?? null)
 							? {
 							? {
 									role: 'system',
 									role: 'system',
 									content: `${promptTemplate(
 									content: `${promptTemplate(
-										$settings?.system ?? '',
+										params?.system ?? $settings?.system ?? '',
 										$user.name,
 										$user.name,
 										$settings?.userLocation
 										$settings?.userLocation
 											? await getAndUpdateUserLocation(localStorage.token)
 											? await getAndUpdateUserLocation(localStorage.token)
@@ -1008,17 +1007,18 @@
 												: message?.raContent ?? message.content
 												: message?.raContent ?? message.content
 								  })
 								  })
 						})),
 						})),
-					seed: $settings?.params?.seed ?? undefined,
+					seed: params?.seed ?? $settings?.params?.seed ?? undefined,
 					stop:
 					stop:
-						$settings?.params?.stop ?? undefined
-							? $settings.params.stop.map((str) =>
+						params?.stop ?? $settings?.params?.stop ?? undefined
+							? (params?.stop ?? $settings.params.stop).map((str) =>
 									decodeURIComponent(JSON.parse('"' + str.replace(/\"/g, '\\"') + '"'))
 									decodeURIComponent(JSON.parse('"' + str.replace(/\"/g, '\\"') + '"'))
 							  )
 							  )
 							: undefined,
 							: undefined,
-					temperature: $settings?.params?.temperature ?? undefined,
-					top_p: $settings?.params?.top_p ?? undefined,
-					frequency_penalty: $settings?.params?.frequency_penalty ?? undefined,
-					max_tokens: $settings?.params?.max_tokens ?? undefined,
+					temperature: params?.temperature ?? $settings?.params?.temperature ?? undefined,
+					top_p: params?.top_p ?? $settings?.params?.top_p ?? undefined,
+					frequency_penalty:
+						params?.frequency_penalty ?? $settings?.params?.frequency_penalty ?? undefined,
+					max_tokens: params?.max_tokens ?? $settings?.params?.max_tokens ?? undefined,
 					tool_ids: selectedToolIds.length > 0 ? selectedToolIds : undefined,
 					tool_ids: selectedToolIds.length > 0 ? selectedToolIds : undefined,
 					files: files.length > 0 ? files : undefined,
 					files: files.length > 0 ? files : undefined,
 					session_id: $socket?.id,
 					session_id: $socket?.id,
@@ -1124,7 +1124,8 @@
 						chat = await updateChatById(localStorage.token, _chatId, {
 						chat = await updateChatById(localStorage.token, _chatId, {
 							models: selectedModels,
 							models: selectedModels,
 							messages: messages,
 							messages: messages,
-							history: history
+							history: history,
+							params: params
 						});
 						});
 						await chats.set(await getChatList(localStorage.token));
 						await chats.set(await getChatList(localStorage.token));
 					}
 					}
@@ -1460,9 +1461,11 @@
 			</div>
 			</div>
 		{/if}
 		{/if}
 
 
-		<div class="flex flex-col flex-auto z-10 {showControls ? 'lg:pr-[24rem]' : ''}">
+		<div class="flex flex-col flex-auto z-10">
 			<div
 			<div
-				class=" pb-2.5 flex flex-col justify-between w-full flex-auto overflow-auto h-0 max-w-full z-10 scrollbar-hidden"
+				class=" pb-2.5 flex flex-col justify-between w-full flex-auto overflow-auto h-0 max-w-full z-10 scrollbar-hidden {showControls
+					? 'lg:pr-[24rem]'
+					: ''}"
 				id="messages-container"
 				id="messages-container"
 				bind:this={messagesContainerElement}
 				bind:this={messagesContainerElement}
 				on:scroll={(e) => {
 				on:scroll={(e) => {
@@ -1488,7 +1491,7 @@
 				</div>
 				</div>
 			</div>
 			</div>
 
 
-			<div class="">
+			<div class={showControls ? 'lg:pr-[24rem]' : ''}>
 				<MessageInput
 				<MessageInput
 					bind:files
 					bind:files
 					bind:prompt
 					bind:prompt
@@ -1511,6 +1514,7 @@
 				/>
 				/>
 			</div>
 			</div>
 		</div>
 		</div>
-		<ChatControls bind:show={showControls} />
+
+		<ChatControls bind:show={showControls} bind:params />
 	</div>
 	</div>
 {/if}
 {/if}

+ 7 - 3
src/lib/components/chat/ChatControls.svelte

@@ -6,8 +6,10 @@
 
 
 	export let show = false;
 	export let show = false;
 
 
-	let largeScreen = false;
+	export let chatId = null;
+	export let params = {};
 
 
+	let largeScreen = false;
 	onMount(() => {
 	onMount(() => {
 		// listen to resize 1024px
 		// listen to resize 1024px
 		const mediaQuery = window.matchMedia('(min-width: 1024px)');
 		const mediaQuery = window.matchMedia('(min-width: 1024px)');
@@ -35,12 +37,13 @@
 		<div class=" absolute bottom-0 right-0 z-20 h-full pointer-events-none">
 		<div class=" absolute bottom-0 right-0 z-20 h-full pointer-events-none">
 			<div class="pr-4 pt-14 pb-8 w-[24rem] h-full" in:slide={{ duration: 200, axis: 'x' }}>
 			<div class="pr-4 pt-14 pb-8 w-[24rem] h-full" in:slide={{ duration: 200, axis: 'x' }}>
 				<div
 				<div
-					class="w-full h-full px-5 py-4 dark:bg-gray-850 border border-gray-100 dark:border-gray-800 rounded-xl shadow-lg z-50 pointer-events-auto"
+					class="w-full h-full px-5 py-4 shadow-lg dark:bg-gray-850 border border-gray-50 dark:border-gray-800 rounded-xl z-50 pointer-events-auto overflow-y-auto scrollbar-hidden"
 				>
 				>
 					<Controls
 					<Controls
 						on:close={() => {
 						on:close={() => {
 							show = false;
 							show = false;
 						}}
 						}}
+						bind:params
 					/>
 					/>
 				</div>
 				</div>
 			</div>
 			</div>
@@ -48,11 +51,12 @@
 	{/if}
 	{/if}
 {:else}
 {:else}
 	<Modal bind:show>
 	<Modal bind:show>
-		<div class="  px-5 py-4 h-full">
+		<div class="  px-6 py-4 h-full">
 			<Controls
 			<Controls
 				on:close={() => {
 				on:close={() => {
 					show = false;
 					show = false;
 				}}
 				}}
+				bind:params
 			/>
 			/>
 		</div>
 		</div>
 	</Modal>
 	</Modal>

+ 38 - 13
src/lib/components/chat/Controls/Controls.svelte

@@ -1,24 +1,49 @@
 <script>
 <script>
-	import { createEventDispatcher } from 'svelte';
-
+	import { createEventDispatcher, getContext } from 'svelte';
 	const dispatch = createEventDispatcher();
 	const dispatch = createEventDispatcher();
+	const i18n = getContext('i18n');
+
 	import XMark from '$lib/components/icons/XMark.svelte';
 	import XMark from '$lib/components/icons/XMark.svelte';
+	import AdvancedParams from '../Settings/Advanced/AdvancedParams.svelte';
+
+	export let params = {};
 </script>
 </script>
 
 
 <div class=" dark:text-white">
 <div class=" dark:text-white">
-	<div class="mb-2 flex justify-between items-center">
-		<div class=" text-lg font-medium font-primary">Chat Controls</div>
+	<div class=" flex justify-between dark:text-gray-100 mb-2">
+		<div class=" text-lg font-medium self-center font-primary">{$i18n.t('Chat Controls')}</div>
+		<button
+			class="self-center"
+			on:click={() => {
+				dispatch('close');
+			}}
+		>
+			<XMark className="size-4" />
+		</button>
+	</div>
 
 
+	<div class=" dark:text-gray-200 text-sm font-primary">
 		<div>
 		<div>
-			<button
-				on:click={() => {
-					dispatch('close');
-				}}
-			>
-				<XMark className="size-4" />
-			</button>
+			<div class="mb-1.5 font-medium">System Prompt</div>
+
+			<div>
+				<textarea
+					bind:value={params.system}
+					class="w-full rounded-lg px-4 py-3 text-sm dark:text-gray-300 dark:bg-gray-850 border dark:border-gray-800 outline-none resize-none"
+					rows="3"
+					placeholder="Enter system prompt"
+				/>
+			</div>
 		</div>
 		</div>
-	</div>
 
 
-	<div>coming soon</div>
+		<hr class="my-2 dark:border-gray-800" />
+
+		<div>
+			<div class="mb-1.5 font-medium">Advanced Params</div>
+
+			<div>
+				<AdvancedParams bind:params />
+			</div>
+		</div>
+	</div>
 </div>
 </div>

+ 19 - 19
src/lib/components/chat/Settings/Advanced/AdvancedParams.svelte

@@ -44,7 +44,7 @@
 			<div class=" self-center text-xs font-medium">{$i18n.t('Seed')}</div>
 			<div class=" self-center text-xs font-medium">{$i18n.t('Seed')}</div>
 
 
 			<button
 			<button
-				class="p-1 px-3 text-xs flex rounded transition"
+				class="p-1 px-3 text-xs flex rounded transition flex-shrink-0 outline-none"
 				type="button"
 				type="button"
 				on:click={() => {
 				on:click={() => {
 					params.seed = (params?.seed ?? null) === null ? 0 : null;
 					params.seed = (params?.seed ?? null) === null ? 0 : null;
@@ -79,7 +79,7 @@
 			<div class=" self-center text-xs font-medium">{$i18n.t('Stop Sequence')}</div>
 			<div class=" self-center text-xs font-medium">{$i18n.t('Stop Sequence')}</div>
 
 
 			<button
 			<button
-				class="p-1 px-3 text-xs flex rounded transition"
+				class="p-1 px-3 text-xs flex rounded transition flex-shrink-0 outline-none"
 				type="button"
 				type="button"
 				on:click={() => {
 				on:click={() => {
 					params.stop = (params?.stop ?? null) === null ? '' : null;
 					params.stop = (params?.stop ?? null) === null ? '' : null;
@@ -113,7 +113,7 @@
 			<div class=" self-center text-xs font-medium">{$i18n.t('Temperature')}</div>
 			<div class=" self-center text-xs font-medium">{$i18n.t('Temperature')}</div>
 
 
 			<button
 			<button
-				class="p-1 px-3 text-xs flex rounded transition"
+				class="p-1 px-3 text-xs flex rounded transition flex-shrink-0 outline-none"
 				type="button"
 				type="button"
 				on:click={() => {
 				on:click={() => {
 					params.temperature = (params?.temperature ?? null) === null ? 0.8 : null;
 					params.temperature = (params?.temperature ?? null) === null ? 0.8 : null;
@@ -159,7 +159,7 @@
 			<div class=" self-center text-xs font-medium">{$i18n.t('Mirostat')}</div>
 			<div class=" self-center text-xs font-medium">{$i18n.t('Mirostat')}</div>
 
 
 			<button
 			<button
-				class="p-1 px-3 text-xs flex rounded transition"
+				class="p-1 px-3 text-xs flex rounded transition flex-shrink-0 outline-none"
 				type="button"
 				type="button"
 				on:click={() => {
 				on:click={() => {
 					params.mirostat = (params?.mirostat ?? null) === null ? 0 : null;
 					params.mirostat = (params?.mirostat ?? null) === null ? 0 : null;
@@ -205,7 +205,7 @@
 			<div class=" self-center text-xs font-medium">{$i18n.t('Mirostat Eta')}</div>
 			<div class=" self-center text-xs font-medium">{$i18n.t('Mirostat Eta')}</div>
 
 
 			<button
 			<button
-				class="p-1 px-3 text-xs flex rounded transition"
+				class="p-1 px-3 text-xs flex rounded transition flex-shrink-0 outline-none"
 				type="button"
 				type="button"
 				on:click={() => {
 				on:click={() => {
 					params.mirostat_eta = (params?.mirostat_eta ?? null) === null ? 0.1 : null;
 					params.mirostat_eta = (params?.mirostat_eta ?? null) === null ? 0.1 : null;
@@ -251,7 +251,7 @@
 			<div class=" self-center text-xs font-medium">{$i18n.t('Mirostat Tau')}</div>
 			<div class=" self-center text-xs font-medium">{$i18n.t('Mirostat Tau')}</div>
 
 
 			<button
 			<button
-				class="p-1 px-3 text-xs flex rounded transition"
+				class="p-1 px-3 text-xs flex rounded transition flex-shrink-0 outline-none"
 				type="button"
 				type="button"
 				on:click={() => {
 				on:click={() => {
 					params.mirostat_tau = (params?.mirostat_tau ?? null) === null ? 5.0 : null;
 					params.mirostat_tau = (params?.mirostat_tau ?? null) === null ? 5.0 : null;
@@ -297,7 +297,7 @@
 			<div class=" self-center text-xs font-medium">{$i18n.t('Top K')}</div>
 			<div class=" self-center text-xs font-medium">{$i18n.t('Top K')}</div>
 
 
 			<button
 			<button
-				class="p-1 px-3 text-xs flex rounded transition"
+				class="p-1 px-3 text-xs flex rounded transition flex-shrink-0 outline-none"
 				type="button"
 				type="button"
 				on:click={() => {
 				on:click={() => {
 					params.top_k = (params?.top_k ?? null) === null ? 40 : null;
 					params.top_k = (params?.top_k ?? null) === null ? 40 : null;
@@ -343,7 +343,7 @@
 			<div class=" self-center text-xs font-medium">{$i18n.t('Top P')}</div>
 			<div class=" self-center text-xs font-medium">{$i18n.t('Top P')}</div>
 
 
 			<button
 			<button
-				class="p-1 px-3 text-xs flex rounded transition"
+				class="p-1 px-3 text-xs flex rounded transition flex-shrink-0 outline-none"
 				type="button"
 				type="button"
 				on:click={() => {
 				on:click={() => {
 					params.top_p = (params?.top_p ?? null) === null ? 0.9 : null;
 					params.top_p = (params?.top_p ?? null) === null ? 0.9 : null;
@@ -389,7 +389,7 @@
 			<div class=" self-center text-xs font-medium">{$i18n.t('Frequency Penalty')}</div>
 			<div class=" self-center text-xs font-medium">{$i18n.t('Frequency Penalty')}</div>
 
 
 			<button
 			<button
-				class="p-1 px-3 text-xs flex rounded transition"
+				class="p-1 px-3 text-xs flex rounded transition flex-shrink-0 outline-none"
 				type="button"
 				type="button"
 				on:click={() => {
 				on:click={() => {
 					params.frequency_penalty = (params?.frequency_penalty ?? null) === null ? 1.1 : null;
 					params.frequency_penalty = (params?.frequency_penalty ?? null) === null ? 1.1 : null;
@@ -435,7 +435,7 @@
 			<div class=" self-center text-xs font-medium">{$i18n.t('Repeat Last N')}</div>
 			<div class=" self-center text-xs font-medium">{$i18n.t('Repeat Last N')}</div>
 
 
 			<button
 			<button
-				class="p-1 px-3 text-xs flex rounded transition"
+				class="p-1 px-3 text-xs flex rounded transition flex-shrink-0 outline-none"
 				type="button"
 				type="button"
 				on:click={() => {
 				on:click={() => {
 					params.repeat_last_n = (params?.repeat_last_n ?? null) === null ? 64 : null;
 					params.repeat_last_n = (params?.repeat_last_n ?? null) === null ? 64 : null;
@@ -481,7 +481,7 @@
 			<div class=" self-center text-xs font-medium">{$i18n.t('Tfs Z')}</div>
 			<div class=" self-center text-xs font-medium">{$i18n.t('Tfs Z')}</div>
 
 
 			<button
 			<button
-				class="p-1 px-3 text-xs flex rounded transition"
+				class="p-1 px-3 text-xs flex rounded transition flex-shrink-0 outline-none"
 				type="button"
 				type="button"
 				on:click={() => {
 				on:click={() => {
 					params.tfs_z = (params?.tfs_z ?? null) === null ? 1 : null;
 					params.tfs_z = (params?.tfs_z ?? null) === null ? 1 : null;
@@ -527,7 +527,7 @@
 			<div class=" self-center text-xs font-medium">{$i18n.t('Context Length')}</div>
 			<div class=" self-center text-xs font-medium">{$i18n.t('Context Length')}</div>
 
 
 			<button
 			<button
-				class="p-1 px-3 text-xs flex rounded transition"
+				class="p-1 px-3 text-xs flex rounded transition flex-shrink-0 outline-none"
 				type="button"
 				type="button"
 				on:click={() => {
 				on:click={() => {
 					params.num_ctx = (params?.num_ctx ?? null) === null ? 2048 : null;
 					params.num_ctx = (params?.num_ctx ?? null) === null ? 2048 : null;
@@ -572,7 +572,7 @@
 			<div class=" self-center text-xs font-medium">{$i18n.t('Batch Size (num_batch)')}</div>
 			<div class=" self-center text-xs font-medium">{$i18n.t('Batch Size (num_batch)')}</div>
 
 
 			<button
 			<button
-				class="p-1 px-3 text-xs flex rounded transition"
+				class="p-1 px-3 text-xs flex rounded transition flex-shrink-0 outline-none"
 				type="button"
 				type="button"
 				on:click={() => {
 				on:click={() => {
 					params.num_batch = (params?.num_batch ?? null) === null ? 512 : null;
 					params.num_batch = (params?.num_batch ?? null) === null ? 512 : null;
@@ -619,7 +619,7 @@
 			</div>
 			</div>
 
 
 			<button
 			<button
-				class="p-1 px-3 text-xs flex rounded transition"
+				class="p-1 px-3 text-xs flex rounded transition flex-shrink-0 outline-none"
 				type="button"
 				type="button"
 				on:click={() => {
 				on:click={() => {
 					params.num_keep = (params?.num_keep ?? null) === null ? 24 : null;
 					params.num_keep = (params?.num_keep ?? null) === null ? 24 : null;
@@ -664,7 +664,7 @@
 			<div class=" self-center text-xs font-medium">{$i18n.t('Max Tokens (num_predict)')}</div>
 			<div class=" self-center text-xs font-medium">{$i18n.t('Max Tokens (num_predict)')}</div>
 
 
 			<button
 			<button
-				class="p-1 px-3 text-xs flex rounded transition"
+				class="p-1 px-3 text-xs flex rounded transition flex-shrink-0 outline-none"
 				type="button"
 				type="button"
 				on:click={() => {
 				on:click={() => {
 					params.max_tokens = (params?.max_tokens ?? null) === null ? 128 : null;
 					params.max_tokens = (params?.max_tokens ?? null) === null ? 128 : null;
@@ -711,7 +711,7 @@
 				<div class=" self-center text-xs font-medium">{$i18n.t('use_mmap (Ollama)')}</div>
 				<div class=" self-center text-xs font-medium">{$i18n.t('use_mmap (Ollama)')}</div>
 
 
 				<button
 				<button
-					class="p-1 px-3 text-xs flex rounded transition"
+					class="p-1 px-3 text-xs flex rounded transition flex-shrink-0 outline-none"
 					type="button"
 					type="button"
 					on:click={() => {
 					on:click={() => {
 						params.use_mmap = (params?.use_mmap ?? null) === null ? true : null;
 						params.use_mmap = (params?.use_mmap ?? null) === null ? true : null;
@@ -731,7 +731,7 @@
 				<div class=" self-center text-xs font-medium">{$i18n.t('use_mlock (Ollama)')}</div>
 				<div class=" self-center text-xs font-medium">{$i18n.t('use_mlock (Ollama)')}</div>
 
 
 				<button
 				<button
-					class="p-1 px-3 text-xs flex rounded transition"
+					class="p-1 px-3 text-xs flex rounded transition flex-shrink-0 outline-none"
 					type="button"
 					type="button"
 					on:click={() => {
 					on:click={() => {
 						params.use_mlock = (params?.use_mlock ?? null) === null ? true : null;
 						params.use_mlock = (params?.use_mlock ?? null) === null ? true : null;
@@ -751,7 +751,7 @@
 				<div class=" self-center text-xs font-medium">{$i18n.t('num_thread (Ollama)')}</div>
 				<div class=" self-center text-xs font-medium">{$i18n.t('num_thread (Ollama)')}</div>
 
 
 				<button
 				<button
-					class="p-1 px-3 text-xs flex rounded transition"
+					class="p-1 px-3 text-xs flex rounded transition flex-shrink-0 outline-none"
 					type="button"
 					type="button"
 					on:click={() => {
 					on:click={() => {
 						params.num_thread = (params?.num_thread ?? null) === null ? 2 : null;
 						params.num_thread = (params?.num_thread ?? null) === null ? 2 : null;
@@ -797,7 +797,7 @@
 				<div class=" self-center text-xs font-medium">{$i18n.t('Template')}</div>
 				<div class=" self-center text-xs font-medium">{$i18n.t('Template')}</div>
 
 
 				<button
 				<button
-					class="p-1 px-3 text-xs flex rounded transition"
+					class="p-1 px-3 text-xs flex rounded transition flex-shrink-0 outline-none"
 					type="button"
 					type="button"
 					on:click={() => {
 					on:click={() => {
 						params.template = (params?.template ?? null) === null ? '' : null;
 						params.template = (params?.template ?? null) === null ? '' : null;

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

@@ -63,7 +63,7 @@
 		<div
 		<div
 			class=" m-auto rounded-2xl max-w-full {sizeToWidth(
 			class=" m-auto rounded-2xl max-w-full {sizeToWidth(
 				size
 				size
-			)} mx-2 bg-gray-50 dark:bg-gray-900 shadow-3xl"
+			)} mx-2 bg-gray-50 dark:bg-gray-900 shadow-3xl max-h-[100dvh] overflow-y-auto scrollbar-hidden"
 			in:flyAndScale
 			in:flyAndScale
 			on:mousedown={(e) => {
 			on:mousedown={(e) => {
 				e.stopPropagation();
 				e.stopPropagation();

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

@@ -22,7 +22,7 @@
 	};
 	};
 </script>
 </script>
 
 
-<div class="flex {showTagInput ? 'flex-row-reverse' : ''}">
+<div class="px-0.5 flex {showTagInput ? 'flex-row-reverse' : ''}">
 	{#if showTagInput}
 	{#if showTagInput}
 		<div class="flex items-center">
 		<div class="flex items-center">
 			<input
 			<input