forked from open-webui/open-webui
		
	feat: multi-user support w/ RBAC
This commit is contained in:
		
							parent
							
								
									31e38df0a5
								
							
						
					
					
						commit
						921eef03b3
					
				
					 21 changed files with 1815 additions and 66 deletions
				
			
		|  | @ -4,8 +4,13 @@ | |||
| 	font-display: swap; | ||||
| } | ||||
| 
 | ||||
| @font-face { | ||||
| 	font-family: 'Mona Sans'; | ||||
| 	src: url('/assets/fonts/Mona-Sans.woff2'); | ||||
| 	font-display: swap; | ||||
| } | ||||
| 
 | ||||
| html { | ||||
| 	@apply bg-gray-800; | ||||
| 	word-break: break-word; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,9 +2,10 @@ | |||
| 	import sha256 from 'js-sha256'; | ||||
| 	import Modal from '../common/Modal.svelte'; | ||||
| 
 | ||||
| 	import { WEB_UI_VERSION, API_BASE_URL as BUILD_TIME_API_BASE_URL } from '$lib/constants'; | ||||
| 	import { WEB_UI_VERSION, OLLAMA_API_BASE_URL as BUILD_TIME_API_BASE_URL } from '$lib/constants'; | ||||
| 	import toast from 'svelte-french-toast'; | ||||
| 	import { onMount } from 'svelte'; | ||||
| 	import { config, user } from '$lib/stores'; | ||||
| 
 | ||||
| 	export let show = false; | ||||
| 	export let saveSettings: Function; | ||||
|  | @ -119,7 +120,8 @@ | |||
| 		const res = await fetch(`${API_BASE_URL}/pull`, { | ||||
| 			method: 'POST', | ||||
| 			headers: { | ||||
| 				'Content-Type': 'text/event-stream' | ||||
| 				'Content-Type': 'text/event-stream', | ||||
| 				...($user && { Authorization: `Bearer ${localStorage.token}` }) | ||||
| 			}, | ||||
| 			body: JSON.stringify({ | ||||
| 				name: modelTag | ||||
|  | @ -175,7 +177,8 @@ | |||
| 		const res = await fetch(`${API_BASE_URL}/delete`, { | ||||
| 			method: 'DELETE', | ||||
| 			headers: { | ||||
| 				'Content-Type': 'text/event-stream' | ||||
| 				'Content-Type': 'text/event-stream', | ||||
| 				...($user && { Authorization: `Bearer ${localStorage.token}` }) | ||||
| 			}, | ||||
| 			body: JSON.stringify({ | ||||
| 				name: deleteModelTag | ||||
|  | @ -992,7 +995,7 @@ | |||
| 								<div class=" mb-2.5 text-sm font-medium">Ollama Web UI Version</div> | ||||
| 								<div class="flex w-full"> | ||||
| 									<div class="flex-1 text-xs text-gray-700 dark:text-gray-200"> | ||||
| 										{WEB_UI_VERSION} | ||||
| 										{$config && $config.version ? $config.version : WEB_UI_VERSION} | ||||
| 									</div> | ||||
| 								</div> | ||||
| 							</div> | ||||
|  |  | |||
|  | @ -1,4 +1,6 @@ | |||
| <script lang="ts"> | ||||
| 	import { goto } from '$app/navigation'; | ||||
| 	import { user } from '$lib/stores'; | ||||
| 	import { onMount } from 'svelte'; | ||||
| 
 | ||||
| 	let show = false; | ||||
|  | @ -22,9 +24,9 @@ | |||
| 	let chatTitleEditIdx = null; | ||||
| 	let chatTitle = ''; | ||||
| 
 | ||||
| 	let _chats = chats.map((item, idx) => chats[chats.length - 1 - idx]); | ||||
| 	let showDropdown = false; | ||||
| 
 | ||||
| 	onMount(() => {}); | ||||
| 	let _chats = chats.map((item, idx) => chats[chats.length - 1 - idx]); | ||||
| 
 | ||||
| 	$: if (chats) { | ||||
| 		_chats = chats.map((item, idx) => chats[chats.length - 1 - idx]); | ||||
|  | @ -98,6 +100,7 @@ | |||
| 			<button | ||||
| 				class="flex-grow flex justify-between rounded-md px-3 py-1.5 my-2 hover:bg-gray-900 transition" | ||||
| 				on:click={() => { | ||||
| 					// goto('/'); | ||||
| 					createNewChat(); | ||||
| 				}} | ||||
| 			> | ||||
|  | @ -163,6 +166,7 @@ | |||
| 							? 'bg-gray-900' | ||||
| 							: ''} transition whitespace-nowrap text-ellipsis" | ||||
| 						on:click={() => { | ||||
| 							// goto(`/c/${chat.id}`); | ||||
| 							if (chat.id !== chatTitleEditIdx) { | ||||
| 								chatTitleEditIdx = null; | ||||
| 								chatTitle = ''; | ||||
|  | @ -380,35 +384,127 @@ | |||
| 					</div> | ||||
| 					<div class=" self-center">Clear conversations</div> | ||||
| 				</button> | ||||
| 				<button | ||||
| 					class=" flex rounded-md py-3 px-3.5 w-full hover:bg-gray-900 transition" | ||||
| 					on:click={() => { | ||||
| 						openSettings(); | ||||
| 					}} | ||||
| 				> | ||||
| 					<div class=" self-center mr-3"> | ||||
| 						<svg | ||||
| 							xmlns="http://www.w3.org/2000/svg" | ||||
| 							fill="none" | ||||
| 							viewBox="0 0 24 24" | ||||
| 							stroke-width="1.5" | ||||
| 							stroke="currentColor" | ||||
| 							class="w-5 h-5" | ||||
| 
 | ||||
| 				{#if $user !== undefined} | ||||
| 					<button | ||||
| 						class=" flex rounded-md py-3 px-3.5 w-full hover:bg-gray-900 transition" | ||||
| 						on:focus={() => { | ||||
| 							showDropdown = true; | ||||
| 						}} | ||||
| 						on:focusout={() => { | ||||
| 							setTimeout(() => { | ||||
| 								showDropdown = false; | ||||
| 							}, 100); | ||||
| 						}} | ||||
| 					> | ||||
| 						<div class=" self-center mr-3"> | ||||
| 							<img src="/user.png" class=" max-w-[30px] object-cover rounded-full" /> | ||||
| 						</div> | ||||
| 						<div class=" self-center font-semibold">{$user.name}</div> | ||||
| 					</button> | ||||
| 
 | ||||
| 					{#if showDropdown} | ||||
| 						<div | ||||
| 							id="dropdownDots" | ||||
| 							class="absolute z-10 bottom-[4.5rem] rounded-lg shadow w-[240px] bg-gray-900" | ||||
| 						> | ||||
| 							<path | ||||
| 								stroke-linecap="round" | ||||
| 								stroke-linejoin="round" | ||||
| 								d="M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 011.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 01-1.449.12l-.738-.527c-.35-.25-.806-.272-1.203-.107-.397.165-.71.505-.781.929l-.149.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 01-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.505-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.107-1.204l-.527-.738a1.125 1.125 0 01.12-1.45l.773-.773a1.125 1.125 0 011.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894z" | ||||
| 							/> | ||||
| 							<path | ||||
| 								stroke-linecap="round" | ||||
| 								stroke-linejoin="round" | ||||
| 								d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" | ||||
| 							/> | ||||
| 						</svg> | ||||
| 					</div> | ||||
| 					<div class=" self-center font-medium">Settings</div> | ||||
| 				</button> | ||||
| 							<div class="py-2 w-full"> | ||||
| 								<button | ||||
| 									class="flex py-2.5 px-3.5 w-full hover:bg-gray-800 transition" | ||||
| 									on:click={() => { | ||||
| 										openSettings(); | ||||
| 									}} | ||||
| 								> | ||||
| 									<div class=" self-center mr-3"> | ||||
| 										<svg | ||||
| 											xmlns="http://www.w3.org/2000/svg" | ||||
| 											fill="none" | ||||
| 											viewBox="0 0 24 24" | ||||
| 											stroke-width="1.5" | ||||
| 											stroke="currentColor" | ||||
| 											class="w-5 h-5" | ||||
| 										> | ||||
| 											<path | ||||
| 												stroke-linecap="round" | ||||
| 												stroke-linejoin="round" | ||||
| 												d="M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 011.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 01-1.449.12l-.738-.527c-.35-.25-.806-.272-1.203-.107-.397.165-.71.505-.781.929l-.149.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 01-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.505-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.107-1.204l-.527-.738a1.125 1.125 0 01.12-1.45l.773-.773a1.125 1.125 0 011.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894z" | ||||
| 											/> | ||||
| 											<path | ||||
| 												stroke-linecap="round" | ||||
| 												stroke-linejoin="round" | ||||
| 												d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" | ||||
| 											/> | ||||
| 										</svg> | ||||
| 									</div> | ||||
| 									<div class=" self-center font-medium">Settings</div> | ||||
| 								</button> | ||||
| 							</div> | ||||
| 
 | ||||
| 							<hr class=" dark:border-gray-700 m-0 p-0" /> | ||||
| 
 | ||||
| 							<div class="py-2 w-full"> | ||||
| 								<button | ||||
| 									class="flex py-2.5 px-3.5 w-full hover:bg-gray-800 transition" | ||||
| 									on:click={() => { | ||||
| 										localStorage.removeItem('token'); | ||||
| 										location.href = '/'; | ||||
| 									}} | ||||
| 								> | ||||
| 									<div class=" self-center mr-3"> | ||||
| 										<svg | ||||
| 											xmlns="http://www.w3.org/2000/svg" | ||||
| 											viewBox="0 0 20 20" | ||||
| 											fill="currentColor" | ||||
| 											class="w-5 h-5" | ||||
| 										> | ||||
| 											<path | ||||
| 												fill-rule="evenodd" | ||||
| 												d="M3 4.25A2.25 2.25 0 015.25 2h5.5A2.25 2.25 0 0113 4.25v2a.75.75 0 01-1.5 0v-2a.75.75 0 00-.75-.75h-5.5a.75.75 0 00-.75.75v11.5c0 .414.336.75.75.75h5.5a.75.75 0 00.75-.75v-2a.75.75 0 011.5 0v2A2.25 2.25 0 0110.75 18h-5.5A2.25 2.25 0 013 15.75V4.25z" | ||||
| 												clip-rule="evenodd" | ||||
| 											/> | ||||
| 											<path | ||||
| 												fill-rule="evenodd" | ||||
| 												d="M6 10a.75.75 0 01.75-.75h9.546l-1.048-.943a.75.75 0 111.004-1.114l2.5 2.25a.75.75 0 010 1.114l-2.5 2.25a.75.75 0 11-1.004-1.114l1.048-.943H6.75A.75.75 0 016 10z" | ||||
| 												clip-rule="evenodd" | ||||
| 											/> | ||||
| 										</svg> | ||||
| 									</div> | ||||
| 									<div class=" self-center font-medium">Sign Out</div> | ||||
| 								</button> | ||||
| 							</div> | ||||
| 						</div> | ||||
| 					{/if} | ||||
| 				{:else} | ||||
| 					<button | ||||
| 						class=" flex rounded-md py-3 px-3.5 w-full hover:bg-gray-900 transition" | ||||
| 						on:click={() => { | ||||
| 							openSettings(); | ||||
| 						}} | ||||
| 					> | ||||
| 						<div class=" self-center mr-3"> | ||||
| 							<svg | ||||
| 								xmlns="http://www.w3.org/2000/svg" | ||||
| 								fill="none" | ||||
| 								viewBox="0 0 24 24" | ||||
| 								stroke-width="1.5" | ||||
| 								stroke="currentColor" | ||||
| 								class="w-5 h-5" | ||||
| 							> | ||||
| 								<path | ||||
| 									stroke-linecap="round" | ||||
| 									stroke-linejoin="round" | ||||
| 									d="M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 011.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 01-1.449.12l-.738-.527c-.35-.25-.806-.272-1.203-.107-.397.165-.71.505-.781.929l-.149.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 01-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.505-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.107-1.204l-.527-.738a1.125 1.125 0 01.12-1.45l.773-.773a1.125 1.125 0 011.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894z" | ||||
| 								/> | ||||
| 								<path | ||||
| 									stroke-linecap="round" | ||||
| 									stroke-linejoin="round" | ||||
| 									d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" | ||||
| 								/> | ||||
| 							</svg> | ||||
| 						</div> | ||||
| 						<div class=" self-center font-medium">Settings</div> | ||||
| 					</button> | ||||
| 				{/if} | ||||
| 			</div> | ||||
| 		</div> | ||||
| 	</div> | ||||
|  |  | |||
|  | @ -1,14 +1,16 @@ | |||
| import { browser } from '$app/environment'; | ||||
| import { dev, browser } from '$app/environment'; | ||||
| import { PUBLIC_API_BASE_URL } from '$env/static/public'; | ||||
| 
 | ||||
| export const API_BASE_URL = | ||||
| export const OLLAMA_API_BASE_URL = | ||||
| 	PUBLIC_API_BASE_URL === '' | ||||
| 		? browser | ||||
| 			? `http://${location.hostname}:11434/api` | ||||
| 			? `http://${location.hostname}:8080/ollama/api` | ||||
| 			: `http://localhost:11434/api` | ||||
| 		: PUBLIC_API_BASE_URL; | ||||
| 
 | ||||
| export const WEB_UI_VERSION = 'v1.0.0-alpha.8'; | ||||
| export const WEBUI_API_BASE_URL = dev ? `http://${location.hostname}:8080/api/v1` : `/api/v1`; | ||||
| 
 | ||||
| export const WEB_UI_VERSION = 'v1.0.0-alpha-static'; | ||||
| 
 | ||||
| // Source: https://kit.svelte.dev/docs/modules#$env-static-public
 | ||||
| // This feature, akin to $env/static/private, exclusively incorporates environment variables
 | ||||
|  |  | |||
							
								
								
									
										4
									
								
								src/lib/stores/index.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/lib/stores/index.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,4 @@ | |||
| import { writable } from 'svelte/store'; | ||||
| 
 | ||||
| export const config = writable(undefined); | ||||
| export const user = writable(undefined); | ||||
							
								
								
									
										12
									
								
								src/routes/(app)/+layout.svelte
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/routes/(app)/+layout.svelte
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | |||
| <script> | ||||
| 	import { config, user } from '$lib/stores'; | ||||
| 	import { goto } from '$app/navigation'; | ||||
| 
 | ||||
| 	if ($config && $config.auth && $user === undefined) { | ||||
| 		goto('/auth'); | ||||
| 	} | ||||
| </script> | ||||
| 
 | ||||
| {#if $config !== undefined} | ||||
| 	<slot /> | ||||
| {/if} | ||||
|  | @ -10,17 +10,17 @@ | |||
| 	import 'katex/dist/katex.min.css'; | ||||
| 	import toast from 'svelte-french-toast'; | ||||
| 
 | ||||
| 	import { API_BASE_URL as BUILD_TIME_API_BASE_URL } from '$lib/constants'; | ||||
| 	import { OLLAMA_API_BASE_URL as BUILD_TIME_API_BASE_URL } from '$lib/constants'; | ||||
| 	import { onMount, tick } from 'svelte'; | ||||
| 
 | ||||
| 	import Navbar from '$lib/components/layout/Navbar.svelte'; | ||||
| 	import SettingsModal from '$lib/components/chat/SettingsModal.svelte'; | ||||
| 	import Suggestions from '$lib/components/chat/Suggestions.svelte'; | ||||
| 	import { user } from '$lib/stores'; | ||||
| 
 | ||||
| 	let API_BASE_URL = BUILD_TIME_API_BASE_URL; | ||||
| 	let db; | ||||
| 
 | ||||
| 	// let selectedModel = ''; | ||||
| 	let selectedModels = ['']; | ||||
| 	let settings = { | ||||
| 		system: null, | ||||
|  | @ -619,7 +619,8 @@ | |||
| 			headers: { | ||||
| 				Accept: 'application/json', | ||||
| 				'Content-Type': 'application/json', | ||||
| 				...(settings.authHeader && { Authorization: settings.authHeader }) | ||||
| 				...(settings.authHeader && { Authorization: settings.authHeader }), | ||||
| 				...($user && { Authorization: `Bearer ${localStorage.token}` }) | ||||
| 			} | ||||
| 		}) | ||||
| 			.then(async (res) => { | ||||
|  | @ -628,7 +629,11 @@ | |||
| 			}) | ||||
| 			.catch((error) => { | ||||
| 				console.log(error); | ||||
| 				toast.error('Server connection failed'); | ||||
| 				if ('detail' in error) { | ||||
| 					toast.error(error.detail); | ||||
| 				} else { | ||||
| 					toast.error('Server connection failed'); | ||||
| 				} | ||||
| 				return null; | ||||
| 			}); | ||||
| 
 | ||||
|  | @ -687,13 +692,6 @@ | |||
| 				} | ||||
| 			}) | ||||
| 		); | ||||
| 
 | ||||
| 		// if (selectedModel.includes('gpt-')) { | ||||
| 		// 	await sendPromptOpenAI(userPrompt, parentId); | ||||
| 		// } else { | ||||
| 		// 	await sendPromptOllama(userPrompt, parentId); | ||||
| 		// } | ||||
| 
 | ||||
| 		console.log(history); | ||||
| 	}; | ||||
| 
 | ||||
|  | @ -724,7 +722,8 @@ | |||
| 			method: 'POST', | ||||
| 			headers: { | ||||
| 				'Content-Type': 'text/event-stream', | ||||
| 				...(settings.authHeader && { Authorization: settings.authHeader }) | ||||
| 				...(settings.authHeader && { Authorization: settings.authHeader }), | ||||
| 				...($user && { Authorization: `Bearer ${localStorage.token}` }) | ||||
| 			}, | ||||
| 			body: JSON.stringify({ | ||||
| 				model: model, | ||||
|  | @ -779,6 +778,8 @@ | |||
| 								responseMessage.content += data.response; | ||||
| 								messages = messages; | ||||
| 							} | ||||
| 						} else if ('detail' in data) { | ||||
| 							throw data; | ||||
| 						} else { | ||||
| 							responseMessage.done = true; | ||||
| 							responseMessage.context = data.context; | ||||
|  | @ -791,6 +792,10 @@ | |||
| 				} | ||||
| 			} catch (error) { | ||||
| 				console.log(error); | ||||
| 				if ('detail' in error) { | ||||
| 					toast.error(error.detail); | ||||
| 				} | ||||
| 				break; | ||||
| 			} | ||||
| 
 | ||||
| 			if (autoScroll) { | ||||
|  | @ -817,7 +822,7 @@ | |||
| 			window.scrollTo({ top: document.body.scrollHeight }); | ||||
| 		} | ||||
| 
 | ||||
| 		if (messages.length == 2) { | ||||
| 		if (messages.length == 2 && messages.at(1).content !== '') { | ||||
| 			await generateChatTitle(chatId, userPrompt); | ||||
| 		} | ||||
| 	}; | ||||
|  | @ -1034,7 +1039,8 @@ | |||
| 			method: 'POST', | ||||
| 			headers: { | ||||
| 				'Content-Type': 'text/event-stream', | ||||
| 				...(settings.authHeader && { Authorization: settings.authHeader }) | ||||
| 				...(settings.authHeader && { Authorization: settings.authHeader }), | ||||
| 				...($user && { Authorization: `Bearer ${localStorage.token}` }) | ||||
| 			}, | ||||
| 			body: JSON.stringify({ | ||||
| 				model: selectedModels[0], | ||||
|  | @ -1047,6 +1053,9 @@ | |||
| 				return res.json(); | ||||
| 			}) | ||||
| 			.catch((error) => { | ||||
| 				if ('detail' in error) { | ||||
| 					toast.error(error.detail); | ||||
| 				} | ||||
| 				console.log(error); | ||||
| 				return null; | ||||
| 			}); | ||||
							
								
								
									
										0
									
								
								src/routes/(app)/c/[id]/+page.svelte
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								src/routes/(app)/c/[id]/+page.svelte
									
										
									
									
									
										Normal file
									
								
							|  | @ -1,13 +1,71 @@ | |||
| <script> | ||||
| 	import { Toaster } from 'svelte-french-toast'; | ||||
| 	import { onMount, tick } from 'svelte'; | ||||
| 	import { config, user } from '$lib/stores'; | ||||
| 	import { goto } from '$app/navigation'; | ||||
| 	import { WEBUI_API_BASE_URL } from '$lib/constants'; | ||||
| 	import toast, { Toaster } from 'svelte-french-toast'; | ||||
| 
 | ||||
| 	import '../app.css'; | ||||
| 	import '../tailwind.css'; | ||||
| 
 | ||||
| 	let loaded = false; | ||||
| 
 | ||||
| 	onMount(async () => { | ||||
| 		const webBackendStatus = await fetch(`${WEBUI_API_BASE_URL}/`, { | ||||
| 			method: 'GET', | ||||
| 			headers: { | ||||
| 				'Content-Type': 'application/json' | ||||
| 			} | ||||
| 		}) | ||||
| 			.then(async (res) => { | ||||
| 				if (!res.ok) throw await res.json(); | ||||
| 				return res.json(); | ||||
| 			}) | ||||
| 			.catch((error) => { | ||||
| 				console.log(error); | ||||
| 				return null; | ||||
| 			}); | ||||
| 
 | ||||
| 		console.log(webBackendStatus); | ||||
| 		await config.set(webBackendStatus); | ||||
| 
 | ||||
| 		if (webBackendStatus) { | ||||
| 			if (webBackendStatus.auth) { | ||||
| 				if (localStorage.token) { | ||||
| 					const res = await fetch(`${WEBUI_API_BASE_URL}/auths`, { | ||||
| 						method: 'GET', | ||||
| 						headers: { | ||||
| 							'Content-Type': 'application/json', | ||||
| 							Authorization: `Bearer ${localStorage.token}` | ||||
| 						} | ||||
| 					}) | ||||
| 						.then(async (res) => { | ||||
| 							if (!res.ok) throw await res.json(); | ||||
| 							return res.json(); | ||||
| 						}) | ||||
| 						.catch((error) => { | ||||
| 							console.log(error); | ||||
| 							toast.error(error.detail); | ||||
| 							return null; | ||||
| 						}); | ||||
| 
 | ||||
| 					await user.set(res); | ||||
| 				} else { | ||||
| 					goto('/auth'); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		await tick(); | ||||
| 		loaded = true; | ||||
| 	}); | ||||
| </script> | ||||
| 
 | ||||
| <svelte:head> | ||||
| 	<title>Ollama</title> | ||||
| </svelte:head> | ||||
| 
 | ||||
| <slot /> | ||||
| <Toaster /> | ||||
| 
 | ||||
| {#if $config !== undefined && loaded} | ||||
| 	<slot /> | ||||
| {/if} | ||||
|  |  | |||
							
								
								
									
										1091
									
								
								src/routes/auth/+page.svelte
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1091
									
								
								src/routes/auth/+page.svelte
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Timothy J. Baek
						Timothy J. Baek