Commit ae376ec8 authored by Jun Siang Cheah's avatar Jun Siang Cheah
Browse files

Merge remote-tracking branch 'upstream/dev' into feat/oauth

parents af4f8aa5 1bb7fc7c
...@@ -36,6 +36,9 @@ ...@@ -36,6 +36,9 @@
import Tooltip from '$lib/components/common/Tooltip.svelte'; import Tooltip from '$lib/components/common/Tooltip.svelte';
import { getBanners } from '$lib/apis/configs'; import { getBanners } from '$lib/apis/configs';
import { getUserSettings } from '$lib/apis/users'; import { getUserSettings } from '$lib/apis/users';
import Help from '$lib/components/layout/Help.svelte';
import AccountPending from '$lib/components/layout/Overlay/AccountPending.svelte';
import { error } from '@sveltejs/kit';
const i18n = getContext('i18n'); const i18n = getContext('i18n');
...@@ -73,7 +76,10 @@ ...@@ -73,7 +76,10 @@
// IndexedDB Not Found // IndexedDB Not Found
} }
const userSettings = await getUserSettings(localStorage.token); const userSettings = await getUserSettings(localStorage.token).catch((error) => {
console.error(error);
return null;
});
if (userSettings) { if (userSettings) {
await settings.set(userSettings.ui); await settings.set(userSettings.ui);
...@@ -160,7 +166,7 @@ ...@@ -160,7 +166,7 @@
if (isCtrlPressed && event.key === '/') { if (isCtrlPressed && event.key === '/') {
event.preventDefault(); event.preventDefault();
console.log('showShortcuts'); console.log('showShortcuts');
showShortcutsButtonElement.click(); document.getElementById('show-shortcuts-button')?.click();
} }
}); });
...@@ -175,69 +181,17 @@ ...@@ -175,69 +181,17 @@
}); });
</script> </script>
<div class=" hidden lg:flex fixed bottom-0 right-0 px-2 py-2 z-10"> <Help />
<Tooltip content={$i18n.t('Help')} placement="left">
<button
id="show-shortcuts-button"
bind:this={showShortcutsButtonElement}
class="text-gray-600 dark:text-gray-300 bg-gray-300/20 size-5 flex items-center justify-center text-[0.7rem] rounded-full"
on:click={() => {
showShortcuts = !showShortcuts;
}}
>
?
</button>
</Tooltip>
</div>
<ShortcutsModal bind:show={showShortcuts} />
<SettingsModal bind:show={$showSettings} /> <SettingsModal bind:show={$showSettings} />
<ChangelogModal bind:show={$showChangelog} /> <ChangelogModal bind:show={$showChangelog} />
<div class="app relative"> <div class="app relative">
<div <div
class=" text-gray-700 dark:text-gray-100 bg-white dark:bg-gray-900 min-h-screen overflow-auto flex flex-row" class=" text-gray-700 dark:text-gray-100 bg-white dark:bg-gray-900 h-screen max-h-[100dvh] overflow-auto flex flex-row"
> >
{#if loaded} {#if loaded}
{#if !['user', 'admin'].includes($user.role)} {#if !['user', 'admin'].includes($user.role)}
<div class="fixed w-full h-full flex z-[999]"> <AccountPending />
<div
class="absolute w-full h-full backdrop-blur-lg bg-white/10 dark:bg-gray-900/50 flex justify-center"
>
<div class="m-auto pb-10 flex flex-col justify-center">
<div class="max-w-md">
<div class="text-center dark:text-white text-2xl font-medium z-50">
Account Activation Pending<br /> Contact Admin for WebUI Access
</div>
<div class=" mt-4 text-center text-sm dark:text-gray-200 w-full">
Your account status is currently pending activation. To access the WebUI, please
reach out to the administrator. Admins can manage user statuses from the Admin
Panel.
</div>
<div class=" mt-6 mx-auto relative group w-fit">
<button
class="relative z-20 flex px-5 py-2 rounded-full bg-white border border-gray-100 dark:border-none hover:bg-gray-100 text-gray-700 transition font-medium text-sm"
on:click={async () => {
location.href = '/';
}}
>
{$i18n.t('Check Again')}
</button>
<button
class="text-xs text-center w-full mt-2 text-gray-400 underline"
on:click={async () => {
localStorage.removeItem('token');
location.href = '/auth';
}}>{$i18n.t('Sign Out')}</button
>
</div>
</div>
</div>
</div>
</div>
{:else if localDBChats.length > 0} {:else if localDBChats.length > 0}
<div class="fixed w-full h-full flex z-50"> <div class="fixed w-full h-full flex z-50">
<div <div
......
...@@ -303,6 +303,31 @@ ...@@ -303,6 +303,31 @@
</svg> </svg>
</button> </button>
</Tooltip> </Tooltip>
{:else}
<Tooltip content={$i18n.t('Edit User')}>
<button
class="self-center w-fit text-sm px-2 py-2 hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
on:click={async () => {
showEditUserModal = !showEditUserModal;
selectedUser = user;
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-4 h-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125"
/>
</svg>
</button>
</Tooltip>
{/if} {/if}
</div> </div>
</td> </td>
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
import AdvancedParams from '$lib/components/chat/Settings/Advanced/AdvancedParams.svelte'; import AdvancedParams from '$lib/components/chat/Settings/Advanced/AdvancedParams.svelte';
import Checkbox from '$lib/components/common/Checkbox.svelte'; import Checkbox from '$lib/components/common/Checkbox.svelte';
import Tags from '$lib/components/common/Tags.svelte';
const i18n = getContext('i18n'); const i18n = getContext('i18n');
...@@ -56,6 +57,20 @@ ...@@ -56,6 +57,20 @@
id = name.replace(/\s+/g, '-').toLowerCase(); id = name.replace(/\s+/g, '-').toLowerCase();
} }
let baseModel = null;
$: {
baseModel = $models.find((m) => m.id === info.base_model_id);
console.log(baseModel);
if (baseModel) {
if (baseModel.owned_by === 'openai') {
capabilities.usage = baseModel.info?.meta?.capabilities?.usage ?? false;
} else {
delete capabilities.usage;
}
capabilities = capabilities;
}
}
const submitHandler = async () => { const submitHandler = async () => {
loading = true; loading = true;
...@@ -64,6 +79,12 @@ ...@@ -64,6 +79,12 @@
info.meta.capabilities = capabilities; info.meta.capabilities = capabilities;
info.params.stop = params.stop ? params.stop.split(',').filter((s) => s.trim()) : null; info.params.stop = params.stop ? params.stop.split(',').filter((s) => s.trim()) : null;
Object.keys(info.params).forEach((key) => {
if (info.params[key] === '' || info.params[key] === null) {
delete info.params[key];
}
});
if ($models.find((m) => m.id === info.id)) { if ($models.find((m) => m.id === info.id)) {
toast.error( toast.error(
`Error: A model with the ID '${info.id}' already exists. Please select a different ID to proceed.` `Error: A model with the ID '${info.id}' already exists. Please select a different ID to proceed.`
...@@ -87,9 +108,9 @@ ...@@ -87,9 +108,9 @@
}); });
if (res) { if (res) {
await models.set(await getModels(localStorage.token));
toast.success('Model created successfully!'); toast.success('Model created successfully!');
await goto('/workspace/models'); await goto('/workspace/models');
await models.set(await getModels(localStorage.token));
} }
} }
...@@ -117,13 +138,9 @@ ...@@ -117,13 +138,9 @@
onMount(async () => { onMount(async () => {
window.addEventListener('message', async (event) => { window.addEventListener('message', async (event) => {
if ( if (
![ !['https://openwebui.com', 'https://www.openwebui.com', 'http://localhost:5173'].includes(
'https://ollamahub.com', event.origin
'https://www.ollamahub.com', )
'https://openwebui.com',
'https://www.openwebui.com',
'http://localhost:5173'
].includes(event.origin)
) )
return; return;
...@@ -248,7 +265,7 @@ ...@@ -248,7 +265,7 @@
<button <button
class=" {info.meta.profile_image_url class=" {info.meta.profile_image_url
? '' ? ''
: 'p-6'} rounded-full dark:bg-gray-700 border border-dashed border-gray-200" : 'p-4'} rounded-full dark:bg-gray-700 border border-dashed border-gray-200 flex items-center"
type="button" type="button"
on:click={() => { on:click={() => {
filesInputElement.click(); filesInputElement.click();
...@@ -258,7 +275,7 @@ ...@@ -258,7 +275,7 @@
<img <img
src={info.meta.profile_image_url} src={info.meta.profile_image_url}
alt="modelfile profile" alt="modelfile profile"
class=" rounded-full w-20 h-20 object-cover" class=" rounded-full size-16 object-cover"
/> />
{:else} {:else}
<svg <svg
...@@ -324,18 +341,40 @@ ...@@ -324,18 +341,40 @@
</div> </div>
</div> </div>
<div class="my-2"> <div class="my-1">
<div class=" text-sm font-semibold mb-2">{$i18n.t('Description')}</div> <div class="flex w-full justify-between items-center mb-1">
<div class=" self-center text-sm font-semibold">{$i18n.t('Description')}</div>
<div> <button
class="p-1 text-xs flex rounded transition"
type="button"
on:click={() => {
if (info.meta.description === null) {
info.meta.description = '';
} else {
info.meta.description = null;
}
}}
>
{#if info.meta.description === null}
<span class="ml-2 self-center">{$i18n.t('Default')}</span>
{:else}
<span class="ml-2 self-center">{$i18n.t('Custom')}</span>
{/if}
</button>
</div>
{#if info.meta.description !== null}
<input <input
class="px-3 py-1.5 text-sm w-full bg-transparent border dark:border-gray-600 outline-none rounded-lg" class="px-3 py-1.5 text-sm w-full bg-transparent border dark:border-gray-600 outline-none rounded-lg"
placeholder={$i18n.t('Add a short description about what this model does')} placeholder={$i18n.t('Add a short description about what this model does')}
bind:value={info.meta.description} bind:value={info.meta.description}
/> />
</div> {/if}
</div> </div>
<hr class=" dark:border-gray-850 my-1" />
<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">{$i18n.t('Model Params')}</div> <div class=" self-center text-sm font-semibold">{$i18n.t('Model Params')}</div>
...@@ -387,7 +426,9 @@ ...@@ -387,7 +426,9 @@
</div> </div>
</div> </div>
<div class="my-2"> <hr class=" dark:border-gray-850 my-1" />
<div class="my-1">
<div class="flex w-full justify-between items-center"> <div class="flex w-full justify-between items-center">
<div class="flex w-full justify-between items-center"> <div class="flex w-full justify-between items-center">
<div class=" self-center text-sm font-semibold">{$i18n.t('Prompt suggestions')}</div> <div class=" self-center text-sm font-semibold">{$i18n.t('Prompt suggestions')}</div>
...@@ -477,8 +518,8 @@ ...@@ -477,8 +518,8 @@
{/if} {/if}
</div> </div>
<div class="my-2"> <div class="my-1">
<div class="flex w-full justify-between"> <div class="flex w-full justify-between mb-1">
<div class=" self-center text-sm font-semibold">{$i18n.t('Capabilities')}</div> <div class=" self-center text-sm font-semibold">{$i18n.t('Capabilities')}</div>
</div> </div>
<div class="flex flex-col"> <div class="flex flex-col">
...@@ -491,7 +532,7 @@ ...@@ -491,7 +532,7 @@
}} }}
/> />
<div class=" py-1.5 text-sm w-full capitalize"> <div class=" py-0.5 text-sm w-full capitalize">
{$i18n.t(capability)} {$i18n.t(capability)}
</div> </div>
</div> </div>
...@@ -499,7 +540,30 @@ ...@@ -499,7 +540,30 @@
</div> </div>
</div> </div>
<div class="my-2 text-gray-500"> <div class="my-1">
<div class="flex w-full justify-between items-center">
<div class=" self-center text-sm font-semibold">{$i18n.t('Tags')}</div>
</div>
<div class="mt-2">
<Tags
tags={info?.meta?.tags ?? []}
deleteTag={(tagName) => {
info.meta.tags = info.meta.tags.filter((tag) => tag.name !== tagName);
}}
addTag={(tagName) => {
console.log(tagName);
if (!(info?.meta?.tags ?? null)) {
info.meta.tags = [{ name: tagName }];
} else {
info.meta.tags = [...info.meta.tags, { name: tagName }];
}
}}
/>
</div>
</div>
<div class="my-2 text-gray-300 dark:text-gray-700">
<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">{$i18n.t('JSON Preview')}</div> <div class=" self-center text-sm font-semibold">{$i18n.t('JSON Preview')}</div>
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
import AdvancedParams from '$lib/components/chat/Settings/Advanced/AdvancedParams.svelte'; import AdvancedParams from '$lib/components/chat/Settings/Advanced/AdvancedParams.svelte';
import { getModels } from '$lib/apis'; import { getModels } from '$lib/apis';
import Checkbox from '$lib/components/common/Checkbox.svelte'; import Checkbox from '$lib/components/common/Checkbox.svelte';
import Tags from '$lib/components/common/Tags.svelte';
const i18n = getContext('i18n'); const i18n = getContext('i18n');
...@@ -44,7 +45,8 @@ ...@@ -44,7 +45,8 @@
meta: { meta: {
profile_image_url: '/favicon.png', profile_image_url: '/favicon.png',
description: '', description: '',
suggestion_prompts: null suggestion_prompts: null,
tags: []
}, },
params: { params: {
system: '' system: ''
...@@ -65,12 +67,18 @@ ...@@ -65,12 +67,18 @@
info.meta.capabilities = capabilities; info.meta.capabilities = capabilities;
info.params.stop = params.stop ? params.stop.split(',').filter((s) => s.trim()) : null; info.params.stop = params.stop ? params.stop.split(',').filter((s) => s.trim()) : null;
Object.keys(info.params).forEach((key) => {
if (info.params[key] === '' || info.params[key] === null) {
delete info.params[key];
}
});
const res = await updateModelById(localStorage.token, info.id, info); const res = await updateModelById(localStorage.token, info.id, info);
if (res) { if (res) {
await models.set(await getModels(localStorage.token));
toast.success('Model updated successfully'); toast.success('Model updated successfully');
await goto('/workspace/models'); await goto('/workspace/models');
await models.set(await getModels(localStorage.token));
} }
loading = false; loading = false;
...@@ -105,7 +113,15 @@ ...@@ -105,7 +113,15 @@
} }
params = { ...params, ...model?.info?.params }; params = { ...params, ...model?.info?.params };
params.stop = params?.stop ? (params?.stop ?? []).join(',') : null; params.stop = params?.stop
? (typeof params.stop === 'string' ? params.stop.split(',') : params?.stop ?? []).join(
','
)
: null;
if (model?.owned_by === 'openai') {
capabilities.usage = false;
}
if (model?.info?.meta?.capabilities) { if (model?.info?.meta?.capabilities) {
capabilities = { ...capabilities, ...model?.info?.meta?.capabilities }; capabilities = { ...capabilities, ...model?.info?.meta?.capabilities };
...@@ -219,26 +235,26 @@ ...@@ -219,26 +235,26 @@
<div class="flex justify-center my-4"> <div class="flex justify-center my-4">
<div class="self-center"> <div class="self-center">
<button <button
class=" {info?.meta?.profile_image_url class=" {info.meta.profile_image_url
? '' ? ''
: 'p-6'} rounded-full dark:bg-gray-700 border border-dashed border-gray-200" : 'p-4'} rounded-full dark:bg-gray-700 border border-dashed border-gray-200 flex items-center"
type="button" type="button"
on:click={() => { on:click={() => {
filesInputElement.click(); filesInputElement.click();
}} }}
> >
{#if info?.meta?.profile_image_url} {#if info.meta.profile_image_url}
<img <img
src={info?.meta?.profile_image_url} src={info.meta.profile_image_url}
alt="modelfile profile" alt="modelfile profile"
class=" rounded-full w-20 h-20 object-cover" class=" rounded-full size-16 object-cover"
/> />
{:else} {:else}
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24" viewBox="0 0 24 24"
fill="currentColor" fill="currentColor"
class="w-8" class="size-8"
> >
<path <path
fill-rule="evenodd" fill-rule="evenodd"
...@@ -251,9 +267,9 @@ ...@@ -251,9 +267,9 @@
</div> </div>
</div> </div>
<div class="my-2 flex space-x-2"> <div class="mt-2 my-1 flex space-x-2">
<div class="flex-1"> <div class="flex-1">
<div class=" text-sm font-semibold mb-2">{$i18n.t('Name')}*</div> <div class=" text-sm font-semibold mb-1">{$i18n.t('Name')}*</div>
<div> <div>
<input <input
...@@ -266,7 +282,7 @@ ...@@ -266,7 +282,7 @@
</div> </div>
<div class="flex-1"> <div class="flex-1">
<div class=" text-sm font-semibold mb-2">{$i18n.t('Model ID')}*</div> <div class=" text-sm font-semibold mb-1">{$i18n.t('Model ID')}*</div>
<div> <div>
<input <input
...@@ -281,8 +297,8 @@ ...@@ -281,8 +297,8 @@
</div> </div>
{#if model.preset} {#if model.preset}
<div class="my-2"> <div class="my-1">
<div class=" text-sm font-semibold mb-2">{$i18n.t('Base Model (From)')}</div> <div class=" text-sm font-semibold mb-1">{$i18n.t('Base Model (From)')}</div>
<div> <div>
<select <select
...@@ -300,18 +316,40 @@ ...@@ -300,18 +316,40 @@
</div> </div>
{/if} {/if}
<div class="my-2"> <div class="my-1">
<div class=" text-sm font-semibold mb-2">{$i18n.t('Description')}</div> <div class="flex w-full justify-between items-center">
<div class=" self-center text-sm font-semibold">{$i18n.t('Description')}</div>
<button
class="p-1 text-xs flex rounded transition"
type="button"
on:click={() => {
if (info.meta.description === null) {
info.meta.description = '';
} else {
info.meta.description = null;
}
}}
>
{#if info.meta.description === null}
<span class="ml-2 self-center">{$i18n.t('Default')}</span>
{:else}
<span class="ml-2 self-center">{$i18n.t('Custom')}</span>
{/if}
</button>
</div>
<div> {#if info.meta.description !== null}
<input <input
class="px-3 py-1.5 text-sm w-full bg-transparent border dark:border-gray-600 outline-none rounded-lg" class="mt-1 px-3 py-1.5 text-sm w-full bg-transparent border dark:border-gray-600 outline-none rounded-lg"
placeholder={$i18n.t('Add a short description about what this model does')} placeholder={$i18n.t('Add a short description about what this model does')}
bind:value={info.meta.description} bind:value={info.meta.description}
/> />
</div> {/if}
</div> </div>
<hr class=" dark:border-gray-850 my-1" />
<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">{$i18n.t('Model Params')}</div> <div class=" self-center text-sm font-semibold">{$i18n.t('Model Params')}</div>
...@@ -365,7 +403,9 @@ ...@@ -365,7 +403,9 @@
</div> </div>
</div> </div>
<div class="my-2"> <hr class=" dark:border-gray-850 my-1" />
<div class="my-1">
<div class="flex w-full justify-between items-center"> <div class="flex w-full justify-between items-center">
<div class="flex w-full justify-between items-center"> <div class="flex w-full justify-between items-center">
<div class=" self-center text-sm font-semibold">{$i18n.t('Prompt suggestions')}</div> <div class=" self-center text-sm font-semibold">{$i18n.t('Prompt suggestions')}</div>
...@@ -455,8 +495,8 @@ ...@@ -455,8 +495,8 @@
{/if} {/if}
</div> </div>
<div class="my-2"> <div class="my-1">
<div class="flex w-full justify-between"> <div class="flex w-full justify-between mb-1">
<div class=" self-center text-sm font-semibold">{$i18n.t('Capabilities')}</div> <div class=" self-center text-sm font-semibold">{$i18n.t('Capabilities')}</div>
</div> </div>
<div class="flex flex-col"> <div class="flex flex-col">
...@@ -469,7 +509,7 @@ ...@@ -469,7 +509,7 @@
}} }}
/> />
<div class=" py-1.5 text-sm w-full capitalize"> <div class=" py-0.5 text-sm w-full capitalize">
{$i18n.t(capability)} {$i18n.t(capability)}
</div> </div>
</div> </div>
...@@ -477,7 +517,30 @@ ...@@ -477,7 +517,30 @@
</div> </div>
</div> </div>
<div class="my-2 text-gray-500"> <div class="my-1">
<div class="flex w-full justify-between items-center">
<div class=" self-center text-sm font-semibold">{$i18n.t('Tags')}</div>
</div>
<div class="mt-2">
<Tags
tags={info?.meta?.tags ?? []}
deleteTag={(tagName) => {
info.meta.tags = info.meta.tags.filter((tag) => tag.name !== tagName);
}}
addTag={(tagName) => {
console.log(tagName);
if (!(info?.meta?.tags ?? null)) {
info.meta.tags = [{ name: tagName }];
} else {
info.meta.tags = [...info.meta.tags, { name: tagName }];
}
}}
/>
</div>
</div>
<div class="my-2 text-gray-300 dark:text-gray-700">
<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">{$i18n.t('JSON Preview')}</div> <div class=" self-center text-sm font-semibold">{$i18n.t('JSON Preview')}</div>
......
...@@ -57,13 +57,9 @@ ...@@ -57,13 +57,9 @@
onMount(async () => { onMount(async () => {
window.addEventListener('message', async (event) => { window.addEventListener('message', async (event) => {
if ( if (
![ !['https://openwebui.com', 'https://www.openwebui.com', 'http://localhost:5173'].includes(
'https://ollamahub.com', event.origin
'https://www.ollamahub.com', )
'https://openwebui.com',
'https://www.openwebui.com',
'http://localhost:5173'
].includes(event.origin)
) )
return; return;
const prompt = JSON.parse(event.data); const prompt = JSON.parse(event.data);
......
<script> <script>
import { io } from 'socket.io-client';
import { onMount, tick, setContext } from 'svelte'; import { onMount, tick, setContext } from 'svelte';
import { config, user, theme, WEBUI_NAME, mobile } from '$lib/stores'; import {
config,
user,
theme,
WEBUI_NAME,
mobile,
socket,
activeUserCount,
USAGE_POOL
} from '$lib/stores';
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import { page } from '$app/stores'; import { page } from '$app/stores';
import { Toaster, toast } from 'svelte-sonner'; import { Toaster, toast } from 'svelte-sonner';
...@@ -13,7 +24,7 @@ ...@@ -13,7 +24,7 @@
import 'tippy.js/dist/tippy.css'; import 'tippy.js/dist/tippy.css';
import { WEBUI_BASE_URL } from '$lib/constants'; import { WEBUI_BASE_URL, WEBUI_HOSTNAME } from '$lib/constants';
import i18n, { initI18n, getLanguages } from '$lib/i18n'; import i18n, { initI18n, getLanguages } from '$lib/i18n';
setContext('i18n', i18n); setContext('i18n', i18n);
...@@ -56,10 +67,30 @@ ...@@ -56,10 +67,30 @@
if (backendConfig) { if (backendConfig) {
// Save Backend Status to Store // Save Backend Status to Store
await config.set(backendConfig); await config.set(backendConfig);
await WEBUI_NAME.set(backendConfig.name); await WEBUI_NAME.set(backendConfig.name);
if ($config) { if ($config) {
const _socket = io(`${WEBUI_BASE_URL}`, {
path: '/ws/socket.io',
auth: { token: localStorage.token }
});
_socket.on('connect', () => {
console.log('connected');
});
await socket.set(_socket);
_socket.on('user-count', (data) => {
console.log('user-count', data);
activeUserCount.set(data.count);
});
_socket.on('usage', (data) => {
console.log('usage', data);
USAGE_POOL.set(data['models']);
});
if (localStorage.token) { if (localStorage.token) {
// Get Session User Info // Get Session User Info
const sessionUser = await getSessionUser(localStorage.token).catch((error) => { const sessionUser = await getSessionUser(localStorage.token).catch((error) => {
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
import { getSessionUser, userSignIn, userSignUp } from '$lib/apis/auths'; import { getSessionUser, userSignIn, userSignUp } from '$lib/apis/auths';
import Spinner from '$lib/components/common/Spinner.svelte'; import Spinner from '$lib/components/common/Spinner.svelte';
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, socket } from '$lib/stores';
import { onMount, getContext } from 'svelte'; import { onMount, getContext } from 'svelte';
import { toast } from 'svelte-sonner'; import { toast } from 'svelte-sonner';
import { generateInitialsImage, canvasPixelTest } from '$lib/utils'; import { generateInitialsImage, canvasPixelTest } from '$lib/utils';
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
if (sessionUser.token) { if (sessionUser.token) {
localStorage.token = sessionUser.token; localStorage.token = sessionUser.token;
} }
$socket.emit('user-join', { auth: { token: sessionUser.token } });
await user.set(sessionUser); await user.set(sessionUser);
goto('/'); goto('/');
} }
...@@ -246,7 +248,7 @@ ...@@ -246,7 +248,7 @@
</div> </div>
</form> </form>
{#if Object.keys($config?.oauth?.providers ?? {}).length > 0 } {#if Object.keys($config?.oauth?.providers ?? {}).length > 0}
<div class="inline-flex items-center justify-center w-full"> <div class="inline-flex items-center justify-center w-full">
<hr class="w-64 h-px my-8 bg-gray-200 border-0 dark:bg-gray-700" /> <hr class="w-64 h-px my-8 bg-gray-200 border-0 dark:bg-gray-700" />
<span <span
...@@ -255,7 +257,7 @@ ...@@ -255,7 +257,7 @@
> >
</div> </div>
<div class="flex flex-col space-y-2"> <div class="flex flex-col space-y-2">
{#if $config?.oauth?.providers?.google } {#if $config?.oauth?.providers?.google}
<button <button
class="flex items-center px-6 border-2 dark:border-gray-800 duration-300 dark:bg-gray-900 hover:bg-gray-100 dark:hover:bg-gray-800 w-full rounded-2xl dark:text-white text-sm py-3 transition" class="flex items-center px-6 border-2 dark:border-gray-800 duration-300 dark:bg-gray-900 hover:bg-gray-100 dark:hover:bg-gray-800 w-full rounded-2xl dark:text-white text-sm py-3 transition"
on:click={() => { on:click={() => {
...@@ -280,7 +282,7 @@ ...@@ -280,7 +282,7 @@
<span>{$i18n.t('Continue with {{provider}}', { provider: 'Google' })}</span> <span>{$i18n.t('Continue with {{provider}}', { provider: 'Google' })}</span>
</button> </button>
{/if} {/if}
{#if $config?.oauth?.providers?.microsoft } {#if $config?.oauth?.providers?.microsoft}
<button <button
class="flex items-center px-6 border-2 dark:border-gray-800 duration-300 dark:bg-gray-900 hover:bg-gray-100 dark:hover:bg-gray-800 w-full rounded-2xl dark:text-white text-sm py-3 transition" class="flex items-center px-6 border-2 dark:border-gray-800 duration-300 dark:bg-gray-900 hover:bg-gray-100 dark:hover:bg-gray-800 w-full rounded-2xl dark:text-white text-sm py-3 transition"
on:click={() => { on:click={() => {
...@@ -305,7 +307,7 @@ ...@@ -305,7 +307,7 @@
<span>{$i18n.t('Continue with {{provider}}', { provider: 'Microsoft' })}</span> <span>{$i18n.t('Continue with {{provider}}', { provider: 'Microsoft' })}</span>
</button> </button>
{/if} {/if}
{#if $config?.oauth?.providers?.oidc } {#if $config?.oauth?.providers?.oidc}
<button <button
class="flex items-center px-6 border-2 dark:border-gray-800 duration-300 dark:bg-gray-900 hover:bg-gray-100 dark:hover:bg-gray-800 w-full rounded-2xl dark:text-white text-sm py-3 transition" class="flex items-center px-6 border-2 dark:border-gray-800 duration-300 dark:bg-gray-900 hover:bg-gray-100 dark:hover:bg-gray-800 w-full rounded-2xl dark:text-white text-sm py-3 transition"
on:click={() => { on:click={() => {
......
<script lang="ts">
import { goto } from '$app/navigation';
import { onMount } from 'svelte';
onMount(async () => {
window.addEventListener('message', async (event) => {
if (
![
'https://ollamahub.com',
'https://www.ollamahub.com',
'https://openwebui.com',
'https://www.openwebui.com',
'http://localhost:5173'
].includes(event.origin)
)
return;
const prompts = JSON.parse(event.data);
sessionStorage.modelfile = JSON.stringify(prompts);
goto('/workspace/prompts/create');
});
if (window.opener ?? false) {
window.opener.postMessage('loaded', '*');
}
});
</script>
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment