|
@@ -21,77 +21,37 @@
|
|
|
import Sidebar from '$lib/components/layout/Sidebar.svelte';
|
|
|
import toast from 'svelte-french-toast';
|
|
|
import { OLLAMA_API_BASE_URL, WEBUI_API_BASE_URL } from '$lib/constants';
|
|
|
+ import { getOllamaModels, getOllamaVersion } from '$lib/apis/ollama';
|
|
|
+ import { getOpenAIModels } from '$lib/apis';
|
|
|
+ import {
|
|
|
+ createNewChat,
|
|
|
+ deleteChatById,
|
|
|
+ getChatById,
|
|
|
+ getChatlist,
|
|
|
+ updateChatById
|
|
|
+ } from '$lib/apis/chats';
|
|
|
|
|
|
let requiredOllamaVersion = '0.1.16';
|
|
|
let loaded = false;
|
|
|
|
|
|
const getModels = async () => {
|
|
|
let models = [];
|
|
|
- const res = await fetch(`${$settings?.API_BASE_URL ?? OLLAMA_API_BASE_URL}/tags`, {
|
|
|
- method: 'GET',
|
|
|
- headers: {
|
|
|
- Accept: 'application/json',
|
|
|
- 'Content-Type': 'application/json',
|
|
|
- ...($settings.authHeader && { Authorization: $settings.authHeader }),
|
|
|
- ...($user && { Authorization: `Bearer ${localStorage.token}` })
|
|
|
- }
|
|
|
- })
|
|
|
- .then(async (res) => {
|
|
|
- if (!res.ok) throw await res.json();
|
|
|
- return res.json();
|
|
|
- })
|
|
|
- .catch((error) => {
|
|
|
+ models.push(
|
|
|
+ ...(await getOllamaModels($settings?.API_BASE_URL ?? OLLAMA_API_BASE_URL, localStorage.token))
|
|
|
+ );
|
|
|
+ // If OpenAI API Key exists
|
|
|
+ if ($settings.OPENAI_API_KEY) {
|
|
|
+ const openAIModels = await getOpenAIModels(
|
|
|
+ $settings.OPENAI_API_BASE_URL ?? 'https://api.openai.com/v1',
|
|
|
+ $settings.OPENAI_API_KEY
|
|
|
+ ).catch((error) => {
|
|
|
console.log(error);
|
|
|
- if ('detail' in error) {
|
|
|
- toast.error(error.detail);
|
|
|
- } else {
|
|
|
- toast.error('Server connection failed');
|
|
|
- }
|
|
|
+ toast.error(error);
|
|
|
return null;
|
|
|
});
|
|
|
- console.log(res);
|
|
|
- models.push(...(res?.models ?? []));
|
|
|
-
|
|
|
- // If OpenAI API Key exists
|
|
|
- if ($settings.OPENAI_API_KEY) {
|
|
|
- // Validate OPENAI_API_KEY
|
|
|
-
|
|
|
- const API_BASE_URL = $settings.OPENAI_API_BASE_URL ?? 'https://api.openai.com/v1';
|
|
|
- const openaiModelRes = await fetch(`${API_BASE_URL}/models`, {
|
|
|
- method: 'GET',
|
|
|
- headers: {
|
|
|
- 'Content-Type': 'application/json',
|
|
|
- Authorization: `Bearer ${$settings.OPENAI_API_KEY}`
|
|
|
- }
|
|
|
- })
|
|
|
- .then(async (res) => {
|
|
|
- if (!res.ok) throw await res.json();
|
|
|
- return res.json();
|
|
|
- })
|
|
|
- .catch((error) => {
|
|
|
- console.log(error);
|
|
|
- toast.error(`OpenAI: ${error?.error?.message ?? 'Network Problem'}`);
|
|
|
- return null;
|
|
|
- });
|
|
|
|
|
|
- const openAIModels = Array.isArray(openaiModelRes)
|
|
|
- ? openaiModelRes
|
|
|
- : openaiModelRes?.data ?? null;
|
|
|
-
|
|
|
- models.push(
|
|
|
- ...(openAIModels
|
|
|
- ? [
|
|
|
- { name: 'hr' },
|
|
|
- ...openAIModels
|
|
|
- .map((model) => ({ name: model.id, external: true }))
|
|
|
- .filter((model) =>
|
|
|
- API_BASE_URL.includes('openai') ? model.name.includes('gpt') : true
|
|
|
- )
|
|
|
- ]
|
|
|
- : [])
|
|
|
- );
|
|
|
+ models.push(...(openAIModels ? [{ name: 'hr' }, ...openAIModels] : []));
|
|
|
}
|
|
|
-
|
|
|
return models;
|
|
|
};
|
|
|
|
|
@@ -109,135 +69,152 @@
|
|
|
return {
|
|
|
db: DB,
|
|
|
getChatById: async function (id) {
|
|
|
- return await this.db.get('chats', id);
|
|
|
+ const chat = await getChatById(localStorage.token, id);
|
|
|
+ return chat;
|
|
|
},
|
|
|
getChats: async function () {
|
|
|
- let chats = await this.db.getAllFromIndex('chats', 'timestamp');
|
|
|
- chats = chats.map((item, idx) => ({
|
|
|
- title: chats[chats.length - 1 - idx].title,
|
|
|
- id: chats[chats.length - 1 - idx].id
|
|
|
- }));
|
|
|
+ const chats = await getChatlist(localStorage.token);
|
|
|
return chats;
|
|
|
},
|
|
|
- exportChats: async function () {
|
|
|
- let chats = await this.db.getAllFromIndex('chats', 'timestamp');
|
|
|
- chats = chats.map((item, idx) => chats[chats.length - 1 - idx]);
|
|
|
- return chats;
|
|
|
- },
|
|
|
- addChats: async function (_chats) {
|
|
|
- for (const chat of _chats) {
|
|
|
- console.log(chat);
|
|
|
- await this.addChat(chat);
|
|
|
- }
|
|
|
+ createNewChat: async function (_chat) {
|
|
|
+ const chat = await createNewChat(localStorage.token, { ..._chat, timestamp: Date.now() });
|
|
|
+ console.log(chat);
|
|
|
await chats.set(await this.getChats());
|
|
|
+
|
|
|
+ return chat;
|
|
|
},
|
|
|
+
|
|
|
addChat: async function (chat) {
|
|
|
await this.db.put('chats', {
|
|
|
...chat
|
|
|
});
|
|
|
},
|
|
|
- createNewChat: async function (chat) {
|
|
|
- await this.addChat({ ...chat, timestamp: Date.now() });
|
|
|
- await chats.set(await this.getChats());
|
|
|
- },
|
|
|
- updateChatById: async function (id, updated) {
|
|
|
- const chat = await this.getChatById(id);
|
|
|
|
|
|
- await this.db.put('chats', {
|
|
|
- ...chat,
|
|
|
+ updateChatById: async function (id, updated) {
|
|
|
+ const chat = await updateChatById(localStorage.token, id, {
|
|
|
...updated,
|
|
|
timestamp: Date.now()
|
|
|
});
|
|
|
-
|
|
|
await chats.set(await this.getChats());
|
|
|
+ return chat;
|
|
|
},
|
|
|
deleteChatById: async function (id) {
|
|
|
if ($chatId === id) {
|
|
|
goto('/');
|
|
|
await chatId.set(uuidv4());
|
|
|
}
|
|
|
- await this.db.delete('chats', id);
|
|
|
+
|
|
|
+ await deleteChatById(localStorage.token, id);
|
|
|
await chats.set(await this.getChats());
|
|
|
},
|
|
|
+
|
|
|
deleteAllChat: async function () {
|
|
|
const tx = this.db.transaction('chats', 'readwrite');
|
|
|
await Promise.all([tx.store.clear(), tx.done]);
|
|
|
-
|
|
|
+ await chats.set(await this.getChats());
|
|
|
+ },
|
|
|
+ exportChats: async function () {
|
|
|
+ let chats = await this.db.getAllFromIndex('chats', 'timestamp');
|
|
|
+ chats = chats.map((item, idx) => chats[chats.length - 1 - idx]);
|
|
|
+ return chats;
|
|
|
+ },
|
|
|
+ importChats: async function (_chats) {
|
|
|
+ for (const chat of _chats) {
|
|
|
+ console.log(chat);
|
|
|
+ await this.addChat(chat);
|
|
|
+ }
|
|
|
await chats.set(await this.getChats());
|
|
|
}
|
|
|
};
|
|
|
};
|
|
|
|
|
|
- const getOllamaVersion = async () => {
|
|
|
- const res = await fetch(`${$settings?.API_BASE_URL ?? OLLAMA_API_BASE_URL}/version`, {
|
|
|
- method: 'GET',
|
|
|
- headers: {
|
|
|
- Accept: 'application/json',
|
|
|
- 'Content-Type': 'application/json',
|
|
|
- ...($settings.authHeader && { Authorization: $settings.authHeader }),
|
|
|
- ...($user && { Authorization: `Bearer ${localStorage.token}` })
|
|
|
- }
|
|
|
- })
|
|
|
- .then(async (res) => {
|
|
|
- if (!res.ok) throw await res.json();
|
|
|
- return res.json();
|
|
|
- })
|
|
|
- .catch((error) => {
|
|
|
- console.log(error);
|
|
|
- if ('detail' in error) {
|
|
|
- toast.error(error.detail);
|
|
|
- } else {
|
|
|
- toast.error('Server connection failed');
|
|
|
- }
|
|
|
- return null;
|
|
|
- });
|
|
|
-
|
|
|
- console.log(res);
|
|
|
-
|
|
|
- return res?.version ?? '0';
|
|
|
- };
|
|
|
+ const setOllamaVersion = async () => {
|
|
|
+ const version = await getOllamaVersion(
|
|
|
+ $settings?.API_BASE_URL ?? OLLAMA_API_BASE_URL,
|
|
|
+ localStorage.token
|
|
|
+ ).catch((error) => {
|
|
|
+ toast.error(error);
|
|
|
+ return '0';
|
|
|
+ });
|
|
|
|
|
|
- const setOllamaVersion = async (ollamaVersion) => {
|
|
|
- await info.set({ ...$info, ollama: { version: ollamaVersion } });
|
|
|
+ await info.set({ ...$info, ollama: { version: version } });
|
|
|
|
|
|
if (
|
|
|
- ollamaVersion.localeCompare(requiredOllamaVersion, undefined, {
|
|
|
+ version.localeCompare(requiredOllamaVersion, undefined, {
|
|
|
numeric: true,
|
|
|
sensitivity: 'case',
|
|
|
caseFirst: 'upper'
|
|
|
}) < 0
|
|
|
) {
|
|
|
- toast.error(`Ollama Version: ${ollamaVersion}`);
|
|
|
+ toast.error(`Ollama Version: ${version}`);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
onMount(async () => {
|
|
|
- if ($config && $config.auth && $user === undefined) {
|
|
|
+ if ($config && $user === undefined) {
|
|
|
await goto('/auth');
|
|
|
}
|
|
|
|
|
|
await settings.set(JSON.parse(localStorage.getItem('settings') ?? '{}'));
|
|
|
-
|
|
|
await models.set(await getModels());
|
|
|
+
|
|
|
await modelfiles.set(JSON.parse(localStorage.getItem('modelfiles') ?? '[]'));
|
|
|
|
|
|
- modelfiles.subscribe(async () => {
|
|
|
- await models.set(await getModels());
|
|
|
- });
|
|
|
+ modelfiles.subscribe(async () => {});
|
|
|
|
|
|
let _db = await getDB();
|
|
|
await db.set(_db);
|
|
|
-
|
|
|
- await setOllamaVersion(await getOllamaVersion());
|
|
|
+ await setOllamaVersion();
|
|
|
|
|
|
await tick();
|
|
|
loaded = true;
|
|
|
});
|
|
|
+
|
|
|
+ let child;
|
|
|
</script>
|
|
|
|
|
|
{#if loaded}
|
|
|
<div class="app relative">
|
|
|
- {#if ($info?.ollama?.version ?? '0').localeCompare( requiredOllamaVersion, undefined, { numeric: true, sensitivity: 'case', caseFirst: 'upper' } ) < 0}
|
|
|
+ {#if !['user', 'admin'].includes($user.role)}
|
|
|
+ <div class="absolute w-full h-full flex z-50">
|
|
|
+ <div
|
|
|
+ class="absolute rounded-xl w-full h-full backdrop-blur bg-gray-900/60 flex justify-center"
|
|
|
+ >
|
|
|
+ <div class="m-auto pb-44 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-gray-100 hover:bg-gray-200 transition font-medium text-sm"
|
|
|
+ on:click={async () => {
|
|
|
+ location.href = '/';
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ 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';
|
|
|
+ }}>Sign Out</button
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ {:else if ($info?.ollama?.version ?? '0').localeCompare( requiredOllamaVersion, undefined, { numeric: true, sensitivity: 'case', caseFirst: 'upper' } ) < 0}
|
|
|
<div class="absolute w-full h-full flex z-50">
|
|
|
<div
|
|
|
class="absolute rounded-xl w-full h-full backdrop-blur bg-gray-900/60 flex justify-center"
|
|
@@ -285,9 +262,7 @@
|
|
|
class=" text-gray-700 dark:text-gray-100 bg-white dark:bg-gray-800 min-h-screen overflow-auto flex flex-row"
|
|
|
>
|
|
|
<Sidebar />
|
|
|
-
|
|
|
<SettingsModal bind:show={$showSettings} />
|
|
|
-
|
|
|
<slot />
|
|
|
</div>
|
|
|
</div>
|