forked from open-webui/open-webui
		
	main #2
					 46 changed files with 492 additions and 381 deletions
				
			
		|  | @ -1,5 +1,5 @@ | |||
| <script lang="ts"> | ||||
| 	import { onMount } from 'svelte'; | ||||
| 	import { onMount, getContext } from 'svelte'; | ||||
| 	import { Confetti } from 'svelte-confetti'; | ||||
| 
 | ||||
| 	import { WEBUI_NAME, config } from '$lib/stores'; | ||||
|  | @ -9,6 +9,8 @@ | |||
| 
 | ||||
| 	import Modal from './common/Modal.svelte'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	export let show = false; | ||||
| 
 | ||||
| 	let changelog = null; | ||||
|  | @ -45,7 +47,7 @@ | |||
| 			</button> | ||||
| 		</div> | ||||
| 		<div class="flex items-center mt-1"> | ||||
| 			<div class="text-sm dark:text-gray-200">Release Notes</div> | ||||
| 			<div class="text-sm dark:text-gray-200">{$i18n.t('Release Notes')}</div> | ||||
| 			<div class="flex self-center w-[1px] h-6 mx-2.5 bg-gray-200 dark:bg-gray-700" /> | ||||
| 			<div class="text-sm dark:text-gray-200"> | ||||
| 				v{WEBUI_VERSION} | ||||
|  | @ -108,7 +110,7 @@ | |||
| 				}} | ||||
| 				class=" px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-gray-100 transition rounded" | ||||
| 			> | ||||
| 				<span class="relative">Okay, Let's Go!</span> | ||||
| 				<span class="relative">{$i18n.t("Okay, Let's Go!")}</span> | ||||
| 			</button> | ||||
| 		</div> | ||||
| 	</div> | ||||
|  |  | |||
|  | @ -2,11 +2,12 @@ | |||
| 	import { toast } from 'svelte-sonner'; | ||||
| 	import dayjs from 'dayjs'; | ||||
| 	import { createEventDispatcher } from 'svelte'; | ||||
| 	import { onMount } from 'svelte'; | ||||
| 	import { onMount, getContext } from 'svelte'; | ||||
| 
 | ||||
| 	import { updateUserById } from '$lib/apis/users'; | ||||
| 	import Modal from '../common/Modal.svelte'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 	const dispatch = createEventDispatcher(); | ||||
| 
 | ||||
| 	export let show = false; | ||||
|  | @ -42,7 +43,7 @@ | |||
| <Modal size="sm" bind:show> | ||||
| 	<div> | ||||
| 		<div class=" flex justify-between dark:text-gray-300 px-5 py-4"> | ||||
| 			<div class=" text-lg font-medium self-center">Edit User</div> | ||||
| 			<div class=" text-lg font-medium self-center">{$i18n.t('Edit User')}</div> | ||||
| 			<button | ||||
| 				class="self-center" | ||||
| 				on:click={() => { | ||||
|  | @ -93,7 +94,7 @@ | |||
| 
 | ||||
| 					<div class=" flex flex-col space-y-1.5"> | ||||
| 						<div class="flex flex-col w-full"> | ||||
| 							<div class=" mb-1 text-xs text-gray-500">Email</div> | ||||
| 							<div class=" mb-1 text-xs text-gray-500">{$i18n.t('Email')}</div> | ||||
| 
 | ||||
| 							<div class="flex-1"> | ||||
| 								<input | ||||
|  | @ -108,7 +109,7 @@ | |||
| 						</div> | ||||
| 
 | ||||
| 						<div class="flex flex-col w-full"> | ||||
| 							<div class=" mb-1 text-xs text-gray-500">Name</div> | ||||
| 							<div class=" mb-1 text-xs text-gray-500">{$i18n.t('Name')}</div> | ||||
| 
 | ||||
| 							<div class="flex-1"> | ||||
| 								<input | ||||
|  | @ -122,7 +123,7 @@ | |||
| 						</div> | ||||
| 
 | ||||
| 						<div class="flex flex-col w-full"> | ||||
| 							<div class=" mb-1 text-xs text-gray-500">New Password</div> | ||||
| 							<div class=" mb-1 text-xs text-gray-500">{$i18n.t('New Password')}</div> | ||||
| 
 | ||||
| 							<div class="flex-1"> | ||||
| 								<input | ||||
|  |  | |||
|  | @ -1,6 +1,8 @@ | |||
| <script lang="ts"> | ||||
| 	import { downloadDatabase } from '$lib/apis/utils'; | ||||
| 	import { onMount } from 'svelte'; | ||||
| 	import { onMount, getContext } from 'svelte'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	export let saveHandler: Function; | ||||
| 
 | ||||
|  | @ -17,10 +19,10 @@ | |||
| > | ||||
| 	<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-80"> | ||||
| 		<div> | ||||
| 			<div class=" mb-2 text-sm font-medium">Database</div> | ||||
| 			<div class=" mb-2 text-sm font-medium">{$i18n.t('Database')}</div> | ||||
| 
 | ||||
| 			<div class="  flex w-full justify-between"> | ||||
| 				<!-- <div class=" self-center text-xs font-medium">Allow Chat Deletion</div> --> | ||||
| 				<!-- <div class=" self-center text-xs font-medium">{$i18n.t('Allow Chat Deletion')}</div> --> | ||||
| 
 | ||||
| 				<button | ||||
| 					class=" flex rounded-md py-1.5 px-3 w-full hover:bg-gray-200 dark:hover:bg-gray-800 transition" | ||||
|  | @ -46,7 +48,7 @@ | |||
| 							/> | ||||
| 						</svg> | ||||
| 					</div> | ||||
| 					<div class=" self-center text-sm font-medium">Download Database</div> | ||||
| 					<div class=" self-center text-sm font-medium">{$i18n.t('Download Database')}</div> | ||||
| 				</button> | ||||
| 			</div> | ||||
| 		</div> | ||||
|  |  | |||
|  | @ -7,7 +7,9 @@ | |||
| 		updateDefaultUserRole, | ||||
| 		updateJWTExpiresDuration | ||||
| 	} from '$lib/apis/auths'; | ||||
| 	import { onMount } from 'svelte'; | ||||
| 	import { onMount, getContext } from 'svelte'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	export let saveHandler: Function; | ||||
| 	let signUpEnabled = true; | ||||
|  | @ -43,10 +45,10 @@ | |||
| > | ||||
| 	<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-80"> | ||||
| 		<div> | ||||
| 			<div class=" mb-2 text-sm font-medium">General Settings</div> | ||||
| 			<div class=" mb-2 text-sm font-medium">{$i18n.t('General Settings')}</div> | ||||
| 
 | ||||
| 			<div class="  flex w-full justify-between"> | ||||
| 				<div class=" self-center text-xs font-medium">Enable New Sign Ups</div> | ||||
| 				<div class=" self-center text-xs font-medium">{$i18n.t('Enable New Sign Ups')}</div> | ||||
| 
 | ||||
| 				<button | ||||
| 					class="p-1 px-3 text-xs flex rounded transition" | ||||
|  | @ -66,7 +68,7 @@ | |||
| 								d="M11.5 1A3.5 3.5 0 0 0 8 4.5V7H2.5A1.5 1.5 0 0 0 1 8.5v5A1.5 1.5 0 0 0 2.5 15h7a1.5 1.5 0 0 0 1.5-1.5v-5A1.5 1.5 0 0 0 9.5 7V4.5a2 2 0 1 1 4 0v1.75a.75.75 0 0 0 1.5 0V4.5A3.5 3.5 0 0 0 11.5 1Z" | ||||
| 							/> | ||||
| 						</svg> | ||||
| 						<span class="ml-2 self-center">Enabled</span> | ||||
| 						<span class="ml-2 self-center">{$i18n.t('Enabled')}</span> | ||||
| 					{:else} | ||||
| 						<svg | ||||
| 							xmlns="http://www.w3.org/2000/svg" | ||||
|  | @ -81,13 +83,13 @@ | |||
| 							/> | ||||
| 						</svg> | ||||
| 
 | ||||
| 						<span class="ml-2 self-center">Disabled</span> | ||||
| 						<span class="ml-2 self-center">{$i18n.t('Disabled')}</span> | ||||
| 					{/if} | ||||
| 				</button> | ||||
| 			</div> | ||||
| 
 | ||||
| 			<div class=" flex w-full justify-between"> | ||||
| 				<div class=" self-center text-xs font-medium">Default User Role</div> | ||||
| 				<div class=" self-center text-xs font-medium">{$i18n.t('Default User Role')}</div> | ||||
| 				<div class="flex items-center relative"> | ||||
| 					<select | ||||
| 						class="w-fit pr-8 rounded py-2 px-2 text-xs bg-transparent outline-none text-right" | ||||
|  | @ -97,9 +99,9 @@ | |||
| 							updateDefaultUserRoleHandler(e.target.value); | ||||
| 						}} | ||||
| 					> | ||||
| 						<option value="pending">Pending</option> | ||||
| 						<option value="user">User</option> | ||||
| 						<option value="admin">Admin</option> | ||||
| 						<option value="pending">{$i18n.t('Pending')}</option> | ||||
| 						<option value="user">{$i18n.t('User')}</option> | ||||
| 						<option value="admin">{$i18n.t('Admin')}</option> | ||||
| 					</select> | ||||
| 				</div> | ||||
| 			</div> | ||||
|  | @ -108,7 +110,7 @@ | |||
| 
 | ||||
| 			<div class=" w-full justify-between"> | ||||
| 				<div class="flex w-full justify-between"> | ||||
| 					<div class=" self-center text-xs font-medium">JWT Expiration</div> | ||||
| 					<div class=" self-center text-xs font-medium">{$i18n.t('JWT Expiration')}</div> | ||||
| 				</div> | ||||
| 
 | ||||
| 				<div class="flex mt-2 space-x-2"> | ||||
|  |  | |||
|  | @ -1,7 +1,9 @@ | |||
| <script lang="ts"> | ||||
| 	import { getSignUpEnabledStatus, toggleSignUpEnabledStatus } from '$lib/apis/auths'; | ||||
| 	import { getUserPermissions, updateUserPermissions } from '$lib/apis/users'; | ||||
| 	import { onMount } from 'svelte'; | ||||
| 	import { onMount, getContext } from 'svelte'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	export let saveHandler: Function; | ||||
| 
 | ||||
|  | @ -26,10 +28,10 @@ | |||
| > | ||||
| 	<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-80"> | ||||
| 		<div> | ||||
| 			<div class=" mb-2 text-sm font-medium">User Permissions</div> | ||||
| 			<div class=" mb-2 text-sm font-medium">{$i18n.t('User Permissions')}</div> | ||||
| 
 | ||||
| 			<div class="  flex w-full justify-between"> | ||||
| 				<div class=" self-center text-xs font-medium">Allow Chat Deletion</div> | ||||
| 				<div class=" self-center text-xs font-medium">{$i18n.t('Allow Chat Deletion')}</div> | ||||
| 
 | ||||
| 				<button | ||||
| 					class="p-1 px-3 text-xs flex rounded transition" | ||||
|  | @ -49,7 +51,7 @@ | |||
| 								d="M11.5 1A3.5 3.5 0 0 0 8 4.5V7H2.5A1.5 1.5 0 0 0 1 8.5v5A1.5 1.5 0 0 0 2.5 15h7a1.5 1.5 0 0 0 1.5-1.5v-5A1.5 1.5 0 0 0 9.5 7V4.5a2 2 0 1 1 4 0v1.75a.75.75 0 0 0 1.5 0V4.5A3.5 3.5 0 0 0 11.5 1Z" | ||||
| 							/> | ||||
| 						</svg> | ||||
| 						<span class="ml-2 self-center">Allow</span> | ||||
| 						<span class="ml-2 self-center">{$i18n.t('Allow')}</span> | ||||
| 					{:else} | ||||
| 						<svg | ||||
| 							xmlns="http://www.w3.org/2000/svg" | ||||
|  | @ -64,7 +66,7 @@ | |||
| 							/> | ||||
| 						</svg> | ||||
| 
 | ||||
| 						<span class="ml-2 self-center">Don't Allow</span> | ||||
| 						<span class="ml-2 self-center">{$i18n.t("Don't Allow")}</span> | ||||
| 					{/if} | ||||
| 				</button> | ||||
| 			</div> | ||||
|  |  | |||
|  | @ -1,10 +1,13 @@ | |||
| <script> | ||||
| 	import { getContext } from 'svelte'; | ||||
| 	import Modal from '../common/Modal.svelte'; | ||||
| 	import Database from './Settings/Database.svelte'; | ||||
| 
 | ||||
| 	import General from './Settings/General.svelte'; | ||||
| 	import Users from './Settings/Users.svelte'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	export let show = false; | ||||
| 
 | ||||
| 	let selectedTab = 'general'; | ||||
|  | @ -13,7 +16,7 @@ | |||
| <Modal bind:show> | ||||
| 	<div> | ||||
| 		<div class=" flex justify-between dark:text-gray-300 px-5 py-4"> | ||||
| 			<div class=" text-lg font-medium self-center">Admin Settings</div> | ||||
| 			<div class=" text-lg font-medium self-center">{$i18n.t('Admin Settings')}</div> | ||||
| 			<button | ||||
| 				class="self-center" | ||||
| 				on:click={() => { | ||||
|  | @ -61,7 +64,7 @@ | |||
| 							/> | ||||
| 						</svg> | ||||
| 					</div> | ||||
| 					<div class=" self-center">General</div> | ||||
| 					<div class=" self-center">{$i18n.t('General')}</div> | ||||
| 				</button> | ||||
| 
 | ||||
| 				<button | ||||
|  | @ -85,7 +88,7 @@ | |||
| 							/> | ||||
| 						</svg> | ||||
| 					</div> | ||||
| 					<div class=" self-center">Users</div> | ||||
| 					<div class=" self-center">{$i18n.t('Users')}</div> | ||||
| 				</button> | ||||
| 
 | ||||
| 				<button | ||||
|  | @ -113,7 +116,7 @@ | |||
| 							/> | ||||
| 						</svg> | ||||
| 					</div> | ||||
| 					<div class=" self-center">Database</div> | ||||
| 					<div class=" self-center">{$i18n.t('Database')}</div> | ||||
| 				</button> | ||||
| 			</div> | ||||
| 			<div class="flex-1 md:min-h-[380px]"> | ||||
|  |  | |||
|  | @ -220,7 +220,7 @@ | |||
| 						isRecording = false; | ||||
| 					}; | ||||
| 				} else { | ||||
| 					toast.error('SpeechRecognition API is not supported in this browser.'); | ||||
| 					toast.error($i18n.t('SpeechRecognition API is not supported in this browser.')); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | @ -341,12 +341,15 @@ | |||
| 						uploadDoc(file); | ||||
| 					} else { | ||||
| 						toast.error( | ||||
| 							`Unknown File Type '${file['type']}', but accepting and treating as plain text` | ||||
| 							$i18n.t( | ||||
| 								`Unknown File Type '{{file_type}}', but accepting and treating as plain text`, | ||||
| 								{ file_type: file['type'] } | ||||
| 							) | ||||
| 						); | ||||
| 						uploadDoc(file); | ||||
| 					} | ||||
| 				} else { | ||||
| 					toast.error(`File not found.`); | ||||
| 					toast.error($i18n.t(`File not found.`)); | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
|  | @ -485,13 +488,16 @@ | |||
| 								filesInputElement.value = ''; | ||||
| 							} else { | ||||
| 								toast.error( | ||||
| 									`Unknown File Type '${file['type']}', but accepting and treating as plain text` | ||||
| 									$i18n.t( | ||||
| 										`Unknown File Type '{{file_type}}', but accepting and treating as plain text`, | ||||
| 										{ file_type: file['type'] } | ||||
| 									) | ||||
| 								); | ||||
| 								uploadDoc(file); | ||||
| 								filesInputElement.value = ''; | ||||
| 							} | ||||
| 						} else { | ||||
| 							toast.error(`File not found.`); | ||||
| 							toast.error($i18n.t(`File not found.`)); | ||||
| 						} | ||||
| 					}} | ||||
| 				/> | ||||
|  | @ -578,7 +584,7 @@ | |||
| 													{file.name} | ||||
| 												</div> | ||||
| 
 | ||||
| 												<div class=" text-gray-500 text-sm">Document</div> | ||||
| 												<div class=" text-gray-500 text-sm">{$i18n.t('Document')}</div> | ||||
| 											</div> | ||||
| 										</div> | ||||
| 									{:else if file.type === 'collection'} | ||||
|  | @ -606,7 +612,7 @@ | |||
| 													{file?.title ?? `#${file.name}`} | ||||
| 												</div> | ||||
| 
 | ||||
| 												<div class=" text-gray-500 text-sm">Collection</div> | ||||
| 												<div class=" text-gray-500 text-sm">{$i18n.t('Collection')}</div> | ||||
| 											</div> | ||||
| 										</div> | ||||
| 									{/if} | ||||
|  | @ -640,7 +646,7 @@ | |||
| 					<div class=" flex"> | ||||
| 						{#if fileUploadEnabled} | ||||
| 							<div class=" self-end mb-2 ml-1"> | ||||
| 								<Tooltip content="Upload files"> | ||||
| 								<Tooltip content={$i18n.t('Upload files')}> | ||||
| 									<button | ||||
| 										class="bg-gray-50 hover:bg-gray-100 text-gray-800 dark:bg-gray-850 dark:text-white dark:hover:bg-gray-800 transition rounded-full p-1.5" | ||||
| 										type="button" | ||||
|  | @ -811,7 +817,7 @@ | |||
| 
 | ||||
| 						<div class="self-end mb-2 flex space-x-1 mr-1"> | ||||
| 							{#if messages.length == 0 || messages.at(-1).done == true} | ||||
| 								<Tooltip content="Record voice"> | ||||
| 								<Tooltip content={$i18n.t('Record voice')}> | ||||
| 									{#if speechRecognitionEnabled} | ||||
| 										<button | ||||
| 											id="voice-input-button" | ||||
|  | @ -880,7 +886,7 @@ | |||
| 									{/if} | ||||
| 								</Tooltip> | ||||
| 
 | ||||
| 								<Tooltip content="Send message"> | ||||
| 								<Tooltip content={$i18n.t('Send message')}> | ||||
| 									<button | ||||
| 										class="{prompt !== '' | ||||
| 											? 'bg-black text-white hover:bg-gray-900 dark:bg-white dark:text-black dark:hover:bg-gray-100 ' | ||||
|  | @ -926,7 +932,7 @@ | |||
| 				</form> | ||||
| 
 | ||||
| 				<div class="mt-1.5 text-xs text-gray-500 text-center"> | ||||
| 					LLMs can make mistakes. Verify important information. | ||||
| 					{$i18n.t('LLMs can make mistakes. Verify important information.')} | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		</div> | ||||
|  |  | |||
|  | @ -3,9 +3,11 @@ | |||
| 
 | ||||
| 	import { documents } from '$lib/stores'; | ||||
| 	import { removeFirstHashWord, isValidHttpUrl } from '$lib/utils'; | ||||
| 	import { tick } from 'svelte'; | ||||
| 	import { tick, getContext } from 'svelte'; | ||||
| 	import { toast } from 'svelte-sonner'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	export let prompt = ''; | ||||
| 
 | ||||
| 	const dispatch = createEventDispatcher(); | ||||
|  | @ -117,7 +119,7 @@ | |||
| 									{doc?.title ?? `#${doc.name}`} | ||||
| 								</div> | ||||
| 
 | ||||
| 								<div class=" text-xs text-gray-600 line-clamp-1">Collection</div> | ||||
| 								<div class=" text-xs text-gray-600 line-clamp-1">{$i18n.t('Collection')}</div> | ||||
| 							{:else} | ||||
| 								<div class=" font-medium text-black line-clamp-1"> | ||||
| 									#{doc.name} ({doc.filename}) | ||||
|  | @ -140,7 +142,9 @@ | |||
| 									confirmSelectWeb(url); | ||||
| 								} else { | ||||
| 									toast.error( | ||||
| 										'Oops! Looks like the URL is invalid. Please double-check and try again.' | ||||
| 										$i18n.t( | ||||
| 											'Oops! Looks like the URL is invalid. Please double-check and try again.' | ||||
| 										) | ||||
| 									); | ||||
| 								} | ||||
| 							}} | ||||
|  | @ -149,7 +153,7 @@ | |||
| 								{prompt.split(' ')?.at(0)?.substring(1)} | ||||
| 							</div> | ||||
| 
 | ||||
| 							<div class=" text-xs text-gray-600 line-clamp-1">Web</div> | ||||
| 							<div class=" text-xs text-gray-600 line-clamp-1">{$i18n.t('Web')}</div> | ||||
| 						</button> | ||||
| 					{/if} | ||||
| 				</div> | ||||
|  |  | |||
|  | @ -43,7 +43,7 @@ | |||
| 		user = JSON.parse(JSON.stringify(model.name)); | ||||
| 		await tick(); | ||||
| 
 | ||||
