Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
chenpangpang
open-webui
Commits
ee22e641
Unverified
Commit
ee22e641
authored
Feb 24, 2024
by
Timothy Jaeryang Baek
Committed by
GitHub
Feb 24, 2024
Browse files
Merge branch 'main' into litellm
parents
9b6dca3d
f69c0d2e
Changes
39
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
265 additions
and
64 deletions
+265
-64
src/lib/components/chat/Messages/Placeholder.svelte
src/lib/components/chat/Messages/Placeholder.svelte
+5
-2
src/lib/components/chat/Messages/ResponseMessage.svelte
src/lib/components/chat/Messages/ResponseMessage.svelte
+6
-3
src/lib/components/chat/Messages/UserMessage.svelte
src/lib/components/chat/Messages/UserMessage.svelte
+38
-7
src/lib/components/chat/Settings/About.svelte
src/lib/components/chat/Settings/About.svelte
+20
-5
src/lib/components/chat/Settings/Images.svelte
src/lib/components/chat/Settings/Images.svelte
+26
-5
src/lib/components/chat/Settings/Models.svelte
src/lib/components/chat/Settings/Models.svelte
+4
-4
src/lib/components/common/Image.svelte
src/lib/components/common/Image.svelte
+18
-0
src/lib/components/common/ImagePreview.svelte
src/lib/components/common/ImagePreview.svelte
+62
-0
src/lib/components/common/Modal.svelte
src/lib/components/common/Modal.svelte
+22
-4
src/lib/components/layout/Navbar.svelte
src/lib/components/layout/Navbar.svelte
+3
-4
src/lib/components/layout/Sidebar.svelte
src/lib/components/layout/Sidebar.svelte
+8
-1
src/lib/constants.ts
src/lib/constants.ts
+2
-3
src/lib/stores/index.ts
src/lib/stores/index.ts
+3
-0
src/routes/(app)/+layout.svelte
src/routes/(app)/+layout.svelte
+15
-8
src/routes/(app)/+page.svelte
src/routes/(app)/+page.svelte
+15
-3
src/routes/(app)/c/[id]/+page.svelte
src/routes/(app)/c/[id]/+page.svelte
+5
-4
src/routes/+layout.svelte
src/routes/+layout.svelte
+6
-3
src/routes/auth/+page.svelte
src/routes/auth/+page.svelte
+5
-5
src/routes/error/+page.svelte
src/routes/error/+page.svelte
+2
-3
No files found.
src/lib/components/chat/Messages/Placeholder.svelte
View file @
ee22e641
<script lang="ts">
<script lang="ts">
import { WEBUI_BASE_URL } from '$lib/constants';
import { onMount } from 'svelte';
import { onMount } from 'svelte';
export let models = [];
export let models = [];
...
@@ -27,14 +28,16 @@
...
@@ -27,14 +28,16 @@
>
>
{#if model in modelfiles}
{#if model in modelfiles}
<img
<img
src={modelfiles[model]?.imageUrl ??
'.
/favicon.png
'
}
src={modelfiles[model]?.imageUrl ??
`${WEBUI_BASE_URL}/static
/favicon.png
`
}
alt="modelfile"
alt="modelfile"
class=" w-14 rounded-full border-[1px] border-gray-200 dark:border-none"
class=" w-14 rounded-full border-[1px] border-gray-200 dark:border-none"
draggable="false"
draggable="false"
/>
/>
{:else}
{:else}
<img
<img
src={models.length === 1 ? '/favicon.png' : '/favicon.png'}
src={models.length === 1
? `${WEBUI_BASE_URL}/static/favicon.png`
: `${WEBUI_BASE_URL}/static/favicon.png`}
class=" w-14 rounded-full border-[1px] border-gray-200 dark:border-none"
class=" w-14 rounded-full border-[1px] border-gray-200 dark:border-none"
alt="logo"
alt="logo"
draggable="false"
draggable="false"
...
...
src/lib/components/chat/Messages/ResponseMessage.svelte
View file @
ee22e641
...
@@ -20,6 +20,8 @@
...
@@ -20,6 +20,8 @@
import ProfileImage from './ProfileImage.svelte';
import ProfileImage from './ProfileImage.svelte';
import Skeleton from './Skeleton.svelte';
import Skeleton from './Skeleton.svelte';
import CodeBlock from './CodeBlock.svelte';
import CodeBlock from './CodeBlock.svelte';
import Image from '$lib/components/common/Image.svelte';
import { WEBUI_BASE_URL } from '$lib/constants';
export let modelfiles = [];
export let modelfiles = [];
export let message;
export let message;
...
@@ -46,7 +48,6 @@
...
@@ -46,7 +48,6 @@
let speakingIdx = null;
let speakingIdx = null;
let loadingSpeech = false;
let loadingSpeech = false;
let generatingImage = false;
let generatingImage = false;
$: tokens = marked.lexer(message.content);
$: tokens = marked.lexer(message.content);
...
@@ -298,7 +299,9 @@
...
@@ -298,7 +299,9 @@
{#key message.id}
{#key message.id}
<div class=" flex w-full message-{message.id}">
<div class=" flex w-full message-{message.id}">
<ProfileImage src={modelfiles[message.model]?.imageUrl ?? '/favicon.png'} />
<ProfileImage
src={modelfiles[message.model]?.imageUrl ?? `${WEBUI_BASE_URL}/static/favicon.png`}
/>
<div class="w-full overflow-hidden">
<div class="w-full overflow-hidden">
<Name>
<Name>
...
@@ -323,7 +326,7 @@
...
@@ -323,7 +326,7 @@
{#each message.files as file}
{#each message.files as file}
<div>
<div>
{#if file.type === 'image'}
{#if file.type === 'image'}
<
img
src={file.url}
alt="input" class=" max-h-96 rounded-lg" draggable="false"
/>
<
Image
src={file.url} />
{/if}
{/if}
</div>
</div>
{/each}
{/each}
...
...
src/lib/components/chat/Messages/UserMessage.svelte
View file @
ee22e641
<script lang="ts">
<script lang="ts">
import dayjs from 'dayjs';
import dayjs from 'dayjs';
import { tick } from 'svelte';
import { tick
, createEventDispatcher
} 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 dispatch = createEventDispatcher();
export let user;
export let user;
export let message;
export let message;
export let siblings;
export let siblings;
export let isFirstMessage: boolean;
export let confirmEditMessage: Function;
export let confirmEditMessage: Function;
export let showPreviousMessage: Function;
export let showPreviousMessage: Function;
...
@@ -42,6 +45,10 @@
...
@@ -42,6 +45,10 @@
edit = false;
edit = false;
editedContent = '';
editedContent = '';
};
};
const deleteMessageHandler = async () => {
dispatch('delete', message.id);
};
</script>
</script>
<div class=" flex w-full">
<div class=" flex w-full">
...
@@ -189,11 +196,11 @@
...
@@ -189,11 +196,11 @@
<div class="w-full">
<div class="w-full">
<pre id="user-message">{message.content}</pre>
<pre id="user-message">{message.content}</pre>
<div class=" flex justify-start space-x-1">
<div class=" flex justify-start space-x-1
text-gray-700 dark:text-gray-500
">
{#if siblings.length > 1}
{#if siblings.length > 1}
<div class="flex self-center">
<div class="flex self-center">
<button
<button
class="self-center"
class="self-center
dark:hover:text-white hover:text-black transition
"
on:click={() => {
on:click={() => {
showPreviousMessage(message);
showPreviousMessage(message);
}}
}}
...
@@ -212,12 +219,12 @@
...
@@ -212,12 +219,12 @@
</svg>
</svg>
</button>
</button>
<div class="text-xs font-bold self-center">
<div class="text-xs font-bold self-center
dark:text-gray-100
">
{siblings.indexOf(message.id) + 1} / {siblings.length}
{siblings.indexOf(message.id) + 1} / {siblings.length}
</div>
</div>
<button
<button
class="self-center"
class="self-center
dark:hover:text-white hover:text-black transition
"
on:click={() => {
on:click={() => {
showNextMessage(message);
showNextMessage(message);
}}
}}
...
@@ -239,7 +246,7 @@
...
@@ -239,7 +246,7 @@
{/if}
{/if}
<button
<button
class="invisible group-hover:visible p-1 rounded dark:hover:text-white transition edit-user-message-button"
class="invisible group-hover:visible p-1 rounded dark:hover:text-white
hover:text-black
transition edit-user-message-button"
on:click={() => {
on:click={() => {
editMessageHandler();
editMessageHandler();
}}
}}
...
@@ -261,7 +268,7 @@
...
@@ -261,7 +268,7 @@
</button>
</button>
<button
<button
class="invisible group-hover:visible p-1 rounded dark:hover:text-white transition"
class="invisible group-hover:visible p-1 rounded dark:hover:text-white
hover:text-black
transition"
on:click={() => {
on:click={() => {
copyToClipboard(message.content);
copyToClipboard(message.content);
}}
}}
...
@@ -281,6 +288,30 @@
...
@@ -281,6 +288,30 @@
/>
/>
</svg>
</svg>
</button>
</button>
{#if !isFirstMessage}
<button
class="invisible group-hover:visible p-1 rounded dark:hover:text-white hover:text-black transition"
on:click={() => {
deleteMessageHandler();
}}
>
<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="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0"
/>
</svg>
</button>
{/if}
</div>
</div>
</div>
</div>
{/if}
{/if}
...
...
src/lib/components/chat/Settings/About.svelte
View file @
ee22e641
<script lang="ts">
<script lang="ts">
import { getOllamaVersion } from '$lib/apis/ollama';
import { getOllamaVersion } from '$lib/apis/ollama';
import { WEBUI_
NAME, WEB_UI_
VERSION } from '$lib/constants';
import { WEBUI_VERSION } from '$lib/constants';
import {
confi
g } from '$lib/stores';
import {
WEBUI_NAME, config, showChangelo
g } from '$lib/stores';
import { onMount } from 'svelte';
import { onMount } from 'svelte';
let ollamaVersion = '';
let ollamaVersion = '';
...
@@ -15,10 +15,25 @@
...
@@ -15,10 +15,25 @@
<div class="flex flex-col h-full justify-between space-y-3 text-sm mb-6">
<div class="flex flex-col h-full justify-between space-y-3 text-sm mb-6">
<div class=" space-y-3">
<div class=" space-y-3">
<div>
<div>
<div class=" mb-2.5 text-sm font-medium">{WEBUI_NAME} Version</div>
<div class=" mb-2.5 text-sm font-medium flex space-x-2 items-center">
<div>
{$WEBUI_NAME} Version
</div>
</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 flex space-x-1.5 items-center">
{WEB_UI_VERSION}
<div>
v{WEBUI_VERSION}
</div>
<button
class=" underline flex items-center space-x-1 text-xs text-gray-500 dark:text-gray-500"
on:click={() => {
showChangelog.set(true);
}}
>
<div>See what's new</div>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
...
...
src/lib/components/chat/Settings/Images.svelte
View file @
ee22e641
...
@@ -8,9 +8,11 @@
...
@@ -8,9 +8,11 @@
getDefaultDiffusionModel,
getDefaultDiffusionModel,
getDiffusionModels,
getDiffusionModels,
getImageGenerationEnabledStatus,
getImageGenerationEnabledStatus,
getImageSize,
toggleImageGenerationEnabledStatus,
toggleImageGenerationEnabledStatus,
updateAUTOMATIC1111Url,
updateAUTOMATIC1111Url,
updateDefaultDiffusionModel
updateDefaultDiffusionModel,
updateImageSize
} from '$lib/apis/images';
} from '$lib/apis/images';
import { getBackendConfig } from '$lib/apis';
import { getBackendConfig } from '$lib/apis';
const dispatch = createEventDispatcher();
const dispatch = createEventDispatcher();
...
@@ -25,6 +27,8 @@
...
@@ -25,6 +27,8 @@
let selectedModel = '';
let selectedModel = '';
let models = [];
let models = [];
let imageSize = '';
const getModels = async () => {
const getModels = async () => {
models = await getDiffusionModels(localStorage.token).catch((error) => {
models = await getDiffusionModels(localStorage.token).catch((error) => {
toast.error(error);
toast.error(error);
...
@@ -53,7 +57,6 @@
...
@@ -53,7 +57,6 @@
AUTOMATIC1111_BASE_URL = await getAUTOMATIC1111Url(localStorage.token);
AUTOMATIC1111_BASE_URL = await getAUTOMATIC1111Url(localStorage.token);
}
}
};
};
const toggleImageGeneration = async () => {
const toggleImageGeneration = async () => {
if (AUTOMATIC1111_BASE_URL) {
if (AUTOMATIC1111_BASE_URL) {
enableImageGeneration = await toggleImageGenerationEnabledStatus(localStorage.token).catch(
enableImageGeneration = await toggleImageGenerationEnabledStatus(localStorage.token).catch(
...
@@ -79,6 +82,7 @@
...
@@ -79,6 +82,7 @@
AUTOMATIC1111_BASE_URL = await getAUTOMATIC1111Url(localStorage.token);
AUTOMATIC1111_BASE_URL = await getAUTOMATIC1111Url(localStorage.token);
if (enableImageGeneration && AUTOMATIC1111_BASE_URL) {
if (enableImageGeneration && AUTOMATIC1111_BASE_URL) {
imageSize = await getImageSize(localStorage.token);
getModels();
getModels();
}
}
}
}
...
@@ -89,13 +93,17 @@
...
@@ -89,13 +93,17 @@
class="flex flex-col h-full justify-between space-y-3 text-sm"
class="flex flex-col h-full justify-between space-y-3 text-sm"
on:submit|preventDefault={async () => {
on:submit|preventDefault={async () => {
loading = true;
loading = true;
const res = await updateDefaultDiffusionModel(localStorage.token, selectedModel);
await updateDefaultDiffusionModel(localStorage.token, selectedModel);
await updateImageSize(localStorage.token, imageSize).catch((error) => {
toast.error(error);
return null;
});
dispatch('save');
dispatch('save');
loading = false;
loading = false;
}}
}}
>
>
<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-
[21rem]
">
<div>
<div>
<div class=" mb-1 text-sm font-medium">Image Settings</div>
<div class=" mb-1 text-sm font-medium">Image Settings</div>
...
@@ -169,7 +177,7 @@
...
@@ -169,7 +177,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
d
efault
m
odel</div>
<div class=" mb-2.5 text-sm font-medium">Set
D
efault
M
odel</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
...
@@ -189,6 +197,19 @@
...
@@ -189,6 +197,19 @@
</div>
</div>
</div>
</div>
</div>
</div>
<div>
<div class=" mb-2.5 text-sm font-medium">Set Image Size</div>
<div class="flex w-full">
<div class="flex-1 mr-2">
<input
class="w-full rounded py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-800 outline-none"
placeholder="Enter Image Size (e.g. 512x512)"
bind:value={imageSize}
/>
</div>
</div>
</div>
{/if}
{/if}
</div>
</div>
...
...
src/lib/components/chat/Settings/Models.svelte
View file @
ee22e641
...
@@ -3,8 +3,8 @@
...
@@ -3,8 +3,8 @@
import toast from 'svelte-french-toast';
import toast from 'svelte-french-toast';
import { createModel, deleteModel, pullModel } from '$lib/apis/ollama';
import { createModel, deleteModel, pullModel } from '$lib/apis/ollama';
import { WEBUI_API_BASE_URL, WEBUI_
NAME
} from '$lib/constants';
import { WEBUI_API_BASE_URL, WEBUI_
BASE_URL
} from '$lib/constants';
import { models, user } from '$lib/stores';
import {
WEBUI_NAME,
models, user } from '$lib/stores';
import { splitStream } from '$lib/utils';
import { splitStream } from '$lib/utils';
export let getModels: Function;
export let getModels: Function;
...
@@ -59,9 +59,9 @@
...
@@ -59,9 +59,9 @@
} else {
} else {
toast.success(`Model '${modelName}' has been successfully downloaded.`);
toast.success(`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.`,
icon:
'
/favicon.png
'
icon:
`${WEBUI_BASE_URL}/static
/favicon.png
`
});
});
models.set(await getModels());
models.set(await getModels());
...
...
src/lib/components/common/Image.svelte
0 → 100644
View file @
ee22e641
<script lang="ts">
import ImagePreview from './ImagePreview.svelte';
export let src = '';
export let alt = '';
let showImagePreview = false;
</script>
<ImagePreview bind:show={showImagePreview} {src} {alt} />
<button
on:click={() => {
console.log('image preview');
showImagePreview = true;
}}
>
<img {src} {alt} class=" max-h-96 rounded-lg" draggable="false" />
</button>
src/lib/components/common/ImagePreview.svelte
0 → 100644
View file @
ee22e641
<script lang="ts">
export let show = false;
export let src = '';
export let alt = '';
</script>
{#if show}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div
class="fixed top-0 right-0 left-0 bottom-0 bg-black text-white w-full min-h-screen h-screen flex justify-center z-50 overflow-hidden overscroll-contain"
>
<div class=" absolute left-0 w-full flex justify-between">
<div>
<button
class=" p-5"
on:click={() => {
show = false;
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="2"
stroke="currentColor"
class="w-6 h-6"
>
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12" />
</svg>
</button>
</div>
<div>
<button
class=" p-5"
on:click={() => {
const a = document.createElement('a');
a.href = src;
a.download = 'Image.png';
a.click();
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
class="w-6 h-6"
>
<path
d="M10.75 2.75a.75.75 0 0 0-1.5 0v8.614L6.295 8.235a.75.75 0 1 0-1.09 1.03l4.25 4.5a.75.75 0 0 0 1.09 0l4.25-4.5a.75.75 0 0 0-1.09-1.03l-2.955 3.129V2.75Z"
/>
<path
d="M3.5 12.75a.75.75 0 0 0-1.5 0v2.5A2.75 2.75 0 0 0 4.75 18h10.5A2.75 2.75 0 0 0 18 15.25v-2.5a.75.75 0 0 0-1.5 0v2.5c0 .69-.56 1.25-1.25 1.25H4.75c-.69 0-1.25-.56-1.25-1.25v-2.5Z"
/>
</svg>
</button>
</div>
</div>
<img {src} {alt} class=" mx-auto h-full object-scale-down" />
</div>
{/if}
src/lib/components/common/Modal.svelte
View file @
ee22e641
<script lang="ts">
<script lang="ts">
import { onMount } from 'svelte';
import { onMount } from 'svelte';
import { fade
, blur
} from 'svelte/transition';
import { fade } from 'svelte/transition';
export let show = true;
export let show = true;
export let size = 'md';
export let size = 'md';
...
@@ -34,16 +34,17 @@
...
@@ -34,16 +34,17 @@
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div
<div
class="fixed top-0 right-0 left-0 bottom-0 bg-black/60 w-full min-h-screen h-screen flex justify-center z-50 overflow-hidden overscroll-contain"
class=" fixed top-0 right-0 left-0 bottom-0 bg-black/60 w-full min-h-screen h-screen flex justify-center z-50 overflow-hidden overscroll-contain"
in:fade={{ duration: 10 }}
on:click={() => {
on:click={() => {
show = false;
show = false;
}}
}}
>
>
<div
<div
class="m-auto rounded-xl max-w-full {sizeToWidth(
class="
modal-content
m-auto rounded-xl max-w-full {sizeToWidth(
size
size
)} mx-2 bg-gray-50 dark:bg-gray-900 shadow-3xl"
)} mx-2 bg-gray-50 dark:bg-gray-900 shadow-3xl"
transitio
n:fade={{
delay: 100,
duration:
20
0 }}
i
n:fade={{ duration:
1
0 }}
on:click={(e) => {
on:click={(e) => {
e.stopPropagation();
e.stopPropagation();
}}
}}
...
@@ -52,3 +53,20 @@
...
@@ -52,3 +53,20 @@
</div>
</div>
</div>
</div>
{/if}
{/if}
<style>
.modal-content {
animation: scaleUp 0.1s ease-out forwards;
}
@keyframes scaleUp {
from {
transform: scale(0.985);
opacity: 0;
}
to {
transform: scale(1);
opacity: 1;
}
}
</style>
src/lib/components/layout/Navbar.svelte
View file @
ee22e641
...
@@ -4,14 +4,13 @@
...
@@ -4,14 +4,13 @@
const { saveAs } = fileSaver;
const { saveAs } = fileSaver;
import { getChatById } from '$lib/apis/chats';
import { getChatById } from '$lib/apis/chats';
import { chatId, modelfiles, settings } from '$lib/stores';
import {
WEBUI_NAME,
chatId, modelfiles, settings } from '$lib/stores';
import ShareChatModal from '../chat/ShareChatModal.svelte';
import ShareChatModal from '../chat/ShareChatModal.svelte';
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';
import { WEBUI_NAME } from '$lib/constants';
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;
export let tags = [];
export let tags = [];
...
@@ -102,7 +101,7 @@
...
@@ -102,7 +101,7 @@
</div>
</div>
<div class=" flex-1 self-center font-medium line-clamp-1">
<div class=" flex-1 self-center font-medium line-clamp-1">
<div>
<div>
{title != '' ? title : WEBUI_NAME}
{title != '' ? title :
$
WEBUI_NAME}
</div>
</div>
</div>
</div>
...
...
src/lib/components/layout/Sidebar.svelte
View file @
ee22e641
...
@@ -16,6 +16,8 @@
...
@@ -16,6 +16,8 @@
updateChatById
updateChatById
} from '$lib/apis/chats';
} from '$lib/apis/chats';
import toast from 'svelte-french-toast';
import toast from 'svelte-french-toast';
import { slide } from 'svelte/transition';
import { WEBUI_BASE_URL } from '$lib/constants';
let show = false;
let show = false;
let navElement;
let navElement;
...
@@ -113,7 +115,11 @@
...
@@ -113,7 +115,11 @@
>
>
<div class="flex self-center">
<div class="flex self-center">
<div class="self-center mr-1.5">
<div class="self-center mr-1.5">
<img src="/favicon.png" class=" w-7 -translate-x-1.5 rounded-full" alt="logo" />
<img
src="{WEBUI_BASE_URL}/static/favicon.png"
class=" w-7 -translate-x-1.5 rounded-full"
alt="logo"
/>
</div>
</div>
<div class=" self-center font-medium text-sm">New Chat</div>
<div class=" self-center font-medium text-sm">New Chat</div>
...
@@ -562,6 +568,7 @@
...
@@ -562,6 +568,7 @@
<div
<div
id="dropdownDots"
id="dropdownDots"
class="absolute z-40 bottom-[70px] 4.5rem rounded-lg shadow w-[240px] bg-gray-900"
class="absolute z-40 bottom-[70px] 4.5rem rounded-lg shadow w-[240px] bg-gray-900"
in:slide={{ duration: 150 }}
>
>
<div class="py-2 w-full">
<div class="py-2 w-full">
{#if $user.role === 'admin'}
{#if $user.role === 'admin'}
...
...
src/lib/constants.ts
View file @
ee22e641
import
{
dev
}
from
'
$app/environment
'
;
import
{
dev
}
from
'
$app/environment
'
;
// import { version } from '../../package.json';
// import { version } from '../../package.json';
export
const
WEBUI
_NAME
=
'
Open WebUI
'
;
export
const
APP
_NAME
=
'
Open WebUI
'
;
export
const
WEBUI_BASE_URL
=
dev
?
`http://
${
location
.
hostname
}
:8080`
:
``
;
export
const
WEBUI_BASE_URL
=
dev
?
`http://
${
location
.
hostname
}
:8080`
:
``
;
export
const
WEBUI_API_BASE_URL
=
`
${
WEBUI_BASE_URL
}
/api/v1`
;
export
const
WEBUI_API_BASE_URL
=
`
${
WEBUI_BASE_URL
}
/api/v1`
;
...
@@ -13,8 +13,7 @@ export const AUDIO_API_BASE_URL = `${WEBUI_BASE_URL}/audio/api/v1`;
...
@@ -13,8 +13,7 @@ export const AUDIO_API_BASE_URL = `${WEBUI_BASE_URL}/audio/api/v1`;
export
const
IMAGES_API_BASE_URL
=
`
${
WEBUI_BASE_URL
}
/images/api/v1`
;
export
const
IMAGES_API_BASE_URL
=
`
${
WEBUI_BASE_URL
}
/images/api/v1`
;
export
const
RAG_API_BASE_URL
=
`
${
WEBUI_BASE_URL
}
/rag/api/v1`
;
export
const
RAG_API_BASE_URL
=
`
${
WEBUI_BASE_URL
}
/rag/api/v1`
;
export
const
WEB_UI_VERSION
=
APP_VERSION
;
export
const
WEBUI_VERSION
=
APP_VERSION
;
export
const
REQUIRED_OLLAMA_VERSION
=
'
0.1.16
'
;
export
const
REQUIRED_OLLAMA_VERSION
=
'
0.1.16
'
;
export
const
SUPPORTED_FILE_TYPE
=
[
export
const
SUPPORTED_FILE_TYPE
=
[
...
...
src/lib/stores/index.ts
View file @
ee22e641
import
{
APP_NAME
}
from
'
$lib/constants
'
;
import
{
writable
}
from
'
svelte/store
'
;
import
{
writable
}
from
'
svelte/store
'
;
// Backend
// Backend
export
const
WEBUI_NAME
=
writable
(
APP_NAME
);
export
const
config
=
writable
(
undefined
);
export
const
config
=
writable
(
undefined
);
export
const
user
=
writable
(
undefined
);
export
const
user
=
writable
(
undefined
);
...
@@ -32,3 +34,4 @@ export const documents = writable([
...
@@ -32,3 +34,4 @@ export const documents = writable([
export
const
settings
=
writable
({});
export
const
settings
=
writable
({});
export
const
showSettings
=
writable
(
false
);
export
const
showSettings
=
writable
(
false
);
export
const
showChangelog
=
writable
(
false
);
src/routes/(app)/+layout.svelte
View file @
ee22e641
<script lang="ts">
<script lang="ts">
import toast from 'svelte-french-toast';
import toast from 'svelte-french-toast';
import { openDB, deleteDB } from 'idb';
import { openDB, deleteDB } from 'idb';
import { onMount, tick } from 'svelte';
import { goto } from '$app/navigation';
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 { getOllamaModels, getOllamaVersion } from '$lib/apis/ollama';
import { getOllamaModels, getOllamaVersion } from '$lib/apis/ollama';
import { getModelfiles } from '$lib/apis/modelfiles';
import { getModelfiles } from '$lib/apis/modelfiles';
import { getPrompts } from '$lib/apis/prompts';
import { getPrompts } from '$lib/apis/prompts';
import { getOpenAIModels } from '$lib/apis/openai';
import { getOpenAIModels } from '$lib/apis/openai';
import { getLiteLLMModels } from '$lib/apis/litellm';
import { getLiteLLMModels } from '$lib/apis/litellm';
import { getDocs } from '$lib/apis/documents';
import { getAllChatTags } from '$lib/apis/chats';
import {
import {
user,
user,
...
@@ -22,16 +23,17 @@
...
@@ -22,16 +23,17 @@
modelfiles,
modelfiles,
prompts,
prompts,
documents,
documents,
tags
tags,
showChangelog,
config
} from '$lib/stores';
} from '$lib/stores';
import { REQUIRED_OLLAMA_VERSION, WEBUI_API_BASE_URL } from '$lib/constants';
import { REQUIRED_OLLAMA_VERSION, WEBUI_API_BASE_URL } from '$lib/constants';
import { checkVersion } from '$lib/utils';
import SettingsModal from '$lib/components/chat/SettingsModal.svelte';
import SettingsModal from '$lib/components/chat/SettingsModal.svelte';
import Sidebar from '$lib/components/layout/Sidebar.svelte';
import Sidebar from '$lib/components/layout/Sidebar.svelte';
import { checkVersion } from '$lib/utils';
import ShortcutsModal from '$lib/components/chat/ShortcutsModal.svelte';
import ShortcutsModal from '$lib/components/chat/ShortcutsModal.svelte';
import { getDocs } from '$lib/apis/documents';
import ChangelogModal from '$lib/components/ChangelogModal.svelte';
import { getAllChatTags } from '$lib/apis/chats';
let ollamaVersion = '';
let ollamaVersion = '';
let loaded = false;
let loaded = false;
...
@@ -190,6 +192,10 @@
...
@@ -190,6 +192,10 @@
}
}
});
});
if ($user.role === 'admin') {
showChangelog.set(localStorage.version !== $config.version);
}
await tick();
await tick();
}
}
...
@@ -363,6 +369,7 @@
...
@@ -363,6 +369,7 @@
>
>
<Sidebar />
<Sidebar />
<SettingsModal bind:show={$showSettings} />
<SettingsModal bind:show={$showSettings} />
<ChangelogModal bind:show={$showChangelog} />
<slot />
<slot />
</div>
</div>
</div>
</div>
...
...
src/routes/(app)/+page.svelte
View file @
ee22e641
...
@@ -37,6 +37,7 @@
...
@@ -37,6 +37,7 @@
import
Navbar
from
'$lib/components/layout/Navbar.svelte'
;
import
Navbar
from
'$lib/components/layout/Navbar.svelte'
;
import
{
RAGTemplate
}
from
'$lib/utils/rag'
;
import
{
RAGTemplate
}
from
'$lib/utils/rag'
;
import
{
LITELLM_API_BASE_URL
,
OPENAI_API_BASE_URL
}
from
'$lib/constants'
;
import
{
LITELLM_API_BASE_URL
,
OPENAI_API_BASE_URL
}
from
'$lib/constants'
;
import
{
WEBUI_BASE_URL
}
from
'$lib/constants'
;
let
stopResponseFlag
=
false
;
let
stopResponseFlag
=
false
;
let
autoScroll
=
true
;
let
autoScroll
=
true
;
...
@@ -335,7 +336,7 @@
...
@@ -335,7 +336,7 @@
content
:
$
settings
.
system
content
:
$
settings
.
system
}
}
:
undefined
,
:
undefined
,
...
messages
...
messages
.
filter
((
message
)
=>
!message.deleted)
]
]
.
filter
((
message
)
=>
message
)
.
filter
((
message
)
=>
message
)
.
map
((
message
,
idx
,
arr
)
=>
({
.
map
((
message
,
idx
,
arr
)
=>
({
...
@@ -453,7 +454,7 @@
...
@@ -453,7 +454,7 @@
:
`${
model
}`,
:
`${
model
}`,
{
{
body
:
responseMessage
.
content
,
body
:
responseMessage
.
content
,
icon
:
selectedModelfile
?.
imageUrl
??
'
/favicon.png
'
icon
:
selectedModelfile
?.
imageUrl
??
`${
WEBUI_BASE_URL
}/
static
/
favicon
.
png
`
}
}
);
);
}
}
...
@@ -538,6 +539,17 @@
...
@@ -538,6 +539,17 @@
stream
:
true
,
stream
:
true
,
messages
:
[
messages
:
[
$
settings
.
system
$
settings
.
system
?
{
role
:
'system'
,
content
:
$
settings
.
system
}
:
undefined
,
...
messages
.
filter
((
message
)
=>
!message.deleted)
]
.
filter
((
message
)
=>
message
)
.
map
((
message
,
idx
,
arr
)
=>
({
role
:
message
.
role
,
...(
message
.
files
?.
filter
((
file
)
=>
file
.
type
===
'image'
).
length
>
0
??
false
?
{
?
{
role
:
'system'
,
role
:
'system'
,
content
:
$
settings
.
system
content
:
$
settings
.
system
...
@@ -627,7 +639,7 @@
...
@@ -627,7 +639,7 @@
if
($
settings
.
notificationEnabled
&&
!document.hasFocus()) {
if
($
settings
.
notificationEnabled
&&
!document.hasFocus()) {
const
notification
=
new
Notification
(`
OpenAI
${
model
}`,
{
const
notification
=
new
Notification
(`
OpenAI
${
model
}`,
{
body
:
responseMessage
.
content
,
body
:
responseMessage
.
content
,
icon
:
'
/favicon.png
'
icon
:
`${
WEBUI_BASE_URL
}/
static
/
favicon
.
png
`
});
});
}
}
...
...
src/routes/(app)/c/[id]/+page.svelte
View file @
ee22e641
...
@@ -37,6 +37,7 @@
...
@@ -37,6 +37,7 @@
import ModelSelector from '$lib/components/chat/ModelSelector.svelte';
import ModelSelector from '$lib/components/chat/ModelSelector.svelte';
import Navbar from '$lib/components/layout/Navbar.svelte';
import Navbar from '$lib/components/layout/Navbar.svelte';
import { RAGTemplate } from '$lib/utils/rag';
import { RAGTemplate } from '$lib/utils/rag';
import { WEBUI_BASE_URL } from '$lib/constants';
let loaded = false;
let loaded = false;
...
@@ -348,7 +349,7 @@
...
@@ -348,7 +349,7 @@
content: $settings.system
content: $settings.system
}
}
: undefined,
: undefined,
...messages
...messages
.filter((message) => !message.deleted)
]
]
.filter((message) => message)
.filter((message) => message)
.map((message, idx, arr) => ({
.map((message, idx, arr) => ({
...
@@ -466,7 +467,7 @@
...
@@ -466,7 +467,7 @@
: `${model}`,
: `${model}`,
{
{
body: responseMessage.content,
body: responseMessage.content,
icon: selectedModelfile?.imageUrl ??
'
/favicon.png
'
icon: selectedModelfile?.imageUrl ??
`${WEBUI_BASE_URL}/static
/favicon.png
`
}
}
);
);
}
}
...
@@ -555,7 +556,7 @@
...
@@ -555,7 +556,7 @@
content: $settings.system
content: $settings.system
}
}
: undefined,
: undefined,
...messages
...messages
.filter((message) => !message.deleted)
]
]
.filter((message) => message)
.filter((message) => message)
.map((message, idx, arr) => ({
.map((message, idx, arr) => ({
...
@@ -637,7 +638,7 @@
...
@@ -637,7 +638,7 @@
if ($settings.notificationEnabled && !document.hasFocus()) {
if ($settings.notificationEnabled && !document.hasFocus()) {
const notification = new Notification(`OpenAI ${model}`, {
const notification = new Notification(`OpenAI ${model}`, {
body: responseMessage.content,
body: responseMessage.content,
icon:
'
/favicon.png
'
icon:
`${WEBUI_BASE_URL}/static
/favicon.png
`
});
});
}
}
...
...
src/routes/+layout.svelte
View file @
ee22e641
<script>
<script>
import { onMount, tick } from 'svelte';
import { onMount, tick } from 'svelte';
import { config, user, theme } from '$lib/stores';
import { config, user, theme
, WEBUI_NAME
} from '$lib/stores';
import { goto } from '$app/navigation';
import { goto } from '$app/navigation';
import toast, { Toaster } from 'svelte-french-toast';
import toast, { Toaster } from 'svelte-french-toast';
...
@@ -10,7 +10,7 @@
...
@@ -10,7 +10,7 @@
import '../app.css';
import '../app.css';
import '../tailwind.css';
import '../tailwind.css';
import 'tippy.js/dist/tippy.css';
import 'tippy.js/dist/tippy.css';
import { WEBUI_
NAME
} from '$lib/constants';
import { WEBUI_
BASE_URL
} from '$lib/constants';
let loaded = false;
let loaded = false;
...
@@ -22,6 +22,8 @@
...
@@ -22,6 +22,8 @@
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);
console.log(backendConfig);
console.log(backendConfig);
if ($config) {
if ($config) {
...
@@ -55,7 +57,8 @@
...
@@ -55,7 +57,8 @@
</script>
</script>
<svelte:head>
<svelte:head>
<title>{WEBUI_NAME}</title>
<title>{$WEBUI_NAME}</title>
<link rel="icon" href="{WEBUI_BASE_URL}/static/favicon.png" />
<link rel="stylesheet" type="text/css" href="/themes/rosepine.css" />
<link rel="stylesheet" type="text/css" href="/themes/rosepine.css" />
<link rel="stylesheet" type="text/css" href="/themes/rosepine-dawn.css" />
<link rel="stylesheet" type="text/css" href="/themes/rosepine-dawn.css" />
...
...
src/routes/auth/+page.svelte
View file @
ee22e641
<script>
<script>
import { goto } from '$app/navigation';
import { goto } from '$app/navigation';
import { userSignIn, userSignUp } from '$lib/apis/auths';
import { userSignIn, userSignUp } from '$lib/apis/auths';
import { WEBUI_API_BASE_URL, WEBUI_
NAME
} from '$lib/constants';
import { WEBUI_API_BASE_URL, WEBUI_
BASE_URL
} from '$lib/constants';
import { config, user } from '$lib/stores';
import {
WEBUI_NAME,
config, user } from '$lib/stores';
import { onMount } from 'svelte';
import { onMount } from 'svelte';
import toast from 'svelte-french-toast';
import toast from 'svelte-french-toast';
...
@@ -61,7 +61,7 @@
...
@@ -61,7 +61,7 @@
<div class="fixed m-10 z-50">
<div class="fixed m-10 z-50">
<div class="flex space-x-2">
<div class="flex space-x-2">
<div class=" self-center">
<div class=" self-center">
<img src="/favicon.png" class=" w-8 rounded-full" alt="logo" />
<img src="
{WEBUI_BASE_URL}/static
/favicon.png" class=" w-8 rounded-full" alt="logo" />
</div>
</div>
</div>
</div>
</div>
</div>
...
@@ -90,12 +90,12 @@
...
@@ -90,12 +90,12 @@
}}
}}
>
>
<div class=" text-xl md:text-2xl font-bold">
<div class=" text-xl md:text-2xl font-bold">
{mode === 'signin' ? 'Sign in' : 'Sign up'} to {WEBUI_NAME}
{mode === 'signin' ? 'Sign in' : 'Sign up'} to {
$
WEBUI_NAME}
</div>
</div>
{#if mode === 'signup'}
{#if mode === 'signup'}
<div class=" mt-1 text-xs font-medium text-gray-500">
<div class=" mt-1 text-xs font-medium text-gray-500">
ⓘ {WEBUI_NAME} does not make any external connections, and your data stays securely on
ⓘ {
$
WEBUI_NAME} does not make any external connections, and your data stays securely on
your locally hosted server.
your locally hosted server.
</div>
</div>
{/if}
{/if}
...
...
src/routes/error/+page.svelte
View file @
ee22e641
<script>
<script>
import { goto } from '$app/navigation';
import { goto } from '$app/navigation';
import { WEBUI_NAME } from '$lib/constants';
import { WEBUI_NAME, config } from '$lib/stores';
import { config } from '$lib/stores';
import { onMount } from 'svelte';
import { onMount } from 'svelte';
let loaded = false;
let loaded = false;
...
@@ -20,7 +19,7 @@
...
@@ -20,7 +19,7 @@
<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">{
$
WEBUI_NAME} Backend Required</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
Oops! You're using an unsupported method (frontend only). Please serve the WebUI from
...
...
Prev
1
2
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment