+layout.svelte 4.09 KB
Newer Older
Timothy J. Baek's avatar
Timothy J. Baek committed
1
<script>
Timothy J. Baek's avatar
Timothy J. Baek committed
2
	import { io } from 'socket.io-client';
Timothy J. Baek's avatar
Timothy J. Baek committed
3
4
5
	import { spring } from 'svelte/motion';

	let loadingProgress = spring(0);
Timothy J. Baek's avatar
Timothy J. Baek committed
6

7
	import { onMount, tick, setContext } from 'svelte';
8
9
10
11
12
13
14
15
16
17
	import {
		config,
		user,
		theme,
		WEBUI_NAME,
		mobile,
		socket,
		activeUserCount,
		USAGE_POOL
	} from '$lib/stores';
18
	import { goto } from '$app/navigation';
Jannik Streidl's avatar
Jannik Streidl committed
19
	import { Toaster, toast } from 'svelte-sonner';
Timothy J. Baek's avatar
Timothy J. Baek committed
20

Timothy J. Baek's avatar
Timothy J. Baek committed
21
22
23
	import { getBackendConfig } from '$lib/apis';
	import { getSessionUser } from '$lib/apis/auths';

Timothy J. Baek's avatar
Timothy J. Baek committed
24
	import '../tailwind.css';
Timothy J. Baek's avatar
Timothy J. Baek committed
25
26
	import '../app.css';

Timothy J. Baek's avatar
Timothy J. Baek committed
27
	import 'tippy.js/dist/tippy.css';
Timothy J. Baek's avatar
Timothy J. Baek committed
28

Timothy J. Baek's avatar
Timothy J. Baek committed
29
	import { WEBUI_BASE_URL, WEBUI_HOSTNAME } from '$lib/constants';
30
	import i18n, { initI18n, getLanguages } from '$lib/i18n';
31
32

	setContext('i18n', i18n);
Timothy J. Baek's avatar
Timothy J. Baek committed
33

34
	let loaded = false;
Timothy J. Baek's avatar
Timothy J. Baek committed
35
	const BREAKPOINT = 768;
36
37

	onMount(async () => {
Timothy J. Baek's avatar
Timothy J. Baek committed
38
		theme.set(localStorage.theme);
39
40
41
42
43
44
45
46
47
48
49
50

		mobile.set(window.innerWidth < BREAKPOINT);
		const onResize = () => {
			if (window.innerWidth < BREAKPOINT) {
				mobile.set(true);
			} else {
				mobile.set(false);
			}
		};

		window.addEventListener('resize', onResize);

Aarni Koskela's avatar
Aarni Koskela committed
51
52
53
		let backendConfig = null;
		try {
			backendConfig = await getBackendConfig();
54
			console.log('Backend config:', backendConfig);
Aarni Koskela's avatar
Aarni Koskela committed
55
		} catch (error) {
56
			console.error('Error loading backend config:', error);
Aarni Koskela's avatar
Aarni Koskela committed
57
58
59
		}
		// Initialize i18n even if we didn't get a backend config,
		// so `/error` can show something that's not `undefined`.
60
61
62
63
64
65
66
67

		const languages = await getLanguages();

		const browserLanguage = navigator.languages
			? navigator.languages[0]
			: navigator.language || navigator.userLanguage;

		initI18n(languages.includes(browserLanguage) ? browserLanguage : backendConfig?.default_locale);
68

Timothy J. Baek's avatar
Timothy J. Baek committed
69
		if (backendConfig) {
Timothy J. Baek's avatar
Timothy J. Baek committed
70
			// Save Backend Status to Store
Timothy J. Baek's avatar
Timothy J. Baek committed
71
			await config.set(backendConfig);
72
			await WEBUI_NAME.set(backendConfig.name);
73

74
			if ($config) {
Timothy J. Baek's avatar
Timothy J. Baek committed
75
76
77
78
79
80
81
82
83
				const _socket = io(`${WEBUI_BASE_URL}`, {
					path: '/ws/socket.io',
					auth: { token: localStorage.token }
				});

				_socket.on('connect', () => {
					console.log('connected');
				});

Timothy J. Baek's avatar
Timothy J. Baek committed
84
85
86
87
88
89
				await socket.set(_socket);

				_socket.on('user-count', (data) => {
					console.log('user-count', data);
					activeUserCount.set(data.count);
				});
Timothy J. Baek's avatar
Timothy J. Baek committed
90

91
92
93
94
95
				_socket.on('usage', (data) => {
					console.log('usage', data);
					USAGE_POOL.set(data['models']);
				});

96
				if (localStorage.token) {
97
					// Get Session User Info
Timothy J. Baek's avatar
Timothy J. Baek committed
98
99
100
101
					const sessionUser = await getSessionUser(localStorage.token).catch((error) => {
						toast.error(error);
						return null;
					});
102

103
					if (sessionUser) {
Timothy J. Baek's avatar
Timothy J. Baek committed
104
						// Save Session User to Store
105
						await user.set(sessionUser);
Timothy J. Baek's avatar
Timothy J. Baek committed
106
					} else {
Timothy J. Baek's avatar
Timothy J. Baek committed
107
						// Redirect Invalid Session User to /auth Page
Timothy J. Baek's avatar
Timothy J. Baek committed
108
109
110
						localStorage.removeItem('token');
						await goto('/auth');
					}
111
				} else {
Timothy J. Baek's avatar
Timothy J. Baek committed
112
					await goto('/auth');
113
114
				}
			}
115
		} else {
Timothy J. Baek's avatar
Timothy J. Baek committed
116
			// Redirect to /error when Backend Not Detected
117
			await goto(`/error`);
118
119
120
		}

		await tick();
Timothy J. Baek's avatar
Timothy J. Baek committed
121

Timothy J. Baek's avatar
Timothy J. Baek committed
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
		if (
			document.documentElement.classList.contains('her') &&
			document.getElementById('progress-bar')
		) {
			loadingProgress.subscribe((value) => {
				document.getElementById('progress-bar').style.width = `${value * 0.24}rem`;
			});

			await loadingProgress.set(100);

			document.getElementById('splash-screen')?.remove();

			const audio = new Audio(`/audio/greeting.mp3`);
			const playAudio = () => {
				audio.play();
				document.removeEventListener('click', playAudio);
			};

			document.addEventListener('click', playAudio);

			loaded = true;
		} else {
			document.getElementById('splash-screen')?.remove();
			loaded = true;
		}
147
148
149
150

		return () => {
			window.removeEventListener('resize', onResize);
		};
151
	});
Timothy J. Baek's avatar
Timothy J. Baek committed
152
153
154
</script>

<svelte:head>
155
	<title>{$WEBUI_NAME}</title>
Timothy J. Baek's avatar
Timothy J. Baek committed
156
	<link crossorigin="anonymous" rel="icon" href="{WEBUI_BASE_URL}/static/favicon.png" />
Timothy J. Baek's avatar
Timothy J. Baek committed
157

Timothy J. Baek's avatar
Timothy J. Baek committed
158
159
	<!-- rosepine themes have been disabled as it's not up to date with our latest version. -->
	<!-- feel free to make a PR to fix if anyone wants to see it return -->
160
161
	<!-- <link rel="stylesheet" type="text/css" href="/themes/rosepine.css" />
	<link rel="stylesheet" type="text/css" href="/themes/rosepine-dawn.css" /> -->
Timothy J. Baek's avatar
Timothy J. Baek committed
162
</svelte:head>
163

164
{#if loaded}
165
166
	<slot />
{/if}
167

Timothy J. Baek's avatar
Timothy J. Baek committed
168
<Toaster richColors position="top-center" />