| 		chatInputPlaceholder = `'${model.name}' is thinking...`; | ||||
| 		chatInputPlaceholder = $i18n.t('{{modelName}} is thinking...', { modelName: model.name }); | ||||
| 
 | ||||
| 		const chatInputElement = document.getElementById('chat-textarea'); | ||||
| 
 | ||||
|  | @ -111,7 +111,7 @@ | |||
| 					toast.error(error.error); | ||||
| 				} | ||||
| 			} else { | ||||
| 				toast.error(`Uh-oh! There was an issue connecting to Ollama.`); | ||||
| 				toast.error($i18n.t('Uh-oh! There was an issue connecting to llama.')); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,9 +1,11 @@ | |||
| <script lang="ts"> | ||||
| 	import { prompts } from '$lib/stores'; | ||||
| 	import { findWordIndices } from '$lib/utils'; | ||||
| 	import { tick } from 'svelte'; | ||||
| 	import { tick, getContext } from 'svelte'; | ||||
| 	import { toast } from 'svelte-sonner'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	export let prompt = ''; | ||||
| 	let selectedCommandIdx = 0; | ||||
| 	let filteredPromptCommands = []; | ||||
|  | @ -29,7 +31,7 @@ | |||
| 
 | ||||
| 		if (command.content.includes('{{CLIPBOARD}}')) { | ||||
| 			const clipboardText = await navigator.clipboard.readText().catch((err) => { | ||||
| 				toast.error('Failed to read clipboard contents'); | ||||
| 				toast.error($i18n.t('Failed to read clipboard contents')); | ||||
| 				return '{{CLIPBOARD}}'; | ||||
| 			}); | ||||
| 
 | ||||
|  | @ -113,8 +115,9 @@ | |||
| 					</div> | ||||
| 
 | ||||
| 					<div class="line-clamp-1"> | ||||
| 						Tip: Update multiple variable slots consecutively by pressing the tab key in the chat | ||||
| 						input after each replacement. | ||||
| 						{$i18n.t( | ||||
| 							'Tip: Update multiple variable slots consecutively by pressing the tab key in the chat input after each replacement.' | ||||
| 						)} | ||||
| 					</div> | ||||
| 				</div> | ||||
| 			</div> | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 	import { v4 as uuidv4 } from 'uuid'; | ||||
| 
 | ||||
| 	import { chats, config, modelfiles, settings, user } from '$lib/stores'; | ||||
| 	import { tick } from 'svelte'; | ||||
| 	import { tick, getContext } from 'svelte'; | ||||
| 
 | ||||
| 	import { toast } from 'svelte-sonner'; | ||||
| 	import { getChatList, updateChatById } from '$lib/apis/chats'; | ||||
|  | @ -13,6 +13,8 @@ | |||
| 	import Spinner from '../common/Spinner.svelte'; | ||||
| 	import { imageGenerations } from '$lib/apis/images'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	export let chatId = ''; | ||||
| 	export let sendPrompt: Function; | ||||
| 	export let continueGeneration: Function; | ||||
|  | @ -67,7 +69,7 @@ | |||
| 		navigator.clipboard.writeText(text).then( | ||||
| 			function () { | ||||
| 				console.log('Async: Copying to clipboard was successful!'); | ||||
| 				toast.success('Copying to clipboard was successful!'); | ||||
| 				toast.success($i18n.t('Copying to clipboard was successful!')); | ||||
| 			}, | ||||
| 			function (err) { | ||||
| 				console.error('Async: Could not copy text: ', err); | ||||
|  |  | |||
|  | @ -7,7 +7,9 @@ | |||
| 	import 'katex/dist/katex.min.css'; | ||||
| 
 | ||||
| 	import { createEventDispatcher } from 'svelte'; | ||||
| 	import { onMount, tick } from 'svelte'; | ||||
| 	import { onMount, tick, getContext } from 'svelte'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	const dispatch = createEventDispatcher(); | ||||
| 
 | ||||
|  | @ -355,7 +357,7 @@ | |||
| 											editMessageConfirmHandler(); | ||||
| 										}} | ||||
| 									> | ||||
| 										Save | ||||
| 										{$i18n.t('Save')} | ||||
| 									</button> | ||||
| 
 | ||||
| 									<button | ||||
|  | @ -364,7 +366,7 @@ | |||
| 											cancelEditMessage(); | ||||
| 										}} | ||||
| 									> | ||||
| 										Cancel | ||||
| 										{$i18n.t('Cancel')} | ||||
| 									</button> | ||||
| 								</div> | ||||
| 							</div> | ||||
|  |  | |||
|  | @ -1,11 +1,13 @@ | |||
| <script lang="ts"> | ||||
| 	import dayjs from 'dayjs'; | ||||
| 
 | ||||
| 	import { tick, createEventDispatcher } from 'svelte'; | ||||
| 	import { tick, createEventDispatcher, getContext } from 'svelte'; | ||||
| 	import Name from './Name.svelte'; | ||||
| 	import ProfileImage from './ProfileImage.svelte'; | ||||
| 	import { modelfiles, settings } from '$lib/stores'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	const dispatch = createEventDispatcher(); | ||||
| 
 | ||||
| 	export let user; | ||||
|  | @ -123,7 +125,7 @@ | |||
| 											{file.name} | ||||
| 										</div> | ||||
| 
 | ||||
| 										<div class=" text-gray-500 text-sm">Document</div> | ||||
| 										<div class=" text-gray-500 text-sm">{$i18n.t('Document')}</div> | ||||
| 									</div> | ||||
| 								</button> | ||||
| 							{:else if file.type === 'collection'} | ||||
|  | @ -152,7 +154,7 @@ | |||
| 											{file?.title ?? `#${file.name}`} | ||||
| 										</div> | ||||
| 
 | ||||
| 										<div class=" text-gray-500 text-sm">Collection</div> | ||||
| 										<div class=" text-gray-500 text-sm">{$i18n.t('Collection')}</div> | ||||
| 									</div> | ||||
| 								</button> | ||||
| 							{/if} | ||||
|  | @ -179,7 +181,7 @@ | |||
| 								editMessageConfirmHandler(); | ||||
| 							}} | ||||
| 						> | ||||
| 							Save & Submit | ||||
| 							{$i18n.t('Save & Submit')} | ||||
| 						</button> | ||||
| 
 | ||||
| 						<button | ||||
|  | @ -188,7 +190,7 @@ | |||
| 								cancelEditMessage(); | ||||
| 							}} | ||||
| 						> | ||||
| 							Cancel | ||||
| 							{$i18n.t('Cancel')} | ||||
| 						</button> | ||||
| 					</div> | ||||
| 				</div> | ||||
|  |  | |||
|  | @ -12,7 +12,7 @@ | |||
| 	const saveDefaultModel = async () => { | ||||
| 		const hasEmptyModel = selectedModels.filter((it) => it === ''); | ||||
| 		if (hasEmptyModel.length) { | ||||
| 			toast.error('Choose a model before saving...'); | ||||
| 			toast.error($i18n.t('Choose a model before saving...')); | ||||
| 			return; | ||||
| 		} | ||||
| 		settings.set({ ...$settings, models: selectedModels }); | ||||
|  | @ -22,7 +22,7 @@ | |||
| 			console.log('setting default models globally'); | ||||
| 			await setDefaultModels(localStorage.token, selectedModels.join(',')); | ||||
| 		} | ||||
| 		toast.success('Default model updated'); | ||||
| 		toast.success($i18n.t('Default model updated')); | ||||
| 	}; | ||||
| 
 | ||||
| 	$: if (selectedModels.length > 0 && $models.length > 0) { | ||||
|  |  | |||
|  | @ -4,7 +4,9 @@ | |||
| 	import { WEBUI_VERSION } from '$lib/constants'; | ||||
| 	import { WEBUI_NAME, config, showChangelog } from '$lib/stores'; | ||||
| 	import { compareVersion } from '$lib/utils'; | ||||
| 	import { onMount } from 'svelte'; | ||||
| 	import { onMount, getContext } from 'svelte'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	let ollamaVersion = ''; | ||||
| 
 | ||||
|  | @ -88,7 +90,7 @@ | |||
| 			<hr class=" dark:border-gray-700" /> | ||||
| 
 | ||||
| 			<div> | ||||
| 				<div class=" mb-2.5 text-sm font-medium">Ollama Version</div> | ||||
| 				<div class=" mb-2.5 text-sm font-medium">{$i18n.t('Ollama Version')}</div> | ||||
| 				<div class="flex w-full"> | ||||
| 					<div class="flex-1 text-xs text-gray-700 dark:text-gray-200"> | ||||
| 						{ollamaVersion ?? 'N/A'} | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| <script lang="ts"> | ||||
| 	import { toast } from 'svelte-sonner'; | ||||
| 	import { onMount } from 'svelte'; | ||||
| 	import { onMount, getContext } from 'svelte'; | ||||
| 
 | ||||
| 	import { user } from '$lib/stores'; | ||||
| 	import { updateUserProfile } from '$lib/apis/auths'; | ||||
|  | @ -9,6 +9,8 @@ | |||
| 	import { getGravatarUrl } from '$lib/apis/utils'; | ||||
| 	import { copyToClipboard } from '$lib/utils'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	export let saveHandler: Function; | ||||
| 
 | ||||
| 	let profileImageUrl = ''; | ||||
|  | @ -99,7 +101,7 @@ | |||
| 			}} | ||||
| 		/> | ||||
| 
 | ||||
| 		<div class=" mb-2.5 text-sm font-medium">Profile</div> | ||||
| 		<div class=" mb-2.5 text-sm font-medium">{$i18n.t('Profile')}</div> | ||||
| 
 | ||||
| 		<div class="flex space-x-5"> | ||||
| 			<div class="flex flex-col"> | ||||
|  | @ -147,7 +149,7 @@ | |||
| 
 | ||||
| 			<div class="flex-1"> | ||||
| 				<div class="flex flex-col w-full"> | ||||
| 					<div class=" mb-1 text-xs text-gray-500">Name</div> | ||||
| 					<div class=" mb-1 text-xs text-gray-500">{$i18n.t('Name')}</div> | ||||
| 
 | ||||
| 					<div class="flex-1"> | ||||
| 						<input | ||||
|  | @ -168,7 +170,7 @@ | |||
| 
 | ||||
| 		<div class=" w-full justify-between"> | ||||
| 			<div class="flex w-full justify-between"> | ||||
| 				<div class=" self-center text-xs font-medium">JWT Token</div> | ||||
| 				<div class=" self-center text-xs font-medium">{$i18n.t('JWT Token')}</div> | ||||
| 			</div> | ||||
| 
 | ||||
| 			<div class="flex mt-2"> | ||||
|  |  | |||
|  | @ -1,7 +1,10 @@ | |||
| <script lang="ts"> | ||||
| 	import { getContext } from 'svelte'; | ||||
| 	import { toast } from 'svelte-sonner'; | ||||
| 	import { updateUserPassword } from '$lib/apis/auths'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	let show = false; | ||||
| 	let currentPassword = ''; | ||||
| 	let newPassword = ''; | ||||
|  | @ -17,7 +20,7 @@ | |||
| 			); | ||||
| 
 | ||||
| 			if (res) { | ||||
| 				toast.success('Successfully updated.'); | ||||
| 				toast.success($i18n.t('Successfully updated.')); | ||||
| 			} | ||||
| 
 | ||||
| 			currentPassword = ''; | ||||
|  | @ -40,7 +43,7 @@ | |||
| 	}} | ||||
| > | ||||
| 	<div class="flex justify-between items-center text-sm"> | ||||
| 		<div class="  font-medium">Change Password</div> | ||||
| 		<div class="  font-medium">{$i18n.t('Change Password')}</div> | ||||
| 		<button | ||||
| 			class=" text-xs font-medium text-gray-500" | ||||
| 			type="button" | ||||
|  | @ -53,7 +56,7 @@ | |||
| 	{#if show} | ||||
| 		<div class=" py-2.5 space-y-1.5"> | ||||
| 			<div class="flex flex-col w-full"> | ||||
| 				<div class=" mb-1 text-xs text-gray-500">Current Password</div> | ||||
| 				<div class=" mb-1 text-xs text-gray-500">{$i18n.t('Current Password')}</div> | ||||
| 
 | ||||
| 				<div class="flex-1"> | ||||
| 					<input | ||||
|  | @ -67,7 +70,7 @@ | |||
| 			</div> | ||||
| 
 | ||||
| 			<div class="flex flex-col w-full"> | ||||
| 				<div class=" mb-1 text-xs text-gray-500">New Password</div> | ||||
| 				<div class=" mb-1 text-xs text-gray-500">{$i18n.t('New Password')}</div> | ||||
| 
 | ||||
| 				<div class="flex-1"> | ||||
| 					<input | ||||
|  | @ -81,7 +84,7 @@ | |||
| 			</div> | ||||
| 
 | ||||
| 			<div class="flex flex-col w-full"> | ||||
| 				<div class=" mb-1 text-xs text-gray-500">Confirm Password</div> | ||||
| 				<div class=" mb-1 text-xs text-gray-500">{$i18n.t('Confirm Password')}</div> | ||||
| 
 | ||||
| 				<div class="flex-1"> | ||||
| 					<input | ||||
|  |  | |||
|  | @ -1,8 +1,10 @@ | |||
| <script lang="ts"> | ||||
| 	import { createEventDispatcher, onMount } from 'svelte'; | ||||
| 	import { createEventDispatcher, onMount, getContext } from 'svelte'; | ||||
| 	import AdvancedParams from './Advanced/AdvancedParams.svelte'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 	const dispatch = createEventDispatcher(); | ||||
| 
 | ||||
| 	import AdvancedParams from './Advanced/AdvancedParams.svelte'; | ||||
| 	export let saveSettings: Function; | ||||
| 
 | ||||
| 	// Advanced | ||||
|  | @ -55,14 +57,14 @@ | |||
| 
 | ||||
| <div class="flex flex-col h-full justify-between text-sm"> | ||||
| 	<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-80"> | ||||
| 		<div class=" text-sm font-medium">Parameters</div> | ||||
| 		<div class=" text-sm font-medium">{$i18n.t('Parameters')}</div> | ||||
| 
 | ||||
| 		<AdvancedParams bind:options /> | ||||
| 		<hr class=" dark:border-gray-700" /> | ||||
| 
 | ||||
| 		<div class=" py-1 w-full justify-between"> | ||||
| 			<div class="flex w-full justify-between"> | ||||
| 				<div class=" self-center text-xs font-medium">Keep Alive</div> | ||||
| 				<div class=" self-center text-xs font-medium">{$i18n.t('Keep Alive')}</div> | ||||
| 
 | ||||
| 				<button | ||||
| 					class="p-1 px-3 text-xs flex rounded transition" | ||||
|  | @ -72,9 +74,9 @@ | |||
| 					}} | ||||
| 				> | ||||
| 					{#if keepAlive === null} | ||||
| 						<span class="ml-2 self-center"> Default </span> | ||||
| 						<span class="ml-2 self-center">{$i18n.t(' Default ')}</span> | ||||
| 					{:else} | ||||
| 						<span class="ml-2 self-center"> Custom </span> | ||||
| 						<span class="ml-2 self-center">{$i18n.t(' Custom ')}</span> | ||||
| 					{/if} | ||||
| 				</button> | ||||
| 			</div> | ||||
|  | @ -93,7 +95,7 @@ | |||
| 
 | ||||
| 		<div> | ||||
| 			<div class=" py-1 flex w-full justify-between"> | ||||
| 				<div class=" self-center text-sm font-medium">Request Mode</div> | ||||
| 				<div class=" self-center text-sm font-medium">{$i18n.t('Request Mode')}</div> | ||||
| 
 | ||||
| 				<button | ||||
| 					class="p-1 px-3 text-xs flex rounded transition" | ||||
|  | @ -102,7 +104,7 @@ | |||
| 					}} | ||||
| 				> | ||||
| 					{#if requestFormat === ''} | ||||
| 						<span class="ml-2 self-center"> Default </span> | ||||
| 						<span class="ml-2 self-center">{$i18n.t(' Default ')}</span> | ||||
| 					{:else if requestFormat === 'json'} | ||||
| 						<!-- <svg | ||||
|                             xmlns="http://www.w3.org/2000/svg" | ||||
|  | @ -114,7 +116,7 @@ | |||
|                                 d="M10 2a.75.75 0 01.75.75v1.5a.75.75 0 01-1.5 0v-1.5A.75.75 0 0110 2zM10 15a.75.75 0 01.75.75v1.5a.75.75 0 01-1.5 0v-1.5A.75.75 0 0110 15zM10 7a3 3 0 100 6 3 3 0 000-6zM15.657 5.404a.75.75 0 10-1.06-1.06l-1.061 1.06a.75.75 0 001.06 1.06l1.06-1.06zM6.464 14.596a.75.75 0 10-1.06-1.06l-1.06 1.06a.75.75 0 001.06 1.06l1.06-1.06zM18 10a.75.75 0 01-.75.75h-1.5a.75.75 0 010-1.5h1.5A.75.75 0 0118 10zM5 10a.75.75 0 01-.75.75h-1.5a.75.75 0 010-1.5h1.5A.75.75 0 015 10zM14.596 15.657a.75.75 0 001.06-1.06l-1.06-1.061a.75.75 0 10-1.06 1.06l1.06 1.06zM5.404 6.464a.75.75 0 001.06-1.06l-1.06-1.06a.75.75 0 10-1.061 1.06l1.06 1.06z" | ||||
|                             /> | ||||
|                         </svg> --> | ||||
| 						<span class="ml-2 self-center"> JSON </span> | ||||
| 						<span class="ml-2 self-center">{$i18n.t(' JSON ')}</span> | ||||
| 					{/if} | ||||
| 				</button> | ||||
| 			</div> | ||||
|  |  | |||
|  | @ -1,4 +1,8 @@ | |||
| <script lang="ts"> | ||||
| 	import { getContext } from 'svelte'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	export let options = { | ||||
| 		// Advanced | ||||
| 		seed: 0, | ||||
|  | @ -20,7 +24,7 @@ | |||
| <div class=" space-y-3 text-xs"> | ||||
| 	<div> | ||||
| 		<div class=" py-0.5 flex w-full justify-between"> | ||||
| 			<div class=" w-20 text-xs font-medium self-center">Seed</div> | ||||
| 			<div class=" w-20 text-xs font-medium self-center">{$i18n.t('Seed')}</div> | ||||
| 			<div class=" flex-1 self-center"> | ||||
| 				<input | ||||
| 					class="w-full rounded py-1.5 px-4 text-sm dark:text-gray-300 dark:bg-gray-800 outline-none border border-gray-100 dark:border-gray-600" | ||||
|  | @ -36,7 +40,7 @@ | |||
| 
 | ||||
| 	<div> | ||||
| 		<div class=" py-0.5 flex w-full justify-between"> | ||||
| 			<div class=" w-20 text-xs font-medium self-center">Stop Sequence</div> | ||||
| 			<div class=" w-20 text-xs font-medium self-center">{$i18n.t('Stop Sequence')}</div> | ||||
| 			<div class=" flex-1 self-center"> | ||||
| 				<input | ||||
| 					class="w-full rounded py-1.5 px-4 text-sm dark:text-gray-300 dark:bg-gray-800 outline-none border border-gray-100 dark:border-gray-600" | ||||
|  | @ -51,7 +55,7 @@ | |||
| 
 | ||||
| 	<div class=" py-0.5 w-full justify-between"> | ||||
| 		<div class="flex w-full justify-between"> | ||||
| 			<div class=" self-center text-xs font-medium">Temperature</div> | ||||
| 			<div class=" self-center text-xs font-medium">{$i18n.t('Temperature')}</div> | ||||
| 
 | ||||
| 			<button | ||||
| 				class="p-1 px-3 text-xs flex rounded transition" | ||||
|  | @ -61,9 +65,9 @@ | |||
| 				}} | ||||
| 			> | ||||
| 				{#if options.temperature === ''} | ||||
| 					<span class="ml-2 self-center"> Default </span> | ||||
| 					<span class="ml-2 self-center"> {$i18n.t('Default')} </span> | ||||
| 				{:else} | ||||
| 					<span class="ml-2 self-center"> Custom </span> | ||||
| 					<span class="ml-2 self-center"> {$i18n.t('Custom')} </span> | ||||
| 				{/if} | ||||
| 			</button> | ||||
| 		</div> | ||||
|  | @ -97,7 +101,7 @@ | |||
| 
 | ||||
| 	<div class=" py-0.5 w-full justify-between"> | ||||
| 		<div class="flex w-full justify-between"> | ||||
| 			<div class=" self-center text-xs font-medium">Mirostat</div> | ||||
| 			<div class=" self-center text-xs font-medium">{$i18n.t('Mirostat')}</div> | ||||
| 
 | ||||
| 			<button | ||||
| 				class="p-1 px-3 text-xs flex rounded transition" | ||||
|  | @ -107,9 +111,9 @@ | |||
| 				}} | ||||
| 			> | ||||
| 				{#if options.mirostat === ''} | ||||
| 					<span class="ml-2 self-center"> Default </span> | ||||
| 					<span class="ml-2 self-center">{$i18n.t(' Default ')}</span> | ||||
| 				{:else} | ||||
| 					<span class="ml-2 self-center"> Custom </span> | ||||
| 					<span class="ml-2 self-center">{$i18n.t(' Custom ')}</span> | ||||
| 				{/if} | ||||
| 			</button> | ||||
| 		</div> | ||||
|  | @ -143,7 +147,7 @@ | |||
| 
 | ||||
| 	<div class=" py-0.5 w-full justify-between"> | ||||
| 		<div class="flex w-full justify-between"> | ||||
| 			<div class=" self-center text-xs font-medium">Mirostat Eta</div> | ||||
| 			<div class=" self-center text-xs font-medium">{$i18n.t('Mirostat Eta')}</div> | ||||
| 
 | ||||
| 			<button | ||||
| 				class="p-1 px-3 text-xs flex rounded transition" | ||||
|  | @ -153,9 +157,9 @@ | |||
| 				}} | ||||
| 			> | ||||
| 				{#if options.mirostat_eta === ''} | ||||
| 					<span class="ml-2 self-center"> Default </span> | ||||
| 					<span class="ml-2 self-center">{$i18n.t(' Default ')}</span> | ||||
| 				{:else} | ||||
| 					<span class="ml-2 self-center"> Custom </span> | ||||
| 					<span class="ml-2 self-center">{$i18n.t(' Custom ')}</span> | ||||
| 				{/if} | ||||
| 			</button> | ||||
| 		</div> | ||||
|  | @ -189,7 +193,7 @@ | |||
| 
 | ||||
| 	<div class=" py-0.5 w-full justify-between"> | ||||
| 		<div class="flex w-full justify-between"> | ||||
| 			<div class=" self-center text-xs font-medium">Mirostat Tau</div> | ||||
| 			<div class=" self-center text-xs font-medium">{$i18n.t('Mirostat Tau')}</div> | ||||
| 
 | ||||
| 			<button | ||||
| 				class="p-1 px-3 text-xs flex rounded transition" | ||||
|  | @ -199,9 +203,9 @@ | |||
| 				}} | ||||
| 			> | ||||
| 				{#if options.mirostat_tau === ''} | ||||
| 					<span class="ml-2 self-center"> Default </span> | ||||
| 					<span class="ml-2 self-center">{$i18n.t(' Default ')}</span> | ||||
| 				{:else} | ||||
| 					<span class="ml-2 self-center"> Custom </span> | ||||
| 					<span class="ml-2 self-center">{$i18n.t(' Custom ')}</span> | ||||
| 				{/if} | ||||
| 			</button> | ||||
| 		</div> | ||||
|  | @ -235,7 +239,7 @@ | |||
| 
 | ||||
| 	<div class=" py-0.5 w-full justify-between"> | ||||
| 		<div class="flex w-full justify-between"> | ||||
| 			<div class=" self-center text-xs font-medium">Top K</div> | ||||
| 			<div class=" self-center text-xs font-medium">{$i18n.t('Top K')}</div> | ||||
| 
 | ||||
| 			<button | ||||
| 				class="p-1 px-3 text-xs flex rounded transition" | ||||
|  | @ -245,9 +249,9 @@ | |||
| 				}} | ||||
| 			> | ||||
| 				{#if options.top_k === ''} | ||||
| 					<span class="ml-2 self-center"> Default </span> | ||||
| 					<span class="ml-2 self-center">{$i18n.t(' Default ')}</span> | ||||
| 				{:else} | ||||
| 					<span class="ml-2 self-center"> Custom </span> | ||||
| 					<span class="ml-2 self-center">{$i18n.t(' Custom ')}</span> | ||||
| 				{/if} | ||||
| 			</button> | ||||
| 		</div> | ||||
|  | @ -281,7 +285,7 @@ | |||
| 
 | ||||
| 	<div class=" py-0.5 w-full justify-between"> | ||||
| 		<div class="flex w-full justify-between"> | ||||
| 			<div class=" self-center text-xs font-medium">Top P</div> | ||||
| 			<div class=" self-center text-xs font-medium">{$i18n.t('Top P')}</div> | ||||
| 
 | ||||
| 			<button | ||||
| 				class="p-1 px-3 text-xs flex rounded transition" | ||||
|  | @ -291,9 +295,9 @@ | |||
| 				}} | ||||
| 			> | ||||
| 				{#if options.top_p === ''} | ||||
| 					<span class="ml-2 self-center"> Default </span> | ||||
| 					<span class="ml-2 self-center">{$i18n.t(' Default ')}</span> | ||||
| 				{:else} | ||||
| 					<span class="ml-2 self-center"> Custom </span> | ||||
| 					<span class="ml-2 self-center">{$i18n.t(' Custom ')}</span> | ||||
| 				{/if} | ||||
| 			</button> | ||||
| 		</div> | ||||
|  | @ -327,7 +331,7 @@ | |||
| 
 | ||||
| 	<div class=" py-0.5 w-full justify-between"> | ||||
| 		<div class="flex w-full justify-between"> | ||||
| 			<div class=" self-center text-xs font-medium">Repeat Penalty</div> | ||||
| 			<div class=" self-center text-xs font-medium">{$i18n.t('Repeat Penalty')}</div> | ||||
| 
 | ||||
| 			<button | ||||
| 				class="p-1 px-3 text-xs flex rounded transition" | ||||
|  | @ -337,9 +341,9 @@ | |||
| 				}} | ||||
| 			> | ||||
| 				{#if options.repeat_penalty === ''} | ||||
| 					<span class="ml-2 self-center"> Default </span> | ||||
| 					<span class="ml-2 self-center">{$i18n.t(' Default ')}</span> | ||||
| 				{:else} | ||||
| 					<span class="ml-2 self-center"> Custom </span> | ||||
| 					<span class="ml-2 self-center">{$i18n.t(' Custom ')}</span> | ||||
| 				{/if} | ||||
| 			</button> | ||||
| 		</div> | ||||
|  | @ -373,7 +377,7 @@ | |||
| 
 | ||||
| 	<div class=" py-0.5 w-full justify-between"> | ||||
| 		<div class="flex w-full justify-between"> | ||||
| 			<div class=" self-center text-xs font-medium">Repeat Last N</div> | ||||
| 			<div class=" self-center text-xs font-medium">{$i18n.t('Repeat Last N')}</div> | ||||
| 
 | ||||
| 			<button | ||||
| 				class="p-1 px-3 text-xs flex rounded transition" | ||||
|  | @ -383,9 +387,9 @@ | |||
| 				}} | ||||
| 			> | ||||
| 				{#if options.repeat_last_n === ''} | ||||
| 					<span class="ml-2 self-center"> Default </span> | ||||
| 					<span class="ml-2 self-center">{$i18n.t(' Default ')}</span> | ||||
| 				{:else} | ||||
| 					<span class="ml-2 self-center"> Custom </span> | ||||
| 					<span class="ml-2 self-center">{$i18n.t(' Custom ')}</span> | ||||
| 				{/if} | ||||
| 			</button> | ||||
| 		</div> | ||||
|  | @ -419,7 +423,7 @@ | |||
| 
 | ||||
| 	<div class=" py-0.5 w-full justify-between"> | ||||
| 		<div class="flex w-full justify-between"> | ||||
| 			<div class=" self-center text-xs font-medium">Tfs Z</div> | ||||
| 			<div class=" self-center text-xs font-medium">{$i18n.t('Tfs Z')}</div> | ||||
| 
 | ||||
| 			<button | ||||
| 				class="p-1 px-3 text-xs flex rounded transition" | ||||
|  | @ -429,9 +433,9 @@ | |||
| 				}} | ||||
| 			> | ||||
| 				{#if options.tfs_z === ''} | ||||
| 					<span class="ml-2 self-center"> Default </span> | ||||
| 					<span class="ml-2 self-center">{$i18n.t(' Default ')}</span> | ||||
| 				{:else} | ||||
| 					<span class="ml-2 self-center"> Custom </span> | ||||
| 					<span class="ml-2 self-center">{$i18n.t(' Custom ')}</span> | ||||
| 				{/if} | ||||
| 			</button> | ||||
| 		</div> | ||||
|  | @ -465,7 +469,7 @@ | |||
| 
 | ||||
| 	<div class=" py-0.5 w-full justify-between"> | ||||
| 		<div class="flex w-full justify-between"> | ||||
| 			<div class=" self-center text-xs font-medium">Context Length</div> | ||||
| 			<div class=" self-center text-xs font-medium">{$i18n.t('Context Length')}</div> | ||||
| 
 | ||||
| 			<button | ||||
| 				class="p-1 px-3 text-xs flex rounded transition" | ||||
|  | @ -475,9 +479,9 @@ | |||
| 				}} | ||||
| 			> | ||||
| 				{#if options.num_ctx === ''} | ||||
| 					<span class="ml-2 self-center"> Default </span> | ||||
| 					<span class="ml-2 self-center">{$i18n.t(' Default ')}</span> | ||||
| 				{:else} | ||||
| 					<span class="ml-2 self-center"> Custom </span> | ||||
| 					<span class="ml-2 self-center">{$i18n.t(' Custom ')}</span> | ||||
| 				{/if} | ||||
| 			</button> | ||||
| 		</div> | ||||
|  | @ -510,7 +514,7 @@ | |||
| 	</div> | ||||
| 	<div class=" py-0.5 w-full justify-between"> | ||||
| 		<div class="flex w-full justify-between"> | ||||
| 			<div class=" self-center text-xs font-medium">Max Tokens</div> | ||||
| 			<div class=" self-center text-xs font-medium">{$i18n.t('Max Tokens')}</div> | ||||
| 
 | ||||
| 			<button | ||||
| 				class="p-1 px-3 text-xs flex rounded transition" | ||||
|  | @ -520,9 +524,9 @@ | |||
| 				}} | ||||
| 			> | ||||
| 				{#if options.num_predict === ''} | ||||
| 					<span class="ml-2 self-center"> Default </span> | ||||
| 					<span class="ml-2 self-center">{$i18n.t(' Default ')}</span> | ||||
| 				{:else} | ||||
| 					<span class="ml-2 self-center"> Custom </span> | ||||
| 					<span class="ml-2 self-center">{$i18n.t(' Custom ')}</span> | ||||
| 				{/if} | ||||
| 			</button> | ||||
| 		</div> | ||||
|  |  | |||
|  | @ -1,8 +1,10 @@ | |||
| <script lang="ts"> | ||||
| 	import { createEventDispatcher, onMount } from 'svelte'; | ||||
| 	import { createEventDispatcher, onMount, getContext } from 'svelte'; | ||||
| 	import { toast } from 'svelte-sonner'; | ||||
| 	const dispatch = createEventDispatcher(); | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	export let saveSettings: Function; | ||||
| 
 | ||||
| 	// Audio | ||||
|  | @ -101,10 +103,10 @@ | |||
| > | ||||
| 	<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-80"> | ||||
| 		<div> | ||||
| 			<div class=" mb-1 text-sm font-medium">STT Settings</div> | ||||
| 			<div class=" mb-1 text-sm font-medium">{$i18n.t('STT Settings')}</div> | ||||
| 
 | ||||
| 			<div class=" py-0.5 flex w-full justify-between"> | ||||
| 				<div class=" self-center text-xs font-medium">Speech-to-Text Engine</div> | ||||
| 				<div class=" self-center text-xs font-medium">{$i18n.t('Speech-to-Text Engine')}</div> | ||||
| 				<div class="flex items-center relative"> | ||||
| 					<select | ||||
| 						class="w-fit pr-8 rounded px-2 p-1 text-xs bg-transparent outline-none text-right" | ||||
|  | @ -119,14 +121,14 @@ | |||
| 							} | ||||
| 						}} | ||||
| 					> | ||||
| 						<option value="">Default (Web API)</option> | ||||
| 						<option value="whisper-local">Whisper (Local)</option> | ||||
| 						<option value="">{$i18n.t('Default (Web API)')}</option> | ||||
| 						<option value="whisper-local">{$i18n.t('Whisper (Local)')}</option> | ||||
| 					</select> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 
 | ||||
| 			<div class=" py-0.5 flex w-full justify-between"> | ||||
| 				<div class=" self-center text-xs font-medium">Conversation Mode</div> | ||||
| 				<div class=" self-center text-xs font-medium">{$i18n.t('Conversation Mode')}</div> | ||||
| 
 | ||||
| 				<button | ||||
| 					class="p-1 px-3 text-xs flex rounded transition" | ||||
|  | @ -136,15 +138,17 @@ | |||
| 					type="button" | ||||
| 				> | ||||
| 					{#if conversationMode === true} | ||||
| 						<span class="ml-2 self-center">On</span> | ||||
| 						<span class="ml-2 self-center">{$i18n.t('On')}</span> | ||||
| 					{:else} | ||||
| 						<span class="ml-2 self-center">Off</span> | ||||
| 						<span class="ml-2 self-center">{$i18n.t('Off')}</span> | ||||
| 					{/if} | ||||
| 				</button> | ||||
| 			</div> | ||||
| 
 | ||||
| 			<div class=" py-0.5 flex w-full justify-between"> | ||||
| 				<div class=" self-center text-xs font-medium">Auto-send input after 3 sec.</div> | ||||
| 				<div class=" self-center text-xs font-medium"> | ||||
| 					{$i18n.t('Auto-send input after 3 sec.')} | ||||
| 				</div> | ||||
| 
 | ||||
| 				<button | ||||
| 					class="p-1 px-3 text-xs flex rounded transition" | ||||
|  | @ -154,19 +158,19 @@ | |||
| 					type="button" | ||||
| 				> | ||||
| 					{#if speechAutoSend === true} | ||||
| 						<span class="ml-2 self-center">On</span> | ||||
| 						<span class="ml-2 self-center">{$i18n.t('On')}</span> | ||||
| 					{:else} | ||||
| 						<span class="ml-2 self-center">Off</span> | ||||
| 						<span class="ml-2 self-center">{$i18n.t('Off')}</span> | ||||
| 					{/if} | ||||
| 				</button> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 
 | ||||
| 		<div> | ||||
| 			<div class=" mb-1 text-sm font-medium">TTS Settings</div> | ||||
| 			<div class=" mb-1 text-sm font-medium">{$i18n.t('TTS Settings')}</div> | ||||
| 
 | ||||
| 			<div class=" py-0.5 flex w-full justify-between"> | ||||
| 				<div class=" self-center text-xs font-medium">Text-to-Speech Engine</div> | ||||
| 				<div class=" self-center text-xs font-medium">{$i18n.t('Text-to-Speech Engine')}</div> | ||||
| 				<div class="flex items-center relative"> | ||||
| 					<select | ||||
| 						class="w-fit pr-8 rounded px-2 p-1 text-xs bg-transparent outline-none text-right" | ||||
|  | @ -182,14 +186,14 @@ | |||
| 							} | ||||
| 						}} | ||||
| 					> | ||||
| 						<option value="">Default (Web API)</option> | ||||
| 						<option value="openai">Open AI</option> | ||||
| 						<option value="">{$i18n.t('Default (Web API)')}</option> | ||||
| 						<option value="openai">{$i18n.t('Open AI')}</option> | ||||
| 					</select> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 
 | ||||
| 			<div class=" py-0.5 flex w-full justify-between"> | ||||
| 				<div class=" self-center text-xs font-medium">Auto-playback response</div> | ||||
| 				<div class=" self-center text-xs font-medium">{$i18n.t('Auto-playback response')}</div> | ||||
| 
 | ||||
| 				<button | ||||
| 					class="p-1 px-3 text-xs flex rounded transition" | ||||
|  | @ -199,9 +203,9 @@ | |||
| 					type="button" | ||||
| 				> | ||||
| 					{#if responseAutoPlayback === true} | ||||
| 						<span class="ml-2 self-center">On</span> | ||||
| 						<span class="ml-2 self-center">{$i18n.t('On')}</span> | ||||
| 					{:else} | ||||
| 						<span class="ml-2 self-center">Off</span> | ||||
| 						<span class="ml-2 self-center">{$i18n.t('Off')}</span> | ||||
| 					{/if} | ||||
| 				</button> | ||||
| 			</div> | ||||
|  | @ -211,7 +215,7 @@ | |||
| 
 | ||||
| 		{#if TTSEngine === ''} | ||||
| 			<div> | ||||
| 				<div class=" mb-2.5 text-sm font-medium">Set Voice</div> | ||||
| 				<div class=" mb-2.5 text-sm font-medium">{$i18n.t('Set Voice')}</div> | ||||
| 				<div class="flex w-full"> | ||||
| 					<div class="flex-1"> | ||||
| 						<select | ||||
|  | @ -230,7 +234,7 @@ | |||
| 			</div> | ||||
| 		{:else if TTSEngine === 'openai'} | ||||
| 			<div> | ||||
| 				<div class=" mb-2.5 text-sm font-medium">Set Voice</div> | ||||
| 				<div class=" mb-2.5 text-sm font-medium">{$i18n.t('Set Voice')}</div> | ||||
| 				<div class="flex w-full"> | ||||
| 					<div class="flex-1"> | ||||
| 						<select | ||||
|  |  | |||
|  | @ -13,10 +13,12 @@ | |||
| 		getChatList | ||||
| 	} from '$lib/apis/chats'; | ||||
| 	import { getImportOrigin, convertOpenAIChats } from '$lib/utils'; | ||||
| 	import { onMount } from 'svelte'; | ||||
| 	import { onMount, getContext } from 'svelte'; | ||||
| 	import { goto } from '$app/navigation'; | ||||
| 	import { toast } from 'svelte-sonner'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	export let saveSettings: Function; | ||||
| 	// Chats | ||||
| 	let saveChatHistory = true; | ||||
|  | @ -104,7 +106,7 @@ | |||
| 			class="flex flex-col justify-between rounded-md items-center py-2 px-3.5 w-full transition" | ||||
| 		> | ||||
| 			<div class="flex w-full justify-between"> | ||||
| 				<div class=" self-center text-sm font-medium">Chat History</div> | ||||
| 				<div class=" self-center text-sm font-medium">{$i18n.t('Chat History')}</div> | ||||
| 
 | ||||
| 				<button | ||||
| 					class="p-1 px-3 text-xs flex rounded transition" | ||||
|  | @ -128,7 +130,7 @@ | |||
| 							/> | ||||
| 						</svg> | ||||
| 
 | ||||
| 						<span class="ml-2 self-center"> On </span> | ||||
| 						<span class="ml-2 self-center"> {$i18n.t('On')} </span> | ||||
| 					{:else} | ||||
| 						<svg | ||||
| 							xmlns="http://www.w3.org/2000/svg" | ||||
|  | @ -146,7 +148,7 @@ | |||
| 							/> | ||||
| 						</svg> | ||||
| 
 | ||||
| 						<span class="ml-2 self-center">Off</span> | ||||
| 						<span class="ml-2 self-center">{$i18n.t('Off')}</span> | ||||
| 					{/if} | ||||
| 				</button> | ||||
| 			</div> | ||||
|  | @ -180,7 +182,7 @@ | |||
| 						/> | ||||
| 					</svg> | ||||
| 				</div> | ||||
| 				<div class=" self-center text-sm font-medium">Import Chats</div> | ||||
| 				<div class=" self-center text-sm font-medium">{$i18n.t('Import Chats')}</div> | ||||
| 			</button> | ||||
| 			<button | ||||
| 				class=" flex rounded-md py-2 px-3.5 w-full hover:bg-gray-200 dark:hover:bg-gray-800 transition" | ||||
|  | @ -202,7 +204,7 @@ | |||
| 						/> | ||||
| 					</svg> | ||||
| 				</div> | ||||
| 				<div class=" self-center text-sm font-medium">Export Chats</div> | ||||
| 				<div class=" self-center text-sm font-medium">{$i18n.t('Export Chats')}</div> | ||||
| 			</button> | ||||
| 		</div> | ||||
| 
 | ||||
|  | @ -288,7 +290,7 @@ | |||
| 						/> | ||||
| 					</svg> | ||||
| 				</div> | ||||
| 				<div class=" self-center text-sm font-medium">Delete Chats</div> | ||||
| 				<div class=" self-center text-sm font-medium">{$i18n.t('Delete Chats')}</div> | ||||
| 			</button> | ||||
| 		{/if} | ||||
| 
 | ||||
|  | @ -316,7 +318,9 @@ | |||
| 						/> | ||||
| 					</svg> | ||||
| 				</div> | ||||
| 				<div class=" self-center text-sm font-medium">Export All Chats (All Users)</div> | ||||
| 				<div class=" self-center text-sm font-medium"> | ||||
| 					{$i18n.t('Export All Chats (All Users)')} | ||||
| 				</div> | ||||
| 			</button> | ||||
| 
 | ||||
| 			<hr class=" dark:border-gray-700" /> | ||||
|  | @ -330,7 +334,7 @@ | |||
| 					}); | ||||
| 
 | ||||
| 					if (res) { | ||||
| 						toast.success('Success'); | ||||
| 						toast.success($i18n.t('Success')); | ||||
| 					} | ||||
| 				}} | ||||
| 			> | ||||
|  | @ -348,7 +352,7 @@ | |||
| 						/> | ||||
| 					</svg> | ||||
| 				</div> | ||||
| 				<div class=" self-center text-sm font-medium">Reset Vector Storage</div> | ||||
| 				<div class=" self-center text-sm font-medium">{$i18n.t('Reset Vector Storage')}</div> | ||||
| 			</button> | ||||
| 		{/if} | ||||
| 	</div> | ||||
|  |  | |||
|  | @ -1,12 +1,14 @@ | |||
| <script lang="ts"> | ||||
| 	import { models, user } from '$lib/stores'; | ||||
| 	import { createEventDispatcher, onMount } from 'svelte'; | ||||
| 	import { createEventDispatcher, onMount, getContext } from 'svelte'; | ||||
| 	const dispatch = createEventDispatcher(); | ||||
| 
 | ||||
| 	import { getOllamaAPIUrl, getOllamaVersion, updateOllamaAPIUrl } from '$lib/apis/ollama'; | ||||
| 	import { getOpenAIKey, getOpenAIUrl, updateOpenAIKey, updateOpenAIUrl } from '$lib/apis/openai'; | ||||
| 	import { toast } from 'svelte-sonner'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	export let getModels: Function; | ||||
| 
 | ||||
| 	// External | ||||
|  | @ -34,7 +36,7 @@ | |||
| 		}); | ||||
| 
 | ||||
| 		if (ollamaVersion) { | ||||
| 			toast.success('Server connection verified'); | ||||
| 			toast.success($i18n.t('Server connection verified')); | ||||
| 			await models.set(await getModels()); | ||||
| 		} | ||||
| 	}; | ||||
|  | @ -64,7 +66,7 @@ | |||
| 		<div class=" space-y-3"> | ||||
| 			<div class="mt-2 space-y-2 pr-1.5"> | ||||
| 				<div class="flex justify-between items-center text-sm"> | ||||
| 					<div class="  font-medium">OpenAI API</div> | ||||
| 					<div class="  font-medium">{$i18n.t('OpenAI API')}</div> | ||||
| 					<button | ||||
| 						class=" text-xs font-medium text-gray-500" | ||||
| 						type="button" | ||||
|  | @ -76,7 +78,7 @@ | |||
| 
 | ||||
| 				{#if showOpenAI} | ||||
| 					<div> | ||||
| 						<div class=" mb-2.5 text-sm font-medium">API Key</div> | ||||
| 						<div class=" mb-2.5 text-sm font-medium">{$i18n.t('API Key')}</div> | ||||
| 						<div class="flex w-full"> | ||||
| 							<div class="flex-1"> | ||||
| 								<input | ||||
|  | @ -90,7 +92,7 @@ | |||
| 					</div> | ||||
| 
 | ||||
| 					<div> | ||||
| 						<div class=" mb-2.5 text-sm font-medium">API Base URL</div> | ||||
| 						<div class=" mb-2.5 text-sm font-medium">{$i18n.t('API Base URL')}</div> | ||||
| 						<div class="flex w-full"> | ||||
| 							<div class="flex-1"> | ||||
| 								<input | ||||
|  | @ -114,7 +116,7 @@ | |||
| 		<hr class=" dark:border-gray-700" /> | ||||
| 
 | ||||
| 		<div> | ||||
| 			<div class=" mb-2.5 text-sm font-medium">Ollama API URL</div> | ||||
| 			<div class=" mb-2.5 text-sm font-medium">{$i18n.t('Ollama API URL')}</div> | ||||
| 			<div class="flex w-full"> | ||||
| 				<div class="flex-1 mr-2"> | ||||
| 					<input | ||||
|  |  | |||
|  | @ -91,10 +91,10 @@ | |||
| <div class="flex flex-col h-full justify-between text-sm"> | ||||
| 	<div class="  pr-1.5 overflow-y-scroll max-h-[20.5rem]"> | ||||
| 		<div class=""> | ||||
| 			<div class=" mb-1 text-sm font-medium">WebUI Settings</div> | ||||
| 			<div class=" mb-1 text-sm font-medium">{$i18n.t('WebUI Settings')}</div> | ||||
| 
 | ||||
| 			<div class=" py-0.5 flex w-full justify-between"> | ||||
| 				<div class=" self-center text-xs font-medium">Theme</div> | ||||
| 				<div class=" self-center text-xs font-medium">{$i18n.t('Theme')}</div> | ||||
| 				<div class="flex items-center relative"> | ||||
| 					<div class=" absolute right-16"> | ||||
| 						{#if theme === 'dark'} | ||||
|  | @ -146,16 +146,16 @@ | |||
| 							console.log(theme); | ||||
| 						}} | ||||
| 					> | ||||
| 						<option value="dark">Dark</option> | ||||
| 						<option value="light">Light</option> | ||||
| 						<option value="rose-pine dark">Rosé Pine</option> | ||||
| 						<option value="rose-pine-dawn light">Rosé Pine Dawn</option> | ||||
| 						<option value="dark">{$i18n.t('Dark')}</option> | ||||
| 						<option value="light">{$i18n.t('Light')}</option> | ||||
| 						<option value="rose-pine dark">{$i18n.t('Rosé Pine')}</option> | ||||
| 						<option value="rose-pine-dawn light">{$i18n.t('Rosé Pine Dawn')}</option> | ||||
| 					</select> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 
 | ||||
| 			<div class=" py-0.5 flex w-full justify-between"> | ||||
| 				<div class=" self-center text-xs font-medium">Language</div> | ||||
| 				<div class=" self-center text-xs font-medium">{$i18n.t('Language')}</div> | ||||
| 				<div class="flex items-center relative"> | ||||
| 					<select | ||||
| 						class="w-fit pr-8 rounded py-2 px-2 text-xs bg-transparent outline-none text-right" | ||||
|  | @ -175,7 +175,7 @@ | |||
| 
 | ||||
| 			<div> | ||||
| 				<div class=" py-0.5 flex w-full justify-between"> | ||||
| 					<div class=" self-center text-xs font-medium">Notification</div> | ||||
| 					<div class=" self-center text-xs font-medium">{$i18n.t('Notification')}</div> | ||||
| 
 | ||||
| 					<button | ||||
| 						class="p-1 px-3 text-xs flex rounded transition" | ||||
|  | @ -185,9 +185,9 @@ | |||
| 						type="button" | ||||
| 					> | ||||
| 						{#if notificationEnabled === true} | ||||
| 							<span class="ml-2 self-center">On</span> | ||||
| 							<span class="ml-2 self-center">{$i18n.t('On')}</span> | ||||
| 						{:else} | ||||
| 							<span class="ml-2 self-center">Off</span> | ||||
| 							<span class="ml-2 self-center">{$i18n.t('Off')}</span> | ||||
| 						{/if} | ||||
| 					</button> | ||||
| 				</div> | ||||
|  | @ -197,7 +197,7 @@ | |||
| 		<hr class=" dark:border-gray-700 my-3" /> | ||||
| 
 | ||||
| 		<div> | ||||
| 			<div class=" my-2.5 text-sm font-medium">System Prompt</div> | ||||
| 			<div class=" my-2.5 text-sm font-medium">{$i18n.t('System Prompt')}</div> | ||||
| 			<textarea | ||||
| 				bind:value={system} | ||||
| 				class="w-full rounded p-4 text-sm dark:text-gray-300 dark:bg-gray-800 outline-none resize-none" | ||||
|  | @ -207,7 +207,7 @@ | |||
| 
 | ||||
| 		<div class="mt-2 space-y-3 pr-1.5"> | ||||
| 			<div class="flex justify-between items-center text-sm"> | ||||
| 				<div class="  font-medium">Advanced Parameters</div> | ||||
| 				<div class="  font-medium">{$i18n.t('Advanced Parameters')}</div> | ||||
| 				<button | ||||
| 					class=" text-xs font-medium text-gray-500" | ||||
| 					type="button" | ||||
|  | @ -223,7 +223,7 @@ | |||
| 
 | ||||
| 				<div class=" py-1 w-full justify-between"> | ||||
| 					<div class="flex w-full justify-between"> | ||||
| 						<div class=" self-center text-xs font-medium">Keep Alive</div> | ||||
| 						<div class=" self-center text-xs font-medium">{$i18n.t('Keep Alive')}</div> | ||||
| 
 | ||||
| 						<button | ||||
| 							class="p-1 px-3 text-xs flex rounded transition" | ||||
|  | @ -233,9 +233,9 @@ | |||
| 							}} | ||||
| 						> | ||||
| 							{#if keepAlive === null} | ||||
| 								<span class="ml-2 self-center"> Default </span> | ||||
| 								<span class="ml-2 self-center"> {$i18n.t('Default')} </span> | ||||
| 							{:else} | ||||
| 								<span class="ml-2 self-center"> Custom </span> | ||||
| 								<span class="ml-2 self-center"> {$i18n.t('Custom')} </span> | ||||
| 							{/if} | ||||
| 						</button> | ||||
| 					</div> | ||||
|  | @ -254,7 +254,7 @@ | |||
| 
 | ||||
| 				<div> | ||||
| 					<div class=" py-1 flex w-full justify-between"> | ||||
| 						<div class=" self-center text-sm font-medium">Request Mode</div> | ||||
| 						<div class=" self-center text-sm font-medium">{$i18n.t('Request Mode')}</div> | ||||
| 
 | ||||
| 						<button | ||||
| 							class="p-1 px-3 text-xs flex rounded transition" | ||||
|  | @ -263,7 +263,7 @@ | |||
| 							}} | ||||
| 						> | ||||
| 							{#if requestFormat === ''} | ||||
| 								<span class="ml-2 self-center"> Default </span> | ||||
| 								<span class="ml-2 self-center"> {$i18n.t('Default')} </span> | ||||
| 							{:else if requestFormat === 'json'} | ||||
| 								<!-- <svg | ||||
|                             xmlns="http://www.w3.org/2000/svg" | ||||
|  | @ -275,7 +275,7 @@ | |||
|                                 d="M10 2a.75.75 0 01.75.75v1.5a.75.75 0 01-1.5 0v-1.5A.75.75 0 0110 2zM10 15a.75.75 0 01.75.75v1.5a.75.75 0 01-1.5 0v-1.5A.75.75 0 0110 15zM10 7a3 3 0 100 6 3 3 0 000-6zM15.657 5.404a.75.75 0 10-1.06-1.06l-1.061 1.06a.75.75 0 001.06 1.06l1.06-1.06zM6.464 14.596a.75.75 0 10-1.06-1.06l-1.06 1.06a.75.75 0 001.06 1.06l1.06-1.06zM18 10a.75.75 0 01-.75.75h-1.5a.75.75 0 010-1.5h1.5A.75.75 0 0118 10zM5 10a.75.75 0 01-.75.75h-1.5a.75.75 0 010-1.5h1.5A.75.75 0 015 10zM14.596 15.657a.75.75 0 001.06-1.06l-1.06-1.061a.75.75 0 10-1.06 1.06l1.06 1.06zM5.404 6.464a.75.75 0 001.06-1.06l-1.06-1.06a.75.75 0 10-1.061 1.06l1.06 1.06z" | ||||
|                             /> | ||||
|                         </svg> --> | ||||
| 								<span class="ml-2 self-center"> JSON </span> | ||||
| 								<span class="ml-2 self-center"> {$i18n.t('JSON')} </span> | ||||
| 							{/if} | ||||
| 						</button> | ||||
| 					</div> | ||||
|  |  | |||
|  | @ -58,7 +58,7 @@ | |||
| 			await getModels(); | ||||
| 
 | ||||
| 			if (models) { | ||||
| 				toast.success('Server connection verified'); | ||||
| 				toast.success($i18n.t('Server connection verified')); | ||||
| 			} | ||||
| 		} else { | ||||
| 			AUTOMATIC1111_BASE_URL = await getAUTOMATIC1111Url(localStorage.token); | ||||
|  | @ -117,11 +117,13 @@ | |||
| > | ||||
| 	<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-[20.5rem]"> | ||||
| 		<div> | ||||
| 			<div class=" mb-1 text-sm font-medium">Image Settings</div> | ||||
| 			<div class=" mb-1 text-sm font-medium">{$i18n.t('Image Settings')}</div> | ||||
| 
 | ||||
| 			<div> | ||||
| 				<div class=" py-0.5 flex w-full justify-between"> | ||||
| 					<div class=" self-center text-xs font-medium">Image Generation (Experimental)</div> | ||||
| 					<div class=" self-center text-xs font-medium"> | ||||
| 						{$i18n.t('Image Generation (Experimental)')} | ||||
| 					</div> | ||||
| 
 | ||||
| 					<button | ||||
| 						class="p-1 px-3 text-xs flex rounded transition" | ||||
|  | @ -131,9 +133,9 @@ | |||
| 						type="button" | ||||
| 					> | ||||
| 						{#if enableImageGeneration === true} | ||||
| 							<span class="ml-2 self-center">On</span> | ||||
| 							<span class="ml-2 self-center">{$i18n.t('On')}</span> | ||||
| 						{:else} | ||||
| 							<span class="ml-2 self-center">Off</span> | ||||
| 							<span class="ml-2 self-center">{$i18n.t('Off')}</span> | ||||
| 						{/if} | ||||
| 					</button> | ||||
| 				</div> | ||||
|  | @ -141,7 +143,7 @@ | |||
| 		</div> | ||||
| 		<hr class=" dark:border-gray-700" /> | ||||
| 
 | ||||
| 		<div class=" mb-2.5 text-sm font-medium">AUTOMATIC1111 Base URL</div> | ||||
| 		<div class=" mb-2.5 text-sm font-medium">{$i18n.t('AUTOMATIC1111 Base URL')}</div> | ||||
| 		<div class="flex w-full"> | ||||
| 			<div class="flex-1 mr-2"> | ||||
| 				<input | ||||
|  | @ -189,7 +191,7 @@ | |||
| 			<hr class=" dark:border-gray-700" /> | ||||
| 
 | ||||
| 			<div> | ||||
| 				<div class=" mb-2.5 text-sm font-medium">Set Default Model</div> | ||||
| 				<div class=" mb-2.5 text-sm font-medium">{$i18n.t('Set Default Model')}</div> | ||||
| 				<div class="flex w-full"> | ||||
| 					<div class="flex-1 mr-2"> | ||||
| 						<select | ||||
|  | @ -211,7 +213,7 @@ | |||
| 			</div> | ||||
| 
 | ||||
| 			<div> | ||||
| 				<div class=" mb-2.5 text-sm font-medium">Set Image Size</div> | ||||
| 				<div class=" mb-2.5 text-sm font-medium">{$i18n.t('Set Image Size')}</div> | ||||
| 				<div class="flex w-full"> | ||||
| 					<div class="flex-1 mr-2"> | ||||
| 						<input | ||||
|  | @ -224,7 +226,7 @@ | |||
| 			</div> | ||||
| 
 | ||||
| 			<div> | ||||
| 				<div class=" mb-2.5 text-sm font-medium">Set Steps</div> | ||||
| 				<div class=" mb-2.5 text-sm font-medium">{$i18n.t('Set Steps')}</div> | ||||
| 				<div class="flex w-full"> | ||||
| 					<div class="flex-1 mr-2"> | ||||
| 						<input | ||||
|  |  | |||
|  | @ -96,11 +96,11 @@ | |||
| > | ||||
| 	<div class=" space-y-3 pr-1.5 overflow-y-scroll h-80"> | ||||
| 		<div> | ||||
| 			<div class=" mb-1 text-sm font-medium">WebUI Add-ons</div> | ||||
| 			<div class=" mb-1 text-sm font-medium">{$i18n.t('WebUI Add-ons')}</div> | ||||
| 
 | ||||
| 			<div> | ||||
| 				<div class=" py-0.5 flex w-full justify-between"> | ||||
| 					<div class=" self-center text-xs font-medium">Title Auto-Generation</div> | ||||
| 					<div class=" self-center text-xs font-medium">{$i18n.t('Title Auto-Generation')}</div> | ||||
| 
 | ||||
| 					<button | ||||
| 						class="p-1 px-3 text-xs flex rounded transition" | ||||
|  | @ -110,9 +110,9 @@ | |||
| 						type="button" | ||||
| 					> | ||||
| 						{#if titleAutoGenerate === true} | ||||
| 							<span class="ml-2 self-center">On</span> | ||||
| 							<span class="ml-2 self-center">{$i18n.t('On')}</span> | ||||
| 						{:else} | ||||
| 							<span class="ml-2 self-center">Off</span> | ||||
| 							<span class="ml-2 self-center">{$i18n.t('Off')}</span> | ||||
| 						{/if} | ||||
| 					</button> | ||||
| 				</div> | ||||
|  | @ -120,7 +120,7 @@ | |||
| 
 | ||||
| 			<div> | ||||
| 				<div class=" py-0.5 flex w-full justify-between"> | ||||
| 					<div class=" self-center text-xs font-medium">Response AutoCopy to Clipboard</div> | ||||
| 					<div class=" self-center text-xs font-medium">{$i18n.t('Response AutoCopy to Clipboard')}</div> | ||||
| 
 | ||||
| 					<button | ||||
| 						class="p-1 px-3 text-xs flex rounded transition" | ||||
|  | @ -130,9 +130,9 @@ | |||
| 						type="button" | ||||
| 					> | ||||
| 						{#if responseAutoCopy === true} | ||||
| 							<span class="ml-2 self-center">On</span> | ||||
| 							<span class="ml-2 self-center">{$i18n.t('On')}</span> | ||||
| 						{:else} | ||||
| 							<span class="ml-2 self-center">Off</span> | ||||
| 							<span class="ml-2 self-center">{$i18n.t('Off')}</span> | ||||
| 						{/if} | ||||
| 					</button> | ||||
| 				</div> | ||||
|  | @ -140,7 +140,7 @@ | |||
| 
 | ||||
| 			<div> | ||||
| 				<div class=" py-0.5 flex w-full justify-between"> | ||||
| 					<div class=" self-center text-xs font-medium">Full Screen Mode</div> | ||||
| 					<div class=" self-center text-xs font-medium">{$i18n.t('Full Screen Mode')}</div> | ||||
| 
 | ||||
| 					<button | ||||
| 						class="p-1 px-3 text-xs flex rounded transition" | ||||
|  | @ -150,9 +150,9 @@ | |||
| 						type="button" | ||||
| 					> | ||||
| 						{#if fullScreenMode === true} | ||||
| 							<span class="ml-2 self-center">On</span> | ||||
| 							<span class="ml-2 self-center">{$i18n.t('On')}</span> | ||||
| 						{:else} | ||||
| 							<span class="ml-2 self-center">Off</span> | ||||
| 							<span class="ml-2 self-center">{$i18n.t('Off')}</span> | ||||
| 						{/if} | ||||
| 					</button> | ||||
| 				</div> | ||||
|  | @ -172,9 +172,9 @@ | |||
| 						type="button" | ||||
| 					> | ||||
| 						{#if showUsername === true} | ||||
| 							<span class="ml-2 self-center">On</span> | ||||
| 							<span class="ml-2 self-center">{$i18n.t('On')}</span> | ||||
| 						{:else} | ||||
| 							<span class="ml-2 self-center">Off</span> | ||||
| 							<span class="ml-2 self-center">{$i18n.t('Off')}</span> | ||||
| 						{/if} | ||||
| 					</button> | ||||
| 				</div> | ||||
|  | @ -184,7 +184,7 @@ | |||
| 		<hr class=" dark:border-gray-700" /> | ||||
| 
 | ||||
| 		<div> | ||||
| 			<div class=" mb-2.5 text-sm font-medium">Set Title Auto-Generation Model</div> | ||||
| 			<div class=" mb-2.5 text-sm font-medium">{$i18n.t('Set Title Auto-Generation Model')}</div> | ||||
| 			<div class="flex w-full"> | ||||
| 				<div class="flex-1 mr-2"> | ||||
| 					<select | ||||
|  | @ -227,7 +227,7 @@ | |||
| 				</button> | ||||
| 			</div> | ||||
| 			<div class="mt-3"> | ||||
| 				<div class=" mb-2.5 text-sm font-medium">Title Generation Prompt</div> | ||||
| 				<div class=" mb-2.5 text-sm font-medium">{$i18n.t('Title Generation Prompt')}</div> | ||||
| 				<textarea | ||||
| 					bind:value={titleGenerationPrompt} | ||||
| 					class="w-full rounded p-4 text-sm dark:text-gray-300 dark:bg-gray-800 outline-none resize-none" | ||||
|  | @ -241,7 +241,7 @@ | |||
| 
 | ||||
| 			<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-80"> | ||||
| 				<div class="flex w-full justify-between mb-2"> | ||||
| 					<div class=" self-center text-sm font-semibold">Default Prompt Suggestions</div> | ||||
| 					<div class=" self-center text-sm font-semibold">{$i18n.t('Default Prompt Suggestions')}</div> | ||||
| 
 | ||||
| 					<button | ||||
| 						class="p-1 px-3 text-xs flex rounded transition" | ||||
|  |  | |||
|  | @ -78,7 +78,7 @@ | |||
| 				if (!data.success) { | ||||
| 					toast.error(data.error); | ||||
| 				} else { | ||||
| 					toast.success(`Model '${modelName}' has been successfully downloaded.`); | ||||
| 					toast.success($i18n.t(`Model '${modelName}' has been successfully downloaded.`)); | ||||
| 
 | ||||
| 					const notification = new Notification($WEBUI_NAME, { | ||||
| 						body: `Model '${modelName}' has been successfully downloaded.`, | ||||
|  | @ -243,7 +243,7 @@ | |||
| 		}); | ||||
| 
 | ||||
| 		if (res) { | ||||
| 			toast.success(`Deleted ${deleteModelTag}`); | ||||
| 			toast.success($i18n.t(`Deleted ${deleteModelTag}`)); | ||||
| 		} | ||||
| 
 | ||||
| 		deleteModelTag = ''; | ||||
|  | @ -372,7 +372,7 @@ | |||
| 				<div> | ||||
| 					<div class=" mb-2 text-sm font-medium">Manage Ollama Models</div> | ||||
| 
 | ||||
| 					<div class=" mb-2 text-sm font-medium">Pull a model from Ollama.com</div> | ||||
| 					<div class=" mb-2 text-sm font-medium">{$i18n.t('Pull a model from Ollama.com')}</div> | ||||
| 					<div class="flex w-full"> | ||||
| 						<div class="flex-1 mr-2"> | ||||
| 							<input | ||||
|  | @ -436,7 +436,7 @@ | |||
| 						To access the available model names for downloading, <a | ||||
| 							class=" text-gray-500 dark:text-gray-300 font-medium underline" | ||||
| 							href="https://ollama.com/library" | ||||
| 							target="_blank">click here.</a | ||||
| 							target="_blank">{$i18n.t('click here.')}</a | ||||
| 						> | ||||
| 					</div> | ||||
| 
 | ||||
|  | @ -461,7 +461,7 @@ | |||
| 				</div> | ||||
| 
 | ||||
| 				<div> | ||||
| 					<div class=" mb-2 text-sm font-medium">Delete a model</div> | ||||
| 					<div class=" mb-2 text-sm font-medium">{$i18n.t('Delete a model')}</div> | ||||
| 					<div class="flex w-full"> | ||||
| 						<div class="flex-1 mr-2"> | ||||
| 							<select | ||||
|  | @ -503,7 +503,7 @@ | |||
| 
 | ||||
| 				<div> | ||||
| 					<div class="flex justify-between items-center text-xs"> | ||||
| 						<div class=" text-sm font-medium">Experimental</div> | ||||
| 						<div class=" text-sm font-medium">{$i18n.t('Experimental')}</div> | ||||
| 						<button | ||||
| 							class=" text-xs font-medium text-gray-500" | ||||
| 							type="button" | ||||
|  | @ -521,7 +521,7 @@ | |||
| 						}} | ||||
| 					> | ||||
| 						<div class=" mb-2 flex w-full justify-between"> | ||||
| 							<div class="  text-sm font-medium">Upload a GGUF model</div> | ||||
| 							<div class="  text-sm font-medium">{$i18n.t('Upload a GGUF model')}</div> | ||||
| 
 | ||||
| 							<button | ||||
| 								class="p-1 px-3 text-xs flex rounded transition" | ||||
|  | @ -535,9 +535,9 @@ | |||
| 								type="button" | ||||
| 							> | ||||
| 								{#if modelUploadMode === 'file'} | ||||
| 									<span class="ml-2 self-center">File Mode</span> | ||||
| 									<span class="ml-2 self-center">{$i18n.t('File Mode')}</span> | ||||
| 								{:else} | ||||
| 									<span class="ml-2 self-center">URL Mode</span> | ||||
| 									<span class="ml-2 self-center">{$i18n.t('URL Mode')}</span> | ||||
| 								{/if} | ||||
| 							</button> | ||||
| 						</div> | ||||
|  | @ -642,7 +642,7 @@ | |||
| 						{#if (modelUploadMode === 'file' && modelInputFile && modelInputFile.length > 0) || (modelUploadMode === 'url' && modelFileUrl !== '')} | ||||
| 							<div> | ||||
| 								<div> | ||||
| 									<div class=" my-2.5 text-sm font-medium">Modelfile Content</div> | ||||
| 									<div class=" my-2.5 text-sm font-medium">{$i18n.t('Modelfile Content')}</div> | ||||
| 									<textarea | ||||
| 										bind:value={modelFileContent} | ||||
| 										class="w-full rounded py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-800 outline-none resize-none" | ||||
|  | @ -655,13 +655,13 @@ | |||
| 							To access the GGUF models available for downloading, <a | ||||
| 								class=" text-gray-500 dark:text-gray-300 font-medium underline" | ||||
| 								href="https://huggingface.co/models?search=gguf" | ||||
| 								target="_blank">click here.</a | ||||
| 								target="_blank">{$i18n.t('click here.')}</a | ||||
| 							> | ||||
| 						</div> | ||||
| 
 | ||||
| 						{#if uploadProgress !== null} | ||||
| 							<div class="mt-2"> | ||||
| 								<div class=" mb-2 text-xs">Upload Progress</div> | ||||
| 								<div class=" mb-2 text-xs">{$i18n.t('Upload Progress')}</div> | ||||
| 
 | ||||
| 								<div class="w-full rounded-full dark:bg-gray-800"> | ||||
| 									<div | ||||
|  | @ -685,11 +685,11 @@ | |||
| 		<div class=" space-y-3"> | ||||
| 			<div class="mt-2 space-y-3 pr-1.5"> | ||||
| 				<div> | ||||
| 					<div class=" mb-2 text-sm font-medium">Manage LiteLLM Models</div> | ||||
| 					<div class=" mb-2 text-sm font-medium">{$i18n.t('Manage LiteLLM Models')}</div> | ||||
| 
 | ||||
| 					<div> | ||||
| 						<div class="flex justify-between items-center text-xs"> | ||||
| 							<div class=" text-sm font-medium">Add a model</div> | ||||
| 							<div class=" text-sm font-medium">{$i18n.t('Add a model')}</div> | ||||
| 							<button | ||||
| 								class=" text-xs font-medium text-gray-500" | ||||
| 								type="button" | ||||
|  | @ -732,7 +732,7 @@ | |||
| 
 | ||||
| 						{#if showLiteLLMParams} | ||||
| 							<div> | ||||
| 								<div class=" mb-1.5 text-sm font-medium">Model Name</div> | ||||
| 								<div class=" mb-1.5 text-sm font-medium">{$i18n.t('Model Name')}</div> | ||||
| 								<div class="flex w-full"> | ||||
| 									<div class="flex-1"> | ||||
| 										<input | ||||
|  | @ -746,7 +746,7 @@ | |||
| 							</div> | ||||
| 
 | ||||
| 							<div> | ||||
| 								<div class=" mb-1.5 text-sm font-medium">API Base URL</div> | ||||
| 								<div class=" mb-1.5 text-sm font-medium">{$i18n.t('API Base URL')}</div> | ||||
| 								<div class="flex w-full"> | ||||
| 									<div class="flex-1"> | ||||
| 										<input | ||||
|  | @ -760,7 +760,7 @@ | |||
| 							</div> | ||||
| 
 | ||||
| 							<div> | ||||
| 								<div class=" mb-1.5 text-sm font-medium">API Key</div> | ||||
| 								<div class=" mb-1.5 text-sm font-medium">{$i18n.t('API Key')}</div> | ||||
| 								<div class="flex w-full"> | ||||
| 									<div class="flex-1"> | ||||
| 										<input | ||||
|  | @ -774,7 +774,7 @@ | |||
| 							</div> | ||||
| 
 | ||||
| 							<div> | ||||
| 								<div class="mb-1.5 text-sm font-medium">API RPM</div> | ||||
| 								<div class="mb-1.5 text-sm font-medium">{$i18n.t('API RPM')}</div> | ||||
| 								<div class="flex w-full"> | ||||
| 									<div class="flex-1"> | ||||
| 										<input | ||||
|  | @ -801,7 +801,7 @@ | |||
| 					</div> | ||||
| 
 | ||||
| 					<div> | ||||
| 						<div class=" mb-2.5 text-sm font-medium">Delete a model</div> | ||||
| 						<div class=" mb-2.5 text-sm font-medium">{$i18n.t('Delete a model')}</div> | ||||
| 						<div class="flex w-full"> | ||||
| 							<div class="flex-1 mr-2"> | ||||
| 								<select | ||||
|  | @ -810,8 +810,7 @@ | |||
| 									placeholder={$i18n.t('Select a model')} | ||||
| 								> | ||||
| 									{#if !deleteLiteLLMModelId} | ||||
| 										<option value="" disabled selected>{$i18n.t('Select a model')}</option | ||||
| 										> | ||||
| 										<option value="" disabled selected>{$i18n.t('Select a model')}</option> | ||||
| 									{/if} | ||||
| 									{#each liteLLMModelInfo as model} | ||||
| 										<option value={model.model_info.id} class="bg-gray-100 dark:bg-gray-700" | ||||
|  | @ -846,7 +845,7 @@ | |||
| 
 | ||||
| 			<!-- <div class="mt-2 space-y-3 pr-1.5"> | ||||
| 				<div> | ||||
| 					<div class=" mb-2.5 text-sm font-medium">Add LiteLLM Model</div> | ||||
| 					<div class=" mb-2.5 text-sm font-medium">{$i18n.t('Add LiteLLM Model')}</div> | ||||
| 					<div class="flex w-full mb-2"> | ||||
| 						<div class="flex-1"> | ||||
| 							<input | ||||
|  | @ -859,7 +858,7 @@ | |||
| 					</div> | ||||
| 
 | ||||
| 					<div class="flex justify-between items-center text-sm"> | ||||
| 						<div class="  font-medium">Advanced Model Params</div> | ||||
| 						<div class="  font-medium">{$i18n.t('Advanced Model Params')}</div> | ||||
| 						<button | ||||
| 							class=" text-xs font-medium text-gray-500" | ||||
| 							type="button" | ||||
|  | @ -871,7 +870,7 @@ | |||
| 
 | ||||
| 					{#if showLiteLLMParams} | ||||
| 						<div> | ||||
| 							<div class=" mb-2.5 text-sm font-medium">LiteLLM API Key</div> | ||||
| 							<div class=" mb-2.5 text-sm font-medium">{$i18n.t('LiteLLM API Key')}</div> | ||||
| 							<div class="flex w-full"> | ||||
| 								<div class="flex-1"> | ||||
| 									<input | ||||
|  | @ -885,7 +884,7 @@ | |||
| 						</div> | ||||
| 
 | ||||
| 						<div> | ||||
| 							<div class=" mb-2.5 text-sm font-medium">LiteLLM API Base URL</div> | ||||
| 							<div class=" mb-2.5 text-sm font-medium">{$i18n.t('LiteLLM API Base URL')}</div> | ||||
| 							<div class="flex w-full"> | ||||
| 								<div class="flex-1"> | ||||
| 									<input | ||||
|  | @ -899,7 +898,7 @@ | |||
| 						</div> | ||||
| 
 | ||||
| 						<div> | ||||
| 							<div class=" mb-2.5 text-sm font-medium">LiteLLM API RPM</div> | ||||
| 							<div class=" mb-2.5 text-sm font-medium">{$i18n.t('LiteLLM API RPM')}</div> | ||||
| 							<div class="flex w-full"> | ||||
| 								<div class="flex-1"> | ||||
| 									<input | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| <script lang="ts"> | ||||
| 	import { getContext } from 'svelte'; | ||||
| 	import { toast } from 'svelte-sonner'; | ||||
| 	import { models, settings, user } from '$lib/stores'; | ||||
| 
 | ||||
|  | @ -17,6 +18,8 @@ | |||
| 	import Connections from './Settings/Connections.svelte'; | ||||
| 	import Images from './Settings/Images.svelte'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	export let show = false; | ||||
| 
 | ||||
| 	const saveSettings = async (updated) => { | ||||
|  | @ -58,7 +61,7 @@ | |||
| <Modal bind:show> | ||||
| 	<div> | ||||
| 		<div class=" flex justify-between dark:text-gray-300 px-5 py-4"> | ||||
| 			<div class=" text-lg font-medium self-center">Settings</div> | ||||
| 			<div class=" text-lg font-medium self-center">{$i18n.t('Settings')}</div> | ||||
| 			<button | ||||
| 				class="self-center" | ||||
| 				on:click={() => { | ||||
|  | @ -106,7 +109,7 @@ | |||
| 							/> | ||||
| 						</svg> | ||||
| 					</div> | ||||
| 					<div class=" self-center">General</div> | ||||
| 					<div class=" self-center">{$i18n.t('General')}</div> | ||||
| 				</button> | ||||
| 
 | ||||
| 				{#if $user?.role === 'admin'} | ||||
|  | @ -131,7 +134,7 @@ | |||
| 								/> | ||||
| 							</svg> | ||||
| 						</div> | ||||
| 						<div class=" self-center">Connections</div> | ||||
| 						<div class=" self-center">{$i18n.t('Connections')}</div> | ||||
| 					</button> | ||||
| 
 | ||||
| 					<button | ||||
|  | @ -157,7 +160,7 @@ | |||
| 								/> | ||||
| 							</svg> | ||||
| 						</div> | ||||
| 						<div class=" self-center">Models</div> | ||||
| 						<div class=" self-center">{$i18n.t('Models')}</div> | ||||
| 					</button> | ||||
| 				{/if} | ||||
| 
 | ||||
|  | @ -184,7 +187,7 @@ | |||
| 							/> | ||||
| 						</svg> | ||||
| 					</div> | ||||
| 					<div class=" self-center">Interface</div> | ||||
| 					<div class=" self-center">{$i18n.t('Interface')}</div> | ||||
| 				</button> | ||||
| 
 | ||||
| 				<button | ||||
|  | @ -211,7 +214,7 @@ | |||
| 							/> | ||||
| 						</svg> | ||||
| 					</div> | ||||
| 					<div class=" self-center">Audio</div> | ||||
| 					<div class=" self-center">{$i18n.t('Audio')}</div> | ||||
| 				</button> | ||||
| 
 | ||||
| 				{#if $user.role === 'admin'} | ||||
|  | @ -238,7 +241,7 @@ | |||
| 								/> | ||||
| 							</svg> | ||||
| 						</div> | ||||
| 						<div class=" self-center">Images</div> | ||||
| 						<div class=" self-center">{$i18n.t('Images')}</div> | ||||
| 					</button> | ||||
| 				{/if} | ||||
| 
 | ||||
|  | @ -265,7 +268,7 @@ | |||
| 							/> | ||||
| 						</svg> | ||||
| 					</div> | ||||
| 					<div class=" self-center">Chats</div> | ||||
| 					<div class=" self-center">{$i18n.t('Chats')}</div> | ||||
| 				</button> | ||||
| 
 | ||||
| 				<button | ||||
|  | @ -291,7 +294,7 @@ | |||
| 							/> | ||||
| 						</svg> | ||||
| 					</div> | ||||
| 					<div class=" self-center">Account</div> | ||||
| 					<div class=" self-center">{$i18n.t('Account')}</div> | ||||
| 				</button> | ||||
| 
 | ||||
| 				<button | ||||
|  | @ -317,7 +320,7 @@ | |||
| 							/> | ||||
| 						</svg> | ||||
| 					</div> | ||||
| 					<div class=" self-center">About</div> | ||||
| 					<div class=" self-center">{$i18n.t('About')}</div> | ||||
| 				</button> | ||||
| 			</div> | ||||
| 			<div class="flex-1 md:min-h-[380px]"> | ||||
|  |  | |||
|  | @ -1,6 +1,9 @@ | |||
| <script lang="ts"> | ||||
| 	import { getContext } from 'svelte'; | ||||
| 	import Modal from '../common/Modal.svelte'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	export let downloadChat: Function; | ||||
| 	export let shareChat: Function; | ||||
| 
 | ||||
|  | @ -17,11 +20,11 @@ | |||
| 				show = false; | ||||
| 			}} | ||||
| 		> | ||||
| 			Share to OpenWebUI Community | ||||
| 			{$i18n.t('Share to OpenWebUI Community')} | ||||
| 		</button> | ||||
| 
 | ||||
| 		<div class="flex justify-center space-x-1 mt-1.5"> | ||||
| 			<div class=" self-center text-gray-400 text-xs font-medium">or</div> | ||||
| 			<div class=" self-center text-gray-400 text-xs font-medium">{$i18n.t('or')}</div> | ||||
| 
 | ||||
| 			<button | ||||
| 				class=" self-center rounded-full text-xs font-medium text-gray-700 dark:text-gray-500 underline" | ||||
|  | @ -31,7 +34,7 @@ | |||
| 					show = false; | ||||
| 				}} | ||||
| 			> | ||||
| 				Download as a File | ||||
| 				{$i18n.t('Download as a File')} | ||||
| 			</button> | ||||
| 		</div> | ||||
| 	</div> | ||||
|  |  | |||
|  | @ -1,13 +1,16 @@ | |||
| <script lang="ts"> | ||||
| 	import { getContext } from 'svelte'; | ||||
| 	import Modal from '../common/Modal.svelte'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	export let show = false; | ||||
| </script> | ||||
| 
 | ||||
| <Modal bind:show> | ||||
| 	<div> | ||||
| 		<div class=" flex justify-between dark:text-gray-300 px-5 py-4"> | ||||
| 			<div class=" text-lg font-medium self-center">Keyboard shortcuts</div> | ||||
| 			<div class=" text-lg font-medium self-center">{$i18n.t('Keyboard shortcuts')}</div> | ||||
| 			<button | ||||
| 				class="self-center" | ||||
| 				on:click={() => { | ||||
|  | @ -32,7 +35,7 @@ | |||
| 			<div class=" flex flex-col w-full sm:flex-row sm:justify-center sm:space-x-6"> | ||||
| 				<div class="flex flex-col space-y-3 w-full self-start"> | ||||
| 					<div class="w-full flex justify-between items-center"> | ||||
| 						<div class=" text-sm">Open new chat</div> | ||||
| 						<div class=" text-sm">{$i18n.t('Open new chat')}</div> | ||||
| 
 | ||||
| 						<div class="flex space-x-1 text-xs"> | ||||
| 							<div | ||||
|  | @ -56,7 +59,7 @@ | |||
| 					</div> | ||||
| 
 | ||||
| 					<div class="w-full flex justify-between items-center"> | ||||
| 						<div class=" text-sm">Focus chat input</div> | ||||
| 						<div class=" text-sm">{$i18n.t('Focus chat input')}</div> | ||||
| 
 | ||||
| 						<div class="flex space-x-1 text-xs"> | ||||
| 							<div | ||||
|  | @ -74,7 +77,7 @@ | |||
| 					</div> | ||||
| 
 | ||||
| 					<div class="w-full flex justify-between items-center"> | ||||
| 						<div class=" text-sm">Copy last code block</div> | ||||
| 						<div class=" text-sm">{$i18n.t('Copy last code block')}</div> | ||||
| 
 | ||||
| 						<div class="flex space-x-1 text-xs"> | ||||
| 							<div | ||||
|  | @ -98,7 +101,7 @@ | |||
| 					</div> | ||||
| 
 | ||||
| 					<div class="w-full flex justify-between items-center"> | ||||
| 						<div class=" text-sm">Copy last response</div> | ||||
| 						<div class=" text-sm">{$i18n.t('Copy last response')}</div> | ||||
| 
 | ||||
| 						<div class="flex space-x-1 text-xs"> | ||||
| 							<div | ||||
|  | @ -124,7 +127,7 @@ | |||
| 
 | ||||
| 				<div class="flex flex-col space-y-3 w-full self-start"> | ||||
| 					<div class="w-full flex justify-between items-center"> | ||||
| 						<div class=" text-sm">Toggle settings</div> | ||||
| 						<div class=" text-sm">{$i18n.t('Toggle settings')}</div> | ||||
| 
 | ||||
| 						<div class="flex space-x-1 text-xs"> | ||||
| 							<div | ||||
|  | @ -141,7 +144,7 @@ | |||
| 					</div> | ||||
| 
 | ||||
| 					<div class="w-full flex justify-between items-center"> | ||||
| 						<div class=" text-sm">Toggle sidebar</div> | ||||
| 						<div class=" text-sm">{$i18n.t('Toggle sidebar')}</div> | ||||
| 
 | ||||
| 						<div class="flex space-x-1 text-xs"> | ||||
| 							<div | ||||
|  | @ -165,7 +168,7 @@ | |||
| 					</div> | ||||
| 
 | ||||
| 					<div class="w-full flex justify-between items-center"> | ||||
| 						<div class=" text-sm">Delete chat</div> | ||||
| 						<div class=" text-sm">{$i18n.t('Delete chat')}</div> | ||||
| 
 | ||||
| 						<div class="flex space-x-1 text-xs"> | ||||
| 							<div | ||||
|  | @ -188,7 +191,7 @@ | |||
| 					</div> | ||||
| 
 | ||||
| 					<div class="w-full flex justify-between items-center"> | ||||
| 						<div class=" text-sm">Show shortcuts</div> | ||||
| 						<div class=" text-sm">{$i18n.t('Show shortcuts')}</div> | ||||
| 
 | ||||
| 						<div class="flex space-x-1 text-xs"> | ||||
| 							<div | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| <script lang="ts"> | ||||
| 	import { toast } from 'svelte-sonner'; | ||||
| 	import dayjs from 'dayjs'; | ||||
| 	import { onMount } from 'svelte'; | ||||
| 	import { onMount, getContext } from 'svelte'; | ||||
| 
 | ||||
| 	import { createNewDoc, getDocs, tagDocByName, updateDocByName } from '$lib/apis/documents'; | ||||
| 	import Modal from '../common/Modal.svelte'; | ||||
|  | @ -13,6 +13,8 @@ | |||
| 	import { transformFileName } from '$lib/utils'; | ||||
| 	import { SUPPORTED_FILE_EXTENSIONS, SUPPORTED_FILE_TYPE } from '$lib/constants'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	export let show = false; | ||||
| 	export let selectedDoc; | ||||
| 
 | ||||
|  | @ -96,7 +98,7 @@ | |||
| <Modal size="sm" bind:show> | ||||
| 	<div> | ||||
| 		<div class=" flex justify-between dark:text-gray-300 px-5 py-4"> | ||||
| 			<div class=" text-lg font-medium self-center">Add Docs</div> | ||||
| 			<div class=" text-lg font-medium self-center">{$i18n.t('Add Docs')}</div> | ||||
| 			<button | ||||
| 				class="self-center" | ||||
| 				on:click={() => { | ||||
|  | @ -145,7 +147,7 @@ | |||
| 
 | ||||
| 					<div class=" flex flex-col space-y-1.5"> | ||||
| 						<div class="flex flex-col w-full"> | ||||
| 							<div class=" mb-1.5 text-xs text-gray-500">Tags</div> | ||||
| 							<div class=" mb-1.5 text-xs text-gray-500">{$i18n.t('Tags')}</div> | ||||
| 
 | ||||
| 							<Tags {tags} addTag={addTagHandler} deleteTag={deleteTagHandler} /> | ||||
| 						</div> | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| <script lang="ts"> | ||||
| 	import { toast } from 'svelte-sonner'; | ||||
| 	import dayjs from 'dayjs'; | ||||
| 	import { onMount } from 'svelte'; | ||||
| 	import { onMount, getContext } from 'svelte'; | ||||
| 
 | ||||
| 	import { getDocs, tagDocByName, updateDocByName } from '$lib/apis/documents'; | ||||
| 	import Modal from '../common/Modal.svelte'; | ||||
|  | @ -10,6 +10,8 @@ | |||
| 	import Tags from '../common/Tags.svelte'; | ||||
| 	import { addTagById } from '$lib/apis/chats'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	export let show = false; | ||||
| 	export let selectedDoc; | ||||
| 
 | ||||
|  | @ -74,7 +76,7 @@ | |||
| <Modal size="sm" bind:show> | ||||
| 	<div> | ||||
| 		<div class=" flex justify-between dark:text-gray-300 px-5 py-4"> | ||||
| 			<div class=" text-lg font-medium self-center">Edit Doc</div> | ||||
| 			<div class=" text-lg font-medium self-center">{$i18n.t('Edit Doc')}</div> | ||||
| 			<button | ||||
| 				class="self-center" | ||||
| 				on:click={() => { | ||||
|  | @ -105,7 +107,7 @@ | |||
| 				> | ||||
| 					<div class=" flex flex-col space-y-1.5"> | ||||
| 						<div class="flex flex-col w-full"> | ||||
| 							<div class=" mb-1 text-xs text-gray-500">Name Tag</div> | ||||
| 							<div class=" mb-1 text-xs text-gray-500">{$i18n.t('Name Tag')}</div> | ||||
| 
 | ||||
| 							<div class="flex flex-1"> | ||||
| 								<div | ||||
|  | @ -134,7 +136,7 @@ | |||
| 						</div> | ||||
| 
 | ||||
| 						<div class="flex flex-col w-full"> | ||||
| 							<div class=" mb-1 text-xs text-gray-500">Title</div> | ||||
| 							<div class=" mb-1 text-xs text-gray-500">{$i18n.t('Title')}</div> | ||||
| 
 | ||||
| 							<div class="flex-1"> | ||||
| 								<input | ||||
|  | @ -148,7 +150,7 @@ | |||
| 						</div> | ||||
| 
 | ||||
| 						<div class="flex flex-col w-full"> | ||||
| 							<div class=" mb-1.5 text-xs text-gray-500">Tags</div> | ||||
| 							<div class=" mb-1.5 text-xs text-gray-500">{$i18n.t('Tags')}</div> | ||||
| 
 | ||||
| 							<Tags {tags} addTag={addTagHandler} deleteTag={deleteTagHandler} /> | ||||
| 						</div> | ||||
|  |  | |||
|  | @ -8,9 +8,11 @@ | |||
| 		updateRAGTemplate | ||||
| 	} from '$lib/apis/rag'; | ||||
| 	import { documents } from '$lib/stores'; | ||||
| 	import { onMount } from 'svelte'; | ||||
| 	import { onMount, getContext } from 'svelte'; | ||||
| 	import { toast } from 'svelte-sonner'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	export let saveHandler: Function; | ||||
| 
 | ||||
| 	let loading = false; | ||||
|  | @ -27,7 +29,7 @@ | |||
| 
 | ||||
| 		if (res) { | ||||
| 			await documents.set(await getDocs(localStorage.token)); | ||||
| 			toast.success('Scan complete!'); | ||||
| 			toast.success($i18n.t('Scan complete!')); | ||||
| 		} | ||||
| 	}; | ||||
| 
 | ||||
|  | @ -57,10 +59,12 @@ | |||
| > | ||||
| 	<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-80"> | ||||
| 		<div> | ||||
| 			<div class=" mb-2 text-sm font-medium">General Settings</div> | ||||
| 			<div class=" mb-2 text-sm font-medium">{$i18n.t('General Settings')}</div> | ||||
| 
 | ||||
| 			<div class="  flex w-full justify-between"> | ||||
| 				<div class=" self-center text-xs font-medium">Scan for documents from '/data/docs'</div> | ||||
| 				<div class=" self-center text-xs font-medium"> | ||||
| 					{$i18n.t('Scan for documents from {{path}}', { path: '/data/docs' })} | ||||
| 				</div> | ||||
| 
 | ||||
| 				<button | ||||
| 					class=" self-center text-xs p-1 px-3 bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 rounded flex flex-row space-x-1 items-center {loading | ||||
|  | @ -73,7 +77,7 @@ | |||
| 					type="button" | ||||
| 					disabled={loading} | ||||
| 				> | ||||
| 					<div class="self-center font-medium">Scan</div> | ||||
| 					<div class="self-center font-medium">{$i18n.t('Scan')}</div> | ||||
| 
 | ||||
| 					<!-- <svg | ||||
| 						xmlns="http://www.w3.org/2000/svg" | ||||
|  | @ -122,11 +126,11 @@ | |||
| 		<hr class=" dark:border-gray-700" /> | ||||
| 
 | ||||
| 		<div class=" "> | ||||
| 			<div class=" text-sm font-medium">Chunk Params</div> | ||||
| 			<div class=" text-sm font-medium">{$i18n.t('Chunk Params')}</div> | ||||
| 
 | ||||
| 			<div class=" flex"> | ||||
| 				<div class="  flex w-full justify-between"> | ||||
| 					<div class="self-center text-xs font-medium min-w-fit">Chunk Size</div> | ||||
| 					<div class="self-center text-xs font-medium min-w-fit">{$i18n.t('Chunk Size')}</div> | ||||
| 
 | ||||
| 					<div class="self-center p-3"> | ||||
| 						<input | ||||
|  | @ -141,7 +145,7 @@ | |||
| 				</div> | ||||
| 
 | ||||
| 				<div class="flex w-full"> | ||||
| 					<div class=" self-center text-xs font-medium min-w-fit">Chunk Overlap</div> | ||||
| 					<div class=" self-center text-xs font-medium min-w-fit">{$i18n.t('Chunk Overlap')}</div> | ||||
| 
 | ||||
| 					<div class="self-center p-3"> | ||||
| 						<input | ||||
|  | @ -157,7 +161,7 @@ | |||
| 			</div> | ||||
| 
 | ||||
| 			<div> | ||||
| 				<div class=" mb-2.5 text-sm font-medium">RAG Template</div> | ||||
| 				<div class=" mb-2.5 text-sm font-medium">{$i18n.t('RAG Template')}</div> | ||||
| 				<textarea | ||||
| 					bind:value={template} | ||||
| 					class="w-full rounded p-4 text-sm dark:text-gray-300 dark:bg-gray-800 outline-none resize-none" | ||||
|  |  | |||
|  | @ -1,7 +1,10 @@ | |||
| <script> | ||||
| 	import { getContext } from 'svelte'; | ||||
| 	import Modal from '../common/Modal.svelte'; | ||||
| 	import General from './Settings/General.svelte'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	export let show = false; | ||||
| 
 | ||||
| 	let selectedTab = 'general'; | ||||
|  | @ -10,7 +13,7 @@ | |||
| <Modal bind:show> | ||||
| 	<div> | ||||
| 		<div class=" flex justify-between dark:text-gray-300 px-5 py-4"> | ||||
| 			<div class=" text-lg font-medium self-center">Document Settings</div> | ||||
| 			<div class=" text-lg font-medium self-center">{$i18n.t('Document Settings')}</div> | ||||
| 			<button | ||||
| 				class="self-center" | ||||
| 				on:click={() => { | ||||
|  | @ -58,7 +61,7 @@ | |||
| 							/> | ||||
| 						</svg> | ||||
| 					</div> | ||||
| 					<div class=" self-center">General</div> | ||||
| 					<div class=" self-center">{$i18n.t('General')}</div> | ||||
| 				</button> | ||||
| 			</div> | ||||
| 			<div class="flex-1 md:min-h-[380px]"> | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| <script lang="ts"> | ||||
| 	import { getContext } from 'svelte'; | ||||
| 	import { toast } from 'svelte-sonner'; | ||||
| 	import fileSaver from 'file-saver'; | ||||
| 	const { saveAs } = fileSaver; | ||||
|  | @ -9,6 +10,8 @@ | |||
| 	import TagInput from '../common/Tags/TagInput.svelte'; | ||||
| 	import Tags from '../common/Tags.svelte'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	export let initNewChat: Function; | ||||
| 	export let title: string = $WEBUI_NAME; | ||||
| 	export let shareEnabled: boolean = false; | ||||
|  | @ -26,7 +29,7 @@ | |||
| 		const chat = (await getChatById(localStorage.token, $chatId)).chat; | ||||
| 		console.log('share', chat); | ||||
| 
 | ||||
| 		toast.success('Redirecting you to OpenWebUI Community'); | ||||
| 		toast.success($i18n.t('Redirecting you to OpenWebUI Community')); | ||||
| 		const url = 'https://openwebui.com'; | ||||
| 		// const url = 'http://localhost:5173'; | ||||
| 
 | ||||
|  |  | |||
|  | @ -7,8 +7,7 @@ | |||
| 	import { goto, invalidateAll } from '$app/navigation'; | ||||
| 	import { page } from '$app/stores'; | ||||
| 	import { user, chats, settings, showSettings, chatId, tags } from '$lib/stores'; | ||||
| 	import { onMount } from 'svelte'; | ||||
| 	import { getContext } from 'svelte'; | ||||
| 	import { onMount, getContext } from 'svelte'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
|  | @ -201,7 +200,7 @@ | |||
| 					</div> | ||||
| 
 | ||||
| 					<div class="flex self-center"> | ||||
| 						<div class=" self-center font-medium text-sm">Prompts</div> | ||||
| 						<div class=" self-center font-medium text-sm">{$i18n.t('Prompts')}</div> | ||||
| 					</div> | ||||
| 				</a> | ||||
| 			</div> | ||||
|  | @ -229,7 +228,7 @@ | |||
| 					</div> | ||||
| 
 | ||||
| 					<div class="flex self-center"> | ||||
| 						<div class=" self-center font-medium text-sm">Documents</div> | ||||
| 						<div class=" self-center font-medium text-sm">{$i18n.t('Documents')}</div> | ||||
| 					</div> | ||||
| 				</a> | ||||
| 			</div> | ||||
|  | @ -239,7 +238,7 @@ | |||
| 			{#if !($settings.saveChatHistory ?? true)} | ||||
| 				<div class="absolute z-40 w-full h-full bg-black/90 flex justify-center"> | ||||
| 					<div class=" text-left px-5 py-2"> | ||||
| 						<div class=" font-medium">Chat History is off for this browser.</div> | ||||
| 						<div class=" font-medium">{$i18n.t('Chat History is off for this browser.')}</div> | ||||
| 						<div class="text-xs mt-2"> | ||||
| 							When history is turned off, new chats on this browser won't appear in your history on | ||||
| 							any of your devices. <span class=" font-semibold" | ||||
|  | @ -596,7 +595,7 @@ | |||
| 												/> | ||||
| 											</svg> | ||||
| 										</div> | ||||
| 										<div class=" self-center font-medium">Admin Panel</div> | ||||
| 										<div class=" self-center font-medium">{$i18n.t('Admin Panel')}</div> | ||||
| 									</button> | ||||
| 								{/if} | ||||
| 
 | ||||
|  | @ -628,7 +627,7 @@ | |||
| 											/> | ||||
| 										</svg> | ||||
| 									</div> | ||||
| 									<div class=" self-center font-medium">Settings</div> | ||||
| 									<div class=" self-center font-medium">{$i18n.t('Settings')}</div> | ||||
| 								</button> | ||||
| 							</div> | ||||
| 
 | ||||
|  | @ -662,7 +661,7 @@ | |||
| 											/> | ||||
| 										</svg> | ||||
| 									</div> | ||||
| 									<div class=" self-center font-medium">Sign Out</div> | ||||
| 									<div class=" self-center font-medium">{$i18n.t('Sign Out')}</div> | ||||
| 								</button> | ||||
| 							</div> | ||||
| 						</div> | ||||
|  |  | |||
|  | @ -1,10 +1,10 @@ | |||
| <script lang="ts"> | ||||
| 	import { toast } from 'svelte-sonner'; | ||||
| 	import { onMount, tick, getContext } from 'svelte'; | ||||
| 	import { openDB, deleteDB } from 'idb'; | ||||
| 	import fileSaver from 'file-saver'; | ||||
| 	const { saveAs } = fileSaver; | ||||
| 
 | ||||
| 	import { onMount, tick } from 'svelte'; | ||||
| 	import { goto } from '$app/navigation'; | ||||
| 
 | ||||
| 	import { getOllamaModels, getOllamaVersion } from '$lib/apis/ollama'; | ||||
|  | @ -35,6 +35,8 @@ | |||
| 	import ShortcutsModal from '$lib/components/chat/ShortcutsModal.svelte'; | ||||
| 	import ChangelogModal from '$lib/components/ChangelogModal.svelte'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	let ollamaVersion = ''; | ||||
| 	let loaded = false; | ||||
| 
 | ||||
|  | @ -266,12 +268,14 @@ | |||
| 							</div> | ||||
| 
 | ||||
| 							<div class=" mt-4 text-center text-sm dark:text-gray-200 w-full"> | ||||
| 								Saving chat logs directly to your browser's storage is no longer supported. Please | ||||
| 								take a moment to download and delete your chat logs by clicking the button below. | ||||
| 								Don't worry, you can easily re-import your chat logs to the backend through <span | ||||
| 									class="font-semibold dark:text-white">Settings > Chats > Import Chats</span | ||||
| 								>. This ensures that your valuable conversations are securely saved to your backend | ||||
| 								database. Thank you! | ||||
| 								{$i18n.t( | ||||
| 									"Saving chat logs directly to your browser's storage is no longer supported. Please take a moment to download and delete your chat logs by clicking the button below. Don't worry, you can easily re-import your chat logs to the backend through" | ||||
| 								)} | ||||
| 								<span class="font-semibold dark:text-white" | ||||
| 									>{$i18n.t('Settings')} > {$i18n.t('Chats')} > {$i18n.t('Import Chats')}</span | ||||
| 								>. {$i18n.t( | ||||
| 									'This ensures that your valuable conversations are securely saved to your backend database. Thank you!' | ||||
| 								)} | ||||
| 							</div> | ||||
| 
 | ||||
| 							<div class=" mt-6 mx-auto relative group w-fit"> | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 	import { WEBUI_API_BASE_URL } from '$lib/constants'; | ||||
| 	import { WEBUI_NAME, config, user } from '$lib/stores'; | ||||
| 	import { goto } from '$app/navigation'; | ||||
| 	import { onMount } from 'svelte'; | ||||
| 	import { onMount, getContext } from 'svelte'; | ||||
| 
 | ||||
| 	import { toast } from 'svelte-sonner'; | ||||
| 
 | ||||
|  | @ -11,6 +11,8 @@ | |||
| 	import EditUserModal from '$lib/components/admin/EditUserModal.svelte'; | ||||
| 	import SettingsModal from '$lib/components/admin/SettingsModal.svelte'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	let loaded = false; | ||||
| 	let users = []; | ||||
| 
 | ||||
|  | @ -37,7 +39,7 @@ | |||
| 		}); | ||||
| 		if (res) { | ||||
| 			users = await getUsers(localStorage.token); | ||||
| 			toast.success('Successfully updated'); | ||||
| 			toast.success($i18n.t('Successfully updated')); | ||||
| 		} | ||||
| 	}; | ||||
| 
 | ||||
|  | @ -115,7 +117,7 @@ | |||
| 										/> | ||||
| 									</svg> | ||||
| 
 | ||||
| 									<div class=" text-xs">Admin Settings</div> | ||||
| 									<div class=" text-xs">{$i18n.t('Admin Settings')}</div> | ||||
| 								</button> | ||||
| 							</div> | ||||
| 						</div> | ||||
|  | @ -131,10 +133,10 @@ | |||
| 									class="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400" | ||||
| 								> | ||||
| 									<tr> | ||||
| 										<th scope="col" class="px-3 py-2"> Role </th> | ||||
| 										<th scope="col" class="px-3 py-2"> Name </th> | ||||
| 										<th scope="col" class="px-3 py-2"> Email </th> | ||||
| 										<th scope="col" class="px-3 py-2"> Action </th> | ||||
| 										<th scope="col" class="px-3 py-2"> {$i18n.t('Role')} </th> | ||||
| 										<th scope="col" class="px-3 py-2"> {$i18n.t('Name')} </th> | ||||
| 										<th scope="col" class="px-3 py-2"> {$i18n.t('Email')} </th> | ||||
| 										<th scope="col" class="px-3 py-2"> {$i18n.t('Action')} </th> | ||||
| 									</tr> | ||||
| 								</thead> | ||||
| 								<tbody> | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ | |||
| 	import fileSaver from 'file-saver'; | ||||
| 	const { saveAs } = fileSaver; | ||||
| 
 | ||||
| 	import { onMount } from 'svelte'; | ||||
| 	import { onMount, getContext } from 'svelte'; | ||||
| 	import { WEBUI_NAME, documents } from '$lib/stores'; | ||||
| 	import { createNewDoc, deleteDocByName, getDocs } from '$lib/apis/documents'; | ||||
| 
 | ||||
|  | @ -17,6 +17,9 @@ | |||
| 	import AddFilesPlaceholder from '$lib/components/AddFilesPlaceholder.svelte'; | ||||
| 	import SettingsModal from '$lib/components/documents/SettingsModal.svelte'; | ||||
| 	import AddDocModal from '$lib/components/documents/AddDocModal.svelte'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	let importFiles = ''; | ||||
| 
 | ||||
| 	let inputFiles = ''; | ||||
|  | @ -188,7 +191,7 @@ | |||
| 		<div class="max-w-2xl mx-auto w-full px-3 md:px-0 my-10"> | ||||
| 			<div class="mb-6"> | ||||
| 				<div class="flex justify-between items-center"> | ||||
| 					<div class=" text-2xl font-semibold self-center">My Documents</div> | ||||
| 					<div class=" text-2xl font-semibold self-center">{$i18n.t('My Documents')}</div> | ||||
| 
 | ||||
| 					<div> | ||||
| 						<button | ||||
|  | @ -211,7 +214,7 @@ | |||
| 								/> | ||||
| 							</svg> | ||||
| 
 | ||||
| 							<div class=" text-xs">Document Settings</div> | ||||
| 							<div class=" text-xs">{$i18n.t('Document Settings')}</div> | ||||
| 						</button> | ||||
| 					</div> | ||||
| 				</div> | ||||
|  | @ -274,7 +277,7 @@ | |||
| 					on:dragleave={onDragLeave} | ||||
| 				> | ||||
| 					<div class="  pointer-events-none"> | ||||
| 						<div class="text-center dark:text-white text-2xl font-semibold z-50">Add Files</div> | ||||
| 						<div class="text-center dark:text-white text-2xl font-semibold z-50">{$i18n.t('Add Files')}</div> | ||||
| 
 | ||||
| 						<div class=" mt-2 text-center text-sm dark:text-gray-200 w-full"> | ||||
| 							Drop any files here to add to my documents | ||||
|  | @ -314,7 +317,7 @@ | |||
| 								// await chats.set(await getChatListByTagName(localStorage.token, tag.name)); | ||||
| 							}} | ||||
| 						> | ||||
| 							<div class=" text-xs font-medium self-center line-clamp-1">all</div> | ||||
| 							<div class=" text-xs font-medium self-center line-clamp-1">{$i18n.t('all')}</div> | ||||
| 						</button> | ||||
| 
 | ||||
| 						{#each tags as tag} | ||||
|  | @ -344,7 +347,7 @@ | |||
| 										// await chats.set(await getChatListByTagName(localStorage.token, tag.name)); | ||||
| 									}} | ||||
| 								> | ||||
| 									<div class=" text-xs font-medium self-center line-clamp-1">add tags</div> | ||||
| 									<div class=" text-xs font-medium self-center line-clamp-1">{$i18n.t('add tags')}</div> | ||||
| 								</button> --> | ||||
| 
 | ||||
| 								<button | ||||
|  | @ -354,7 +357,9 @@ | |||
| 										// await chats.set(await getChatListByTagName(localStorage.token, tag.name)); | ||||
| 									}} | ||||
| 								> | ||||
| 									<div class=" text-xs font-medium self-center line-clamp-1">delete</div> | ||||
| 									<div class=" text-xs font-medium self-center line-clamp-1"> | ||||
| 										{$i18n.t('delete')} | ||||
| 									</div> | ||||
| 								</button> | ||||
| 							</div> | ||||
| 						</div> | ||||
|  | @ -562,7 +567,7 @@ | |||
| 							document.getElementById('documents-import-input')?.click(); | ||||
| 						}} | ||||
| 					> | ||||
| 						<div class=" self-center mr-2 font-medium">Import Documents Mapping</div> | ||||
| 						<div class=" self-center mr-2 font-medium">{$i18n.t('Import Documents Mapping')}</div> | ||||
| 
 | ||||
| 						<div class=" self-center"> | ||||
| 							<svg | ||||
|  | @ -589,7 +594,7 @@ | |||
| 							saveAs(blob, `documents-mapping-export-${Date.now()}.json`); | ||||
| 						}} | ||||
| 					> | ||||
| 						<div class=" self-center mr-2 font-medium">Export Documents Mapping</div> | ||||
| 						<div class=" self-center mr-2 font-medium">{$i18n.t('Export Documents Mapping')}</div> | ||||
| 
 | ||||
| 						<div class=" self-center"> | ||||
| 							<svg | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ | |||
| 	import fileSaver from 'file-saver'; | ||||
| 	const { saveAs } = fileSaver; | ||||
| 
 | ||||
| 	import { onMount } from 'svelte'; | ||||
| 	import { onMount, getContext } from 'svelte'; | ||||
| 
 | ||||
| 	import { WEBUI_NAME, modelfiles, settings, user } from '$lib/stores'; | ||||
| 	import { createModel, deleteModel } from '$lib/apis/ollama'; | ||||
|  | @ -14,6 +14,8 @@ | |||
| 	} from '$lib/apis/modelfiles'; | ||||
| 	import { goto } from '$app/navigation'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	let localModelfiles = []; | ||||
| 	let importFiles; | ||||
| 
 | ||||
|  | @ -23,7 +25,7 @@ | |||
| 		success = await deleteModel(localStorage.token, tagName); | ||||
| 
 | ||||
| 		if (success) { | ||||
| 			toast.success(`Deleted ${tagName}`); | ||||
| 			toast.success($i18n.t(`Deleted {tagName}`, { tagName })); | ||||
| 		} | ||||
| 
 | ||||
| 		return success; | ||||
|  | @ -36,7 +38,7 @@ | |||
| 	}; | ||||
| 
 | ||||
| 	const shareModelfile = async (modelfile) => { | ||||
| 		toast.success('Redirecting you to OpenWebUI Community'); | ||||
| 		toast.success($i18n.t('Redirecting you to OpenWebUI Community')); | ||||
| 
 | ||||
| 		const url = 'https://openwebui.com'; | ||||
| 
 | ||||
|  | @ -78,7 +80,7 @@ | |||
| <div class="min-h-screen max-h-[100dvh] w-full flex justify-center dark:text-white"> | ||||
| 	<div class="flex flex-col justify-between w-full overflow-y-auto"> | ||||
| 		<div class="max-w-2xl mx-auto w-full px-3 md:px-0 my-10"> | ||||
| 			<div class=" text-2xl font-semibold mb-3">My Modelfiles</div> | ||||
| 			<div class=" text-2xl font-semibold mb-3">{$i18n.t('My Modelfiles')}</div> | ||||
| 
 | ||||
| 			<a class=" flex space-x-4 cursor-pointer w-full mb-2 px-3 py-2" href="/modelfiles/create"> | ||||
| 				<div class=" self-center w-10"> | ||||
|  | @ -101,8 +103,8 @@ | |||
| 				</div> | ||||
| 
 | ||||
| 				<div class=" self-center"> | ||||
| 					<div class=" font-bold">Create a modelfile</div> | ||||
| 					<div class=" text-sm">Customize Ollama models for a specific purpose</div> | ||||
| 					<div class=" font-bold">{$i18n.t('Create a modelfile')}</div> | ||||
| 					<div class=" text-sm">{$i18n.t('Customize Ollama models for a specific purpose')}</div> | ||||
| 				</div> | ||||
| 			</a> | ||||
| 
 | ||||
|  | @ -266,7 +268,7 @@ | |||
| 							document.getElementById('modelfiles-import-input')?.click(); | ||||
| 						}} | ||||
| 					> | ||||
| 						<div class=" self-center mr-2 font-medium">Import Modelfiles</div> | ||||
| 						<div class=" self-center mr-2 font-medium">{$i18n.t('Import Modelfiles')}</div> | ||||
| 
 | ||||
| 						<div class=" self-center"> | ||||
| 							<svg | ||||
|  | @ -290,7 +292,7 @@ | |||
| 							saveModelfiles($modelfiles); | ||||
| 						}} | ||||
| 					> | ||||
| 						<div class=" self-center mr-2 font-medium">Export Modelfiles</div> | ||||
| 						<div class=" self-center mr-2 font-medium">{$i18n.t('Export Modelfiles')}</div> | ||||
| 
 | ||||
| 						<div class=" self-center"> | ||||
| 							<svg | ||||
|  | @ -331,7 +333,7 @@ | |||
| 									await modelfiles.set(await getModelfiles(localStorage.token)); | ||||
| 								}} | ||||
| 							> | ||||
| 								<div class=" self-center mr-2 font-medium">Sync All</div> | ||||
| 								<div class=" self-center mr-2 font-medium">{$i18n.t('Sync All')}</div> | ||||
| 
 | ||||
| 								<div class=" self-center"> | ||||
| 									<svg | ||||
|  | @ -382,7 +384,7 @@ | |||
| 			</div> | ||||
| 
 | ||||
| 			<div class=" my-16"> | ||||
| 				<div class=" text-2xl font-semibold mb-3">Made by OpenWebUI Community</div> | ||||
| 				<div class=" text-2xl font-semibold mb-3">{$i18n.t('Made by OpenWebUI Community')}</div> | ||||
| 
 | ||||
| 				<a | ||||
| 					class=" flex space-x-4 cursor-pointer w-full mb-2 px-3 py-2" | ||||
|  | @ -409,8 +411,8 @@ | |||
| 					</div> | ||||
| 
 | ||||
| 					<div class=" self-center"> | ||||
| 						<div class=" font-bold">Discover a modelfile</div> | ||||
| 						<div class=" text-sm">Discover, download, and explore model presets</div> | ||||
| 						<div class=" font-bold">{$i18n.t('Discover a modelfile')}</div> | ||||
| 						<div class=" text-sm">{$i18n.t('Discover, download, and explore model presets')}</div> | ||||
| 					</div> | ||||
| 				</a> | ||||
| 			</div> | ||||
|  |  | |||
|  | @ -6,10 +6,12 @@ | |||
| 
 | ||||
| 	import AdvancedParams from '$lib/components/chat/Settings/Advanced/AdvancedParams.svelte'; | ||||
| 	import { splitStream } from '$lib/utils'; | ||||
| 	import { onMount, tick } from 'svelte'; | ||||
| 	import { onMount, tick, getContext } from 'svelte'; | ||||
| 	import { createModel } from '$lib/apis/ollama'; | ||||
| 	import { createNewModelfile, getModelfileByTagName, getModelfiles } from '$lib/apis/modelfiles'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	let loading = false; | ||||
| 
 | ||||
| 	let filesInputElement; | ||||
|  | @ -349,7 +351,7 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, ''); | |||
| 				}} | ||||
| 			/> | ||||
| 
 | ||||
| 			<div class=" text-2xl font-semibold mb-6">My Modelfiles</div> | ||||
| 			<div class=" text-2xl font-semibold mb-6">{$i18n.t('My Modelfiles')}</div> | ||||
| 
 | ||||
| 			<button | ||||
| 				class="flex space-x-1" | ||||
|  | @ -371,7 +373,7 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, ''); | |||
| 						/> | ||||
| 					</svg> | ||||
| 				</div> | ||||
| 				<div class=" self-center font-medium text-sm">Back</div> | ||||
| 				<div class=" self-center font-medium text-sm">{$i18n.t('Back')}</div> | ||||
| 			</button> | ||||
| 			<hr class="my-3 dark:border-gray-700" /> | ||||
| 
 | ||||
|  | @ -418,7 +420,7 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, ''); | |||
| 
 | ||||
| 				<div class="my-2 flex space-x-2"> | ||||
| 					<div class="flex-1"> | ||||
| 						<div class=" text-sm font-semibold mb-2">Name*</div> | ||||
| 						<div class=" text-sm font-semibold mb-2">{$i18n.t('Name')}*</div> | ||||
| 
 | ||||
| 						<div> | ||||
| 							<input | ||||
|  | @ -431,7 +433,7 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, ''); | |||
| 					</div> | ||||
| 
 | ||||
