forked from open-webui/open-webui
Merge pull request #842 from jannikstdl/release-notes-modal
Release Notes Modal
This commit is contained in:
commit
7bbb6bdabe
15 changed files with 326 additions and 20 deletions
25
CHANGELOG.md
Normal file
25
CHANGELOG.md
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [0.1.102] - 2024-02-22
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- **🖼️ Image Generation**: Generate Images using the stable-difusion-webui API. You can set this up in settings -> images.
|
||||||
|
- **📝 Change title generation prompt**: Change the promt used to generate titles for your chats. You can set this up in the settings -> interface.
|
||||||
|
- **🤖 Change embedding model**: Change the embedding model used to generate embeddings for your chats in the Dockerfile. Use any sentence transformer model from huggingface.co.
|
||||||
|
- **📢 CHANGELOG.md/Popup**: This popup will show you the latest changes. You can edit it in the constants.ts file.
|
||||||
|
|
||||||
|
## [0.1.101] - 2024-02-22
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- LaTex output formatting issue (#828)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Instead of having the previous 1.0.0-alpha.101, we switched to semantic versioning as a way to respect global conventions.
|
|
@ -73,6 +73,8 @@ COPY --from=build /app/onnx /root/.cache/chroma/onnx_models/all-MiniLM-L6-v2/onn
|
||||||
|
|
||||||
# copy built frontend files
|
# copy built frontend files
|
||||||
COPY --from=build /app/build /app/build
|
COPY --from=build /app/build /app/build
|
||||||
|
COPY --from=build /app/CHANGELOG.md /app/CHANGELOG.md
|
||||||
|
COPY --from=build /app/package.json /app/package.json
|
||||||
|
|
||||||
# copy backend files
|
# copy backend files
|
||||||
COPY ./backend .
|
COPY ./backend .
|
||||||
|
|
|
@ -6,6 +6,8 @@ from base64 import b64encode
|
||||||
from constants import ERROR_MESSAGES
|
from constants import ERROR_MESSAGES
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import json
|
import json
|
||||||
|
import markdown
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -23,6 +25,75 @@ except ImportError:
|
||||||
ENV = os.environ.get("ENV", "dev")
|
ENV = os.environ.get("ENV", "dev")
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(f"../package.json", "r") as f:
|
||||||
|
PACKAGE_DATA = json.load(f)
|
||||||
|
except:
|
||||||
|
PACKAGE_DATA = {"version": "0.0.0"}
|
||||||
|
|
||||||
|
VERSION = PACKAGE_DATA["version"]
|
||||||
|
|
||||||
|
|
||||||
|
# Function to parse each section
|
||||||
|
def parse_section(section):
|
||||||
|
items = []
|
||||||
|
for li in section.find_all("li"):
|
||||||
|
# Extract raw HTML string
|
||||||
|
raw_html = str(li)
|
||||||
|
|
||||||
|
# Extract text without HTML tags
|
||||||
|
text = li.get_text(separator=" ", strip=True)
|
||||||
|
|
||||||
|
# Split into title and content
|
||||||
|
parts = text.split(": ", 1)
|
||||||
|
title = parts[0].strip() if len(parts) > 1 else ""
|
||||||
|
content = parts[1].strip() if len(parts) > 1 else text
|
||||||
|
|
||||||
|
items.append({"title": title, "content": content, "raw": raw_html})
|
||||||
|
return items
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open("../CHANGELOG.md", "r") as file:
|
||||||
|
changelog_content = file.read()
|
||||||
|
except:
|
||||||
|
changelog_content = ""
|
||||||
|
|
||||||
|
# Convert markdown content to HTML
|
||||||
|
html_content = markdown.markdown(changelog_content)
|
||||||
|
|
||||||
|
# Parse the HTML content
|
||||||
|
soup = BeautifulSoup(html_content, "html.parser")
|
||||||
|
|
||||||
|
# Initialize JSON structure
|
||||||
|
changelog_json = {}
|
||||||
|
|
||||||
|
# Iterate over each version
|
||||||
|
for version in soup.find_all("h2"):
|
||||||
|
version_number = version.get_text().strip().split(" - ")[0][1:-1] # Remove brackets
|
||||||
|
date = version.get_text().strip().split(" - ")[1]
|
||||||
|
|
||||||
|
version_data = {"date": date}
|
||||||
|
|
||||||
|
# Find the next sibling that is a h3 tag (section title)
|
||||||
|
current = version.find_next_sibling()
|
||||||
|
|
||||||
|
print(current)
|
||||||
|
|
||||||
|
while current and current.name != "h2":
|
||||||
|
if current.name == "h3":
|
||||||
|
section_title = current.get_text().lower() # e.g., "added", "fixed"
|
||||||
|
section_items = parse_section(current.find_next_sibling("ul"))
|
||||||
|
version_data[section_title] = section_items
|
||||||
|
|
||||||
|
# Move to the next element
|
||||||
|
current = current.find_next_sibling()
|
||||||
|
|
||||||
|
changelog_json[version_number] = version_data
|
||||||
|
|
||||||
|
|
||||||
|
CHANGELOG = changelog_json
|
||||||
|
|
||||||
####################################
|
####################################
|
||||||
# DATA/FRONTEND BUILD DIR
|
# DATA/FRONTEND BUILD DIR
|
||||||
####################################
|
####################################
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
import json
|
||||||
|
import markdown
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
|
||||||
from fastapi import FastAPI, Request
|
from fastapi import FastAPI, Request
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
from fastapi import HTTPException
|
from fastapi import HTTPException
|
||||||
|
@ -16,7 +20,7 @@ from apps.rag.main import app as rag_app
|
||||||
|
|
||||||
from apps.web.main import app as webui_app
|
from apps.web.main import app as webui_app
|
||||||
|
|
||||||
from config import ENV, FRONTEND_BUILD_DIR
|
from config import ENV, VERSION, CHANGELOG, FRONTEND_BUILD_DIR
|
||||||
|
|
||||||
|
|
||||||
class SPAStaticFiles(StaticFiles):
|
class SPAStaticFiles(StaticFiles):
|
||||||
|
@ -65,14 +69,21 @@ app.mount("/rag/api/v1", rag_app)
|
||||||
|
|
||||||
@app.get("/api/config")
|
@app.get("/api/config")
|
||||||
async def get_app_config():
|
async def get_app_config():
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"status": True,
|
"status": True,
|
||||||
|
"version": VERSION,
|
||||||
"images": images_app.state.ENABLED,
|
"images": images_app.state.ENABLED,
|
||||||
"default_models": webui_app.state.DEFAULT_MODELS,
|
"default_models": webui_app.state.DEFAULT_MODELS,
|
||||||
"default_prompt_suggestions": webui_app.state.DEFAULT_PROMPT_SUGGESTIONS,
|
"default_prompt_suggestions": webui_app.state.DEFAULT_PROMPT_SUGGESTIONS,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/api/changelog")
|
||||||
|
async def get_app_changelog():
|
||||||
|
return CHANGELOG
|
||||||
|
|
||||||
|
|
||||||
app.mount(
|
app.mount(
|
||||||
"/",
|
"/",
|
||||||
SPAStaticFiles(directory=FRONTEND_BUILD_DIR, html=True),
|
SPAStaticFiles(directory=FRONTEND_BUILD_DIR, html=True),
|
||||||
|
|
BIN
bun.lockb
BIN
bun.lockb
Binary file not shown.
21
package-lock.json
generated
21
package-lock.json
generated
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "open-webui",
|
"name": "open-webui",
|
||||||
"version": "0.0.1",
|
"version": "v1.0.0-alpha.101",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "open-webui",
|
"name": "open-webui",
|
||||||
"version": "0.0.1",
|
"version": "v1.0.0-alpha.101",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sveltejs/adapter-node": "^1.3.1",
|
"@sveltejs/adapter-node": "^1.3.1",
|
||||||
"async": "^3.2.5",
|
"async": "^3.2.5",
|
||||||
|
@ -38,6 +38,7 @@
|
||||||
"prettier-plugin-svelte": "^2.10.1",
|
"prettier-plugin-svelte": "^2.10.1",
|
||||||
"svelte": "^4.0.5",
|
"svelte": "^4.0.5",
|
||||||
"svelte-check": "^3.4.3",
|
"svelte-check": "^3.4.3",
|
||||||
|
"svelte-confetti": "^1.3.2",
|
||||||
"tailwindcss": "^3.3.3",
|
"tailwindcss": "^3.3.3",
|
||||||
"tslib": "^2.4.1",
|
"tslib": "^2.4.1",
|
||||||
"typescript": "^5.0.0",
|
"typescript": "^5.0.0",
|
||||||
|
@ -3174,6 +3175,15 @@
|
||||||
"svelte": "^3.55.0 || ^4.0.0-next.0 || ^4.0.0"
|
"svelte": "^3.55.0 || ^4.0.0-next.0 || ^4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/svelte-confetti": {
|
||||||
|
"version": "1.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/svelte-confetti/-/svelte-confetti-1.3.2.tgz",
|
||||||
|
"integrity": "sha512-R+JwFTC7hIgWVA/OuXrkj384B7CMoceb0t9VacyW6dORTQg0pWojVBB8Bo3tM30cLEQE48Fekzqgx+XSzHESMA==",
|
||||||
|
"dev": true,
|
||||||
|
"peerDependencies": {
|
||||||
|
"svelte": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/svelte-eslint-parser": {
|
"node_modules/svelte-eslint-parser": {
|
||||||
"version": "0.33.1",
|
"version": "0.33.1",
|
||||||
"resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-0.33.1.tgz",
|
"resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-0.33.1.tgz",
|
||||||
|
@ -5852,6 +5862,13 @@
|
||||||
"typescript": "^5.0.3"
|
"typescript": "^5.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"svelte-confetti": {
|
||||||
|
"version": "1.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/svelte-confetti/-/svelte-confetti-1.3.2.tgz",
|
||||||
|
"integrity": "sha512-R+JwFTC7hIgWVA/OuXrkj384B7CMoceb0t9VacyW6dORTQg0pWojVBB8Bo3tM30cLEQE48Fekzqgx+XSzHESMA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
"svelte-eslint-parser": {
|
"svelte-eslint-parser": {
|
||||||
"version": "0.33.1",
|
"version": "0.33.1",
|
||||||
"resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-0.33.1.tgz",
|
"resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-0.33.1.tgz",
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
"prettier-plugin-svelte": "^2.10.1",
|
"prettier-plugin-svelte": "^2.10.1",
|
||||||
"svelte": "^4.0.5",
|
"svelte": "^4.0.5",
|
||||||
"svelte-check": "^3.4.3",
|
"svelte-check": "^3.4.3",
|
||||||
|
"svelte-confetti": "^1.3.2",
|
||||||
"tailwindcss": "^3.3.3",
|
"tailwindcss": "^3.3.3",
|
||||||
"tslib": "^2.4.1",
|
"tslib": "^2.4.1",
|
||||||
"typescript": "^5.0.0",
|
"typescript": "^5.0.0",
|
||||||
|
|
|
@ -21,3 +21,25 @@ export const getBackendConfig = async () => {
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getChangelog = async () => {
|
||||||
|
let error = null;
|
||||||
|
|
||||||
|
const res = await fetch(`${WEBUI_BASE_URL}/api/changelog`, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(async (res) => {
|
||||||
|
if (!res.ok) throw await res.json();
|
||||||
|
return res.json();
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
error = err;
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
115
src/lib/components/ChangelogModal.svelte
Normal file
115
src/lib/components/ChangelogModal.svelte
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
import { Confetti } from 'svelte-confetti';
|
||||||
|
|
||||||
|
import { config } from '$lib/stores';
|
||||||
|
|
||||||
|
import { WEBUI_NAME, WEB_UI_VERSION } from '$lib/constants';
|
||||||
|
import { getChangelog } from '$lib/apis';
|
||||||
|
|
||||||
|
import Modal from './common/Modal.svelte';
|
||||||
|
|
||||||
|
export let show = false;
|
||||||
|
|
||||||
|
let changelog = null;
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
const res = await getChangelog();
|
||||||
|
changelog = res;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Modal bind:show>
|
||||||
|
<div class="px-5 py-4 dark:text-gray-300">
|
||||||
|
<div class="flex justify-between items-start">
|
||||||
|
<div class="text-xl font-bold">
|
||||||
|
What’s New in {WEBUI_NAME}
|
||||||
|
<Confetti x={[-1, -0.25]} y={[0, 0.5]} />
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
class="self-center"
|
||||||
|
on:click={() => {
|
||||||
|
show = false;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="currentColor"
|
||||||
|
class="w-5 h-5"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center mt-1">
|
||||||
|
<div class="text-sm dark:text-gray-200">Release Notes</div>
|
||||||
|
<div class="flex self-center w-[1px] h-6 mx-2.5 bg-gray-200 dark:bg-gray-700" />
|
||||||
|
<div class="text-sm dark:text-gray-200">
|
||||||
|
v{WEB_UI_VERSION}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr class=" dark:border-gray-800" />
|
||||||
|
|
||||||
|
<div class=" w-full p-4 px-5">
|
||||||
|
<div class=" overflow-y-scroll max-h-80">
|
||||||
|
<div class="mb-3">
|
||||||
|
{#if changelog}
|
||||||
|
{#each Object.keys(changelog) as version}
|
||||||
|
<div class=" mb-3 pr-2">
|
||||||
|
<div class="font-bold text-xl mb-1 dark:text-white">
|
||||||
|
v{version} - {changelog[version].date}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr class=" dark:border-gray-800 my-2" />
|
||||||
|
|
||||||
|
{#each Object.keys(changelog[version]).filter((section) => section !== 'date') as section}
|
||||||
|
<div class="">
|
||||||
|
<div
|
||||||
|
class="font-bold uppercase text-xs {section === 'added'
|
||||||
|
? 'text-white bg-blue-600'
|
||||||
|
: section === 'fixed'
|
||||||
|
? 'text-white bg-green-600'
|
||||||
|
: section === 'changed'
|
||||||
|
? 'text-white bg-yellow-600'
|
||||||
|
: section === 'removed'
|
||||||
|
? 'text-white bg-red-600'
|
||||||
|
: ''} w-fit px-3 rounded-full my-2.5"
|
||||||
|
>
|
||||||
|
{section}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="my-2.5 px-1.5">
|
||||||
|
{#each Object.keys(changelog[version][section]) as item}
|
||||||
|
<div class="text-sm mb-2">
|
||||||
|
<div class="font-semibold uppercase">
|
||||||
|
{changelog[version][section][item].title}
|
||||||
|
</div>
|
||||||
|
<div class="mb-2 mt-1">{changelog[version][section][item].content}</div>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-end pt-3 text-sm font-medium">
|
||||||
|
<button
|
||||||
|
on:click={() => {
|
||||||
|
localStorage.version = $config.version;
|
||||||
|
show = false;
|
||||||
|
}}
|
||||||
|
class=" px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-gray-100 transition rounded"
|
||||||
|
>
|
||||||
|
<span class="relative">Okay, Let's Go!</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
|
@ -1,7 +1,7 @@
|
||||||
<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_NAME, WEB_UI_VERSION } from '$lib/constants';
|
||||||
import { config } from '$lib/stores';
|
import { config, showChangelog } from '$lib/stores';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
let ollamaVersion = '';
|
let ollamaVersion = '';
|
||||||
|
@ -15,11 +15,26 @@
|
||||||
<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">
|
||||||
|
<div>
|
||||||
v{WEB_UI_VERSION}
|
v{WEB_UI_VERSION}
|
||||||
</div>
|
</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>
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<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';
|
||||||
|
@ -35,15 +35,16 @@
|
||||||
<!-- 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"
|
||||||
transition:fade={{ delay: 100, duration: 200 }}
|
in:fade={{ duration: 10 }}
|
||||||
on:click={(e) => {
|
on:click={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
}}
|
}}
|
||||||
|
@ -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>
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
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';
|
||||||
|
|
||||||
let show = false;
|
let show = false;
|
||||||
let navElement;
|
let navElement;
|
||||||
|
@ -562,6 +563,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'}
|
||||||
|
|
|
@ -12,7 +12,6 @@ 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 WEB_UI_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 = [
|
||||||
|
|
|
@ -32,3 +32,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);
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
<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 { getDocs } from '$lib/apis/documents';
|
||||||
|
import { getAllChatTags } from '$lib/apis/chats';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
user,
|
user,
|
||||||
|
@ -21,16 +22,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;
|
||||||
|
@ -182,6 +184,10 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if ($user.role === 'admin') {
|
||||||
|
showChangelog.set(localStorage.version !== $config.version);
|
||||||
|
}
|
||||||
|
|
||||||
await tick();
|
await tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -355,6 +361,7 @@
|
||||||
>
|
>
|
||||||
<Sidebar />
|
<Sidebar />
|
||||||
<SettingsModal bind:show={$showSettings} />
|
<SettingsModal bind:show={$showSettings} />
|
||||||
|
<ChangelogModal bind:show={$showChangelog} />
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue