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