| 					<div class="flex-1"> | ||||
| 						<div class=" text-sm font-semibold mb-2">Model Tag Name*</div> | ||||
| 						<div class=" text-sm font-semibold mb-2">{$i18n.t('Model Tag Name')}*</div> | ||||
| 
 | ||||
| 						<div> | ||||
| 							<input | ||||
|  | @ -445,7 +447,7 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, ''); | |||
| 				</div> | ||||
| 
 | ||||
| 				<div class="my-2"> | ||||
| 					<div class=" text-sm font-semibold mb-2">Description*</div> | ||||
| 					<div class=" text-sm font-semibold mb-2">{$i18n.t('Description')}*</div> | ||||
| 
 | ||||
| 					<div> | ||||
| 						<input | ||||
|  | @ -459,7 +461,7 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, ''); | |||
| 
 | ||||
| 				<div class="my-2"> | ||||
| 					<div class="flex w-full justify-between"> | ||||
| 						<div class=" self-center text-sm font-semibold">Modelfile</div> | ||||
| 						<div class=" self-center text-sm font-semibold">{$i18n.t('Modelfile')}</div> | ||||
| 
 | ||||
| 						<button | ||||
| 							class="p-1 px-3 text-xs flex rounded transition" | ||||
|  | @ -469,9 +471,9 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, ''); | |||
| 							}} | ||||
| 						> | ||||
| 							{#if raw} | ||||
| 								<span class="ml-2 self-center"> Raw Format </span> | ||||
| 								<span class="ml-2 self-center"> {$i18n.t('Raw Format')} </span> | ||||
| 							{:else} | ||||
| 								<span class="ml-2 self-center"> Builder Mode </span> | ||||
| 								<span class="ml-2 self-center"> {$i18n.t('Builder Mode')} </span> | ||||
| 							{/if} | ||||
| 						</button> | ||||
| 					</div> | ||||
|  | @ -480,7 +482,7 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, ''); | |||
| 
 | ||||
| 					{#if raw} | ||||
| 						<div class="mt-2"> | ||||
| 							<div class=" text-xs font-semibold mb-2">Content*</div> | ||||
| 							<div class=" text-xs font-semibold mb-2">{$i18n.t('Content')}*</div> | ||||
| 
 | ||||
| 							<div> | ||||
| 								<textarea | ||||
|  | @ -493,12 +495,13 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, ''); | |||
| 							</div> | ||||
| 
 | ||||
| 							<div class="text-xs text-gray-400 dark:text-gray-500"> | ||||
| 								Not sure what to write? Switch to <button | ||||
| 								{$i18n.t('Not sure what to write? Switch to')} | ||||
| 								<button | ||||
| 									class="text-gray-500 dark:text-gray-300 font-medium cursor-pointer" | ||||
| 									type="button" | ||||
| 									on:click={() => { | ||||
| 										raw = !raw; | ||||
| 									}}>Builder Mode</button | ||||
| 									}}>{$i18n.t('Builder Mode')}</button | ||||
| 								> | ||||
| 								or | ||||
| 								<a | ||||
|  | @ -506,13 +509,13 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, ''); | |||
| 									href="https://openwebui.com" | ||||
| 									target="_blank" | ||||
| 								> | ||||
| 									Click here to check other modelfiles. | ||||
| 									{$i18n.t('Click here to check other modelfiles.')} | ||||
| 								</a> | ||||
| 							</div> | ||||
| 						</div> | ||||
| 					{:else} | ||||
| 						<div class="my-2"> | ||||
| 							<div class=" text-xs font-semibold mb-2">From (Base Model)*</div> | ||||
| 							<div class=" text-xs font-semibold mb-2">{$i18n.t('From (Base Model)')}*</div> | ||||
| 
 | ||||
| 							<div> | ||||
| 								<input | ||||
|  | @ -524,16 +527,17 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, ''); | |||
| 							</div> | ||||
| 
 | ||||
| 							<div class="mt-1 text-xs text-gray-400 dark:text-gray-500"> | ||||
| 								To access the available model names for downloading, <a | ||||
| 								{$i18n.t('To access the available model names for downloading,')} | ||||
| 								<a | ||||
| 									class=" text-gray-500 dark:text-gray-300 font-medium" | ||||
| 									href="https://ollama.com/library" | ||||
| 									target="_blank">click here.</a | ||||
| 									target="_blank">{$i18n.t('click here.')}</a | ||||
| 								> | ||||
| 							</div> | ||||
| 						</div> | ||||
| 
 | ||||
| 						<div class="my-1"> | ||||
| 							<div class=" text-xs font-semibold mb-2">System Prompt</div> | ||||
| 							<div class=" text-xs font-semibold mb-2">{$i18n.t('System Prompt')}</div> | ||||
| 
 | ||||
| 							<div> | ||||
| 								<textarea | ||||
|  | @ -546,7 +550,9 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, ''); | |||
| 						</div> | ||||
| 
 | ||||
| 						<div class="flex w-full justify-between"> | ||||
| 							<div class=" self-center text-sm font-semibold">Modelfile Advanced Settings</div> | ||||
| 							<div class=" self-center text-sm font-semibold"> | ||||
| 								{$i18n.t('Modelfile Advanced Settings')} | ||||
| 							</div> | ||||
| 
 | ||||
| 							<button | ||||
| 								class="p-1 px-3 text-xs flex rounded transition" | ||||
|  | @ -556,16 +562,16 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, ''); | |||
| 								}} | ||||
| 							> | ||||
| 								{#if advanced} | ||||
| 									<span class="ml-2 self-center"> Custom </span> | ||||
| 									<span class="ml-2 self-center">{$i18n.t(' Custom ')}</span> | ||||
| 								{:else} | ||||
| 									<span class="ml-2 self-center"> Default </span> | ||||
| 									<span class="ml-2 self-center">{$i18n.t(' Default ')}</span> | ||||
| 								{/if} | ||||
| 							</button> | ||||
| 						</div> | ||||
| 
 | ||||
| 						{#if advanced} | ||||
| 							<div class="my-2"> | ||||
| 								<div class=" text-xs font-semibold mb-2">Template</div> | ||||
| 								<div class=" text-xs font-semibold mb-2">{$i18n.t('Template')}</div> | ||||
| 
 | ||||
| 								<div> | ||||
| 									<textarea | ||||
|  | @ -578,7 +584,7 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, ''); | |||
| 							</div> | ||||
| 
 | ||||
| 							<div class="my-2"> | ||||
| 								<div class=" text-xs font-semibold mb-2">Parameters</div> | ||||
| 								<div class=" text-xs font-semibold mb-2">{$i18n.t('Parameters')}</div> | ||||
| 
 | ||||
| 								<div> | ||||
| 									<AdvancedParams bind:options /> | ||||
|  | @ -590,7 +596,7 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, ''); | |||
| 
 | ||||
| 				<div class="my-2"> | ||||
| 					<div class="flex w-full justify-between mb-2"> | ||||
| 						<div class=" self-center text-sm font-semibold">Prompt suggestions</div> | ||||
| 						<div class=" self-center text-sm font-semibold">{$i18n.t('Prompt suggestions')}</div> | ||||
| 
 | ||||
| 						<button | ||||
| 							class="p-1 px-3 text-xs flex rounded transition" | ||||
|  | @ -647,7 +653,7 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, ''); | |||
| 				</div> | ||||
| 
 | ||||
| 				<div class="my-2"> | ||||
| 					<div class=" text-sm font-semibold mb-2">Categories</div> | ||||
| 					<div class=" text-sm font-semibold mb-2">{$i18n.t('Categories')}</div> | ||||
| 
 | ||||
| 					<div class="grid grid-cols-4"> | ||||
| 						{#each Object.keys(categories) as category} | ||||
|  | @ -661,7 +667,7 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, ''); | |||
| 
 | ||||
| 				{#if pullProgress !== null} | ||||
| 					<div class="my-2"> | ||||
| 						<div class=" text-sm font-semibold mb-2">Pull Progress</div> | ||||
| 						<div class=" text-sm font-semibold mb-2">{$i18n.t('Pull Progress')}</div> | ||||
| 						<div class="w-full rounded-full dark:bg-gray-800"> | ||||
| 							<div | ||||
| 								class="dark:bg-gray-600 bg-gray-500 text-xs font-medium text-gray-100 text-center p-0.5 leading-none rounded-full" | ||||
|  | @ -684,7 +690,7 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, ''); | |||
| 						type="submit" | ||||
| 						disabled={loading} | ||||
| 					> | ||||
| 						<div class=" self-center font-medium">Save & Create</div> | ||||
| 						<div class=" self-center font-medium">{$i18n.t('Save & Create')}</div> | ||||
| 
 | ||||
| 						{#if loading} | ||||
| 							<div class="ml-1.5 self-center"> | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ | |||
| 	import { toast } from 'svelte-sonner'; | ||||
| 	import { goto } from '$app/navigation'; | ||||
| 
 | ||||
| 	import { onMount } from 'svelte'; | ||||
| 	import { onMount, getContext } from 'svelte'; | ||||
| 	import { page } from '$app/stores'; | ||||
| 
 | ||||
| 	import { settings, user, config, modelfiles } from '$lib/stores'; | ||||
|  | @ -14,6 +14,8 @@ | |||
| 
 | ||||
| 	import AdvancedParams from '$lib/components/chat/Settings/Advanced/AdvancedParams.svelte'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	let loading = false; | ||||
| 
 | ||||
| 	let filesInputElement; | ||||
|  | @ -248,7 +250,7 @@ | |||
| 				}} | ||||
| 			/> | ||||
| 
 | ||||
| 			<div class=" text-2xl font-semibold mb-6">My Modelfiles</div> | ||||
| 			<div class=" text-2xl font-semibold mb-6">{$i18n.t('My Modelfiles')}</div> | ||||
| 
 | ||||
| 			<button | ||||
| 				class="flex space-x-1" | ||||
|  | @ -270,7 +272,7 @@ | |||
| 						/> | ||||
| 					</svg> | ||||
| 				</div> | ||||
| 				<div class=" self-center font-medium text-sm">Back</div> | ||||
| 				<div class=" self-center font-medium text-sm">{$i18n.t('Back')}</div> | ||||
| 			</button> | ||||
| 			<hr class="my-3 dark:border-gray-700" /> | ||||
| 
 | ||||
|  | @ -317,7 +319,7 @@ | |||
| 
 | ||||
| 				<div class="my-2 flex space-x-2"> | ||||
| 					<div class="flex-1"> | ||||
| 						<div class=" text-sm font-semibold mb-2">Name*</div> | ||||
| 						<div class=" text-sm font-semibold mb-2">{$i18n.t('Name')}*</div> | ||||
| 
 | ||||
| 						<div> | ||||
| 							<input | ||||
|  | @ -330,7 +332,7 @@ | |||
| 					</div> | ||||
| 
 | ||||
| 					<div class="flex-1"> | ||||
| 						<div class=" text-sm font-semibold mb-2">Model Tag Name*</div> | ||||
| 						<div class=" text-sm font-semibold mb-2">{$i18n.t('Model Tag Name')}*</div> | ||||
| 
 | ||||
| 						<div> | ||||
| 							<input | ||||
|  | @ -345,7 +347,7 @@ | |||
| 				</div> | ||||
| 
 | ||||
| 				<div class="my-2"> | ||||
| 					<div class=" text-sm font-semibold mb-2">Description*</div> | ||||
| 					<div class=" text-sm font-semibold mb-2">{$i18n.t('Description')}*</div> | ||||
| 
 | ||||
| 					<div> | ||||
| 						<input | ||||
|  | @ -359,13 +361,13 @@ | |||
| 
 | ||||
| 				<div class="my-2"> | ||||
| 					<div class="flex w-full justify-between"> | ||||
| 						<div class=" self-center text-sm font-semibold">Modelfile</div> | ||||
| 						<div class=" self-center text-sm font-semibold">{$i18n.t('Modelfile')}</div> | ||||
| 					</div> | ||||
| 
 | ||||
| 					<!-- <div class=" text-sm font-semibold mb-2"></div> --> | ||||
| 
 | ||||
| 					<div class="mt-2"> | ||||
| 						<div class=" text-xs font-semibold mb-2">Content*</div> | ||||
| 						<div class=" text-xs font-semibold mb-2">{$i18n.t('Content')}*</div> | ||||
| 
 | ||||
| 						<div> | ||||
| 							<textarea | ||||
|  | @ -381,7 +383,7 @@ | |||
| 
 | ||||
| 				<div class="my-2"> | ||||
| 					<div class="flex w-full justify-between mb-2"> | ||||
| 						<div class=" self-center text-sm font-semibold">Prompt suggestions</div> | ||||
| 						<div class=" self-center text-sm font-semibold">{$i18n.t('Prompt suggestions')}</div> | ||||
| 
 | ||||
| 						<button | ||||
| 							class="p-1 px-3 text-xs flex rounded transition" | ||||
|  | @ -438,7 +440,7 @@ | |||
| 				</div> | ||||
| 
 | ||||
| 				<div class="my-2"> | ||||
| 					<div class=" text-sm font-semibold mb-2">Categories</div> | ||||
| 					<div class=" text-sm font-semibold mb-2">{$i18n.t('Categories')}</div> | ||||
| 
 | ||||
| 					<div class="grid grid-cols-4"> | ||||
| 						{#each Object.keys(categories) as category} | ||||
|  | @ -453,7 +455,7 @@ | |||
| 
 | ||||
| 				{#if pullProgress !== null} | ||||
| 					<div class="my-2"> | ||||
| 						<div class=" text-sm font-semibold mb-2">Pull Progress</div> | ||||
| 						<div class=" text-sm font-semibold mb-2">{$i18n.t('Pull Progress')}</div> | ||||
| 						<div class="w-full rounded-full dark:bg-gray-800"> | ||||
| 							<div | ||||
| 								class="dark:bg-gray-600 text-xs font-medium text-blue-100 text-center p-0.5 leading-none rounded-full" | ||||
|  | @ -476,7 +478,7 @@ | |||
| 						type="submit" | ||||
| 						disabled={loading} | ||||
| 					> | ||||
| 						<div class=" self-center font-medium">Save & Update</div> | ||||
| 						<div class=" self-center font-medium">{$i18n.t('Save & Update')}</div> | ||||
| 
 | ||||
| 						{#if loading} | ||||
| 							<div class="ml-1.5 self-center"> | ||||
|  |  | |||
|  | @ -3,17 +3,19 @@ | |||
| 	import fileSaver from 'file-saver'; | ||||
| 	const { saveAs } = fileSaver; | ||||
| 
 | ||||
| 	import { onMount } from 'svelte'; | ||||
| 	import { onMount, getContext } from 'svelte'; | ||||
| 	import { WEBUI_NAME, prompts } from '$lib/stores'; | ||||
| 	import { createNewPrompt, deletePromptByCommand, getPrompts } from '$lib/apis/prompts'; | ||||
| 	import { error } from '@sveltejs/kit'; | ||||
| 	import { goto } from '$app/navigation'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	let importFiles = ''; | ||||
| 	let query = ''; | ||||
| 
 | ||||
| 	const sharePrompt = async (prompt) => { | ||||
| 		toast.success('Redirecting you to OpenWebUI Community'); | ||||
| 		toast.success($i18n.t('Redirecting you to OpenWebUI Community')); | ||||
| 
 | ||||
| 		const url = 'https://openwebui.com'; | ||||
| 
 | ||||
|  | @ -46,7 +48,7 @@ | |||
| 	<div class="flex flex-col justify-between w-full overflow-y-auto"> | ||||
| 		<div class="max-w-2xl mx-auto w-full px-3 md:px-0 my-10"> | ||||
| 			<div class="mb-6 flex justify-between items-center"> | ||||
| 				<div class=" text-2xl font-semibold self-center">My Prompts</div> | ||||
| 				<div class=" text-2xl font-semibold self-center">{$i18n.t('My Prompts')}</div> | ||||
| 			</div> | ||||
| 
 | ||||
| 			<div class=" flex w-full space-x-2"> | ||||
|  | @ -245,7 +247,7 @@ | |||
| 							document.getElementById('prompts-import-input')?.click(); | ||||
| 						}} | ||||
| 					> | ||||
| 						<div class=" self-center mr-2 font-medium">Import Prompts</div> | ||||
| 						<div class=" self-center mr-2 font-medium">{$i18n.t('Import Prompts')}</div> | ||||
| 
 | ||||
| 						<div class=" self-center"> | ||||
| 							<svg | ||||
|  | @ -273,7 +275,7 @@ | |||
| 							saveAs(blob, `prompts-export-${Date.now()}.json`); | ||||
| 						}} | ||||
| 					> | ||||
| 						<div class=" self-center mr-2 font-medium">Export Prompts</div> | ||||
| 						<div class=" self-center mr-2 font-medium">{$i18n.t('Export Prompts')}</div> | ||||
| 
 | ||||
| 						<div class=" self-center"> | ||||
| 							<svg | ||||
|  | @ -302,7 +304,7 @@ | |||
| 			</div> | ||||
| 
 | ||||
| 			<div class=" my-16"> | ||||
| 				<div class=" text-2xl font-semibold mb-3">Made by OpenWebUI Community</div> | ||||
| 				<div class=" text-2xl font-semibold mb-3">{$i18n.t('Made by OpenWebUI Community')}</div> | ||||
| 
 | ||||
| 				<a | ||||
| 					class=" flex space-x-4 cursor-pointer w-full mb-3 px-3 py-2" | ||||
|  | @ -329,8 +331,8 @@ | |||
| 					</div> | ||||
| 
 | ||||
| 					<div class=" self-center"> | ||||
| 						<div class=" font-bold">Discover a prompt</div> | ||||
| 						<div class=" text-sm">Discover, download, and explore custom prompts</div> | ||||
| 						<div class=" font-bold">{$i18n.t('Discover a prompt')}</div> | ||||
| 						<div class=" text-sm">{$i18n.t('Discover, download, and explore custom prompts')}</div> | ||||
| 					</div> | ||||
| 				</a> | ||||
| 			</div> | ||||
|  |  | |||
|  | @ -3,10 +3,12 @@ | |||
| 
 | ||||
| 	import { goto } from '$app/navigation'; | ||||
| 	import { prompts } from '$lib/stores'; | ||||
| 	import { onMount, tick } from 'svelte'; | ||||
| 	import { onMount, tick, getContext } from 'svelte'; | ||||
| 
 | ||||
| 	import { createNewPrompt, getPrompts } from '$lib/apis/prompts'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	let loading = false; | ||||
| 
 | ||||
| 	// /////////// | ||||
|  | @ -92,7 +94,7 @@ | |||
| <div class="min-h-screen max-h-[100dvh] w-full flex justify-center dark:text-white"> | ||||
| 	<div class=" flex flex-col justify-between w-full overflow-y-auto"> | ||||
| 		<div class="max-w-2xl mx-auto w-full px-3 md:px-0 my-10"> | ||||
| 			<div class=" text-2xl font-semibold mb-6">My Prompts</div> | ||||
| 			<div class=" text-2xl font-semibold mb-6">{$i18n.t('My Prompts')}</div> | ||||
| 
 | ||||
| 			<button | ||||
| 				class="flex space-x-1" | ||||
|  | @ -114,7 +116,7 @@ | |||
| 						/> | ||||
| 					</svg> | ||||
| 				</div> | ||||
| 				<div class=" self-center font-medium text-sm">Back</div> | ||||
| 				<div class=" self-center font-medium text-sm">{$i18n.t('Back')}</div> | ||||
| 			</button> | ||||
| 			<hr class="my-3 dark:border-gray-700" /> | ||||
| 
 | ||||
|  | @ -125,7 +127,7 @@ | |||
| 				}} | ||||
| 			> | ||||
| 				<div class="my-2"> | ||||
| 					<div class=" text-sm font-semibold mb-2">Title*</div> | ||||
| 					<div class=" text-sm font-semibold mb-2">{$i18n.t('Title')}*</div> | ||||
| 
 | ||||
| 					<div> | ||||
| 						<input | ||||
|  | @ -138,7 +140,7 @@ | |||
| 				</div> | ||||
| 
 | ||||
| 				<div class="my-2"> | ||||
| 					<div class=" text-sm font-semibold mb-2">Command*</div> | ||||
| 					<div class=" text-sm font-semibold mb-2">{$i18n.t('Command')}*</div> | ||||
| 
 | ||||
| 					<div class="flex items-center mb-1"> | ||||
| 						<div | ||||
|  | @ -168,7 +170,7 @@ | |||
| 
 | ||||
| 				<div class="my-2"> | ||||
| 					<div class="flex w-full justify-between"> | ||||
| 						<div class=" self-center text-sm font-semibold">Prompt Content*</div> | ||||
| 						<div class=" self-center text-sm font-semibold">{$i18n.t('Prompt Content')}*</div> | ||||
| 					</div> | ||||
| 
 | ||||
| 					<div class="mt-2"> | ||||
|  | @ -207,7 +209,7 @@ | |||
| 						type="submit" | ||||
| 						disabled={loading} | ||||
| 					> | ||||
| 						<div class=" self-center font-medium">Save & Create</div> | ||||
| 						<div class=" self-center font-medium">{$i18n.t('Save & Create')}</div> | ||||
| 
 | ||||
| 						{#if loading} | ||||
| 							<div class="ml-1.5 self-center"> | ||||
|  |  | |||
|  | @ -3,7 +3,9 @@ | |||
| 
 | ||||
| 	import { goto } from '$app/navigation'; | ||||
| 	import { prompts } from '$lib/stores'; | ||||
| 	import { onMount, tick } from 'svelte'; | ||||
| 	import { onMount, tick, getContext } from 'svelte'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	import { getPrompts, updatePromptByCommand } from '$lib/apis/prompts'; | ||||
| 	import { page } from '$app/stores'; | ||||
|  | @ -74,7 +76,7 @@ | |||
| <div class="min-h-screen max-h-[100dvh] w-full flex justify-center dark:text-white"> | ||||
| 	<div class="flex flex-col justify-between w-full overflow-y-auto"> | ||||
| 		<div class="max-w-2xl mx-auto w-full px-3 md:px-0 my-10"> | ||||
| 			<div class=" text-2xl font-semibold mb-6">My Prompts</div> | ||||
| 			<div class=" text-2xl font-semibold mb-6">{$i18n.t('My Prompts')}</div> | ||||
| 
 | ||||
| 			<button | ||||
| 				class="flex space-x-1" | ||||
|  | @ -96,7 +98,7 @@ | |||
| 						/> | ||||
| 					</svg> | ||||
| 				</div> | ||||
| 				<div class=" self-center font-medium text-sm">Back</div> | ||||
| 				<div class=" self-center font-medium text-sm">{$i18n.t('Back')}</div> | ||||
| 			</button> | ||||
| 			<hr class="my-3 dark:border-gray-700" /> | ||||
| 
 | ||||
|  | @ -107,7 +109,7 @@ | |||
| 				}} | ||||
| 			> | ||||
| 				<div class="my-2"> | ||||
| 					<div class=" text-sm font-semibold mb-2">Title*</div> | ||||
| 					<div class=" text-sm font-semibold mb-2">{$i18n.t('Title')}*</div> | ||||
| 
 | ||||
| 					<div> | ||||
| 						<input | ||||
|  | @ -120,7 +122,7 @@ | |||
| 				</div> | ||||
| 
 | ||||
| 				<div class="my-2"> | ||||
| 					<div class=" text-sm font-semibold mb-2">Command*</div> | ||||
| 					<div class=" text-sm font-semibold mb-2">{$i18n.t('Command')}*</div> | ||||
| 
 | ||||
| 					<div class="flex items-center mb-1"> | ||||
| 						<div | ||||
|  | @ -151,7 +153,7 @@ | |||
| 
 | ||||
| 				<div class="my-2"> | ||||
| 					<div class="flex w-full justify-between"> | ||||
| 						<div class=" self-center text-sm font-semibold">Prompt Content*</div> | ||||
| 						<div class=" self-center text-sm font-semibold">{$i18n.t('Prompt Content')}*</div> | ||||
| 					</div> | ||||
| 
 | ||||
| 					<div class="mt-2"> | ||||
|  | @ -184,7 +186,7 @@ | |||
| 						type="submit" | ||||
| 						disabled={loading} | ||||
| 					> | ||||
| 						<div class=" self-center font-medium">Save & Update</div> | ||||
| 						<div class=" self-center font-medium">{$i18n.t('Save & Update')}</div> | ||||
| 
 | ||||
| 						{#if loading} | ||||
| 							<div class="ml-1.5 self-center"> | ||||
|  |  | |||
|  | @ -3,9 +3,11 @@ | |||
| 	import { userSignIn, userSignUp } from '$lib/apis/auths'; | ||||
| 	import { WEBUI_API_BASE_URL, WEBUI_BASE_URL } from '$lib/constants'; | ||||
| 	import { WEBUI_NAME, config, user } from '$lib/stores'; | ||||
| 	import { onMount } from 'svelte'; | ||||
| 	import { onMount, getContext } from 'svelte'; | ||||
| 	import { toast } from 'svelte-sonner'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	let loaded = false; | ||||
| 	let mode = 'signin'; | ||||
| 
 | ||||
|  | @ -16,7 +18,7 @@ | |||
| 	const setSessionUser = async (sessionUser) => { | ||||
| 		if (sessionUser) { | ||||
| 			console.log(sessionUser); | ||||
| 			toast.success(`You're now logged in.`); | ||||
| 			toast.success($i18n.t(`You're now logged in.`)); | ||||
| 			localStorage.token = sessionUser.token; | ||||
| 			await user.set(sessionUser); | ||||
| 			goto('/'); | ||||
|  | @ -109,7 +111,7 @@ | |||
| 					<div class="flex flex-col mt-4"> | ||||
| 						{#if mode === 'signup'} | ||||
| 							<div> | ||||
| 								<div class=" text-sm font-semibold text-left mb-1">Name</div> | ||||
| 								<div class=" text-sm font-semibold text-left mb-1">{$i18n.t('Name')}</div> | ||||
| 								<input | ||||
| 									bind:value={name} | ||||
| 									type="text" | ||||
|  | @ -124,7 +126,7 @@ | |||
| 						{/if} | ||||
| 
 | ||||
| 						<div class="mb-2"> | ||||
| 							<div class=" text-sm font-semibold text-left mb-1">Email</div> | ||||
| 							<div class=" text-sm font-semibold text-left mb-1">{$i18n.t('Email')}</div> | ||||
| 							<input | ||||
| 								bind:value={email} | ||||
| 								type="email" | ||||
|  | @ -136,7 +138,7 @@ | |||
| 						</div> | ||||
| 
 | ||||
| 						<div> | ||||
| 							<div class=" text-sm font-semibold text-left mb-1">Password</div> | ||||
| 							<div class=" text-sm font-semibold text-left mb-1">{$i18n.t('Password')}</div> | ||||
| 							<input | ||||
| 								bind:value={password} | ||||
| 								type="password" | ||||
|  |  | |||
|  | @ -1,7 +1,9 @@ | |||
| <script> | ||||
| 	import { goto } from '$app/navigation'; | ||||
| 	import { WEBUI_NAME, config } from '$lib/stores'; | ||||
| 	import { onMount } from 'svelte'; | ||||
| 	import { onMount, getContext } from 'svelte'; | ||||
| 
 | ||||
| 	const i18n = getContext('i18n'); | ||||
| 
 | ||||
| 	let loaded = false; | ||||
| 
 | ||||
|  | @ -19,22 +21,25 @@ | |||
| 		<div class="absolute rounded-xl w-full h-full backdrop-blur flex justify-center"> | ||||
| 			<div class="m-auto pb-44 flex flex-col justify-center"> | ||||
| 				<div class="max-w-md"> | ||||
| 					<div class="text-center text-2xl font-medium z-50">{$WEBUI_NAME} Backend Required</div> | ||||
| 					<div class="text-center text-2xl font-medium z-50"> | ||||
| 						{$i18n.t('{{webui_name}} Backend Required', { webui_name: $WEBUI_NAME })} | ||||
| 					</div> | ||||
| 
 | ||||
| 					<div class=" mt-4 text-center text-sm w-full"> | ||||
| 						Oops! You're using an unsupported method (frontend only). Please serve the WebUI from | ||||
| 						the backend. | ||||
| 						{$i18n.t( | ||||
| 							"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend." | ||||
| 						)} | ||||
| 
 | ||||
| 						<br class=" " /> | ||||
| 						<br class=" " /> | ||||
| 						<a | ||||
| 							class=" font-semibold underline" | ||||
| 							href="https://github.com/open-webui/open-webui#how-to-install-" | ||||
| 							target="_blank">See readme.md for instructions</a | ||||
| 							target="_blank">{$i18n.t('See readme.md for instructions')}</a | ||||
| 						> | ||||
| 						or | ||||
| 						{$i18n.t('or')} | ||||
| 						<a class=" font-semibold underline" href="https://discord.gg/5rJgQTnV4s" target="_blank" | ||||
| 							>join our Discord for help.</a | ||||
| 							>{$i18n.t('join our Discord for help.')}</a | ||||
| 						> | ||||
| 					</div> | ||||
| 
 | ||||
|  | @ -45,7 +50,7 @@ | |||
| 								location.href = '/'; | ||||
| 							}} | ||||
| 						> | ||||
| 							Check Again | ||||
| 							{$i18n.t('Check Again')} | ||||
| 						</button> | ||||
| 					</div> | ||||
| 				</div> | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue