Bladeren bron

feat: changelog.md

Timothy J. Baek 1 jaar geleden
bovenliggende
commit
9f950aea9c

+ 33 - 0
CHANGELOG.md

@@ -0,0 +1,33 @@
+# 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.
+
+### Fixed
+
+- X, Y, and Z
+
+### Changed
+
+- X, Y, and Z
+
+### Removed
+
+- X, Y, and Z
+
+## [0.1.101] - 2024-02-21
+
+### Added
+
+- X, Y, and Z

+ 8 - 0
backend/config.py

@@ -23,6 +23,14 @@ except ImportError:
 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"]
+
 ####################################
 # DATA/FRONTEND BUILD DIR
 ####################################

+ 76 - 1
backend/main.py

@@ -1,5 +1,9 @@
+from bs4 import BeautifulSoup
+import json
+import markdown
 import time
 
+
 from fastapi import FastAPI, Request
 from fastapi.staticfiles import StaticFiles
 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 config import ENV, FRONTEND_BUILD_DIR
+from config import ENV, VERSION, FRONTEND_BUILD_DIR
 
 
 class SPAStaticFiles(StaticFiles):
@@ -65,14 +69,85 @@ app.mount("/rag/api/v1", rag_app)
 
 @app.get("/api/config")
 async def get_app_config():
+
     return {
         "status": True,
+        "version": VERSION,
         "images": images_app.state.ENABLED,
         "default_models": webui_app.state.DEFAULT_MODELS,
         "default_prompt_suggestions": webui_app.state.DEFAULT_PROMPT_SUGGESTIONS,
     }
 
 
+# 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
+
+
+@app.get("/api/changelog")
+async def get_app_changelog():
+    try:
+        with open("../CHANGELOG.md", "r") as file:
+            changelog_content = file.read()
+        # Convert markdown content to HTML
+        html_content = markdown.markdown(changelog_content)
+
+        # Parse the HTML content
+        soup = BeautifulSoup(html_content, "html.parser")
+
+        print(soup)
+        # 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
+
+        # print(changelog_json)
+
+        # Return content as JSON string
+        return changelog_json
+    except FileNotFoundError:
+        return {"error": "readme.md not found"}
+    except Exception as e:
+        return {"error": f"An error occurred: {e}"}
+
+
 app.mount(
     "/",
     SPAStaticFiles(directory=FRONTEND_BUILD_DIR, html=True),

+ 2 - 2
package.json

@@ -1,6 +1,6 @@
 {
 	"name": "open-webui",
-	"version": "v1.0.0-alpha.101",
+	"version": "0.1.102",
 	"private": true,
 	"scripts": {
 		"dev": "vite dev --host",
@@ -53,4 +53,4 @@
 		"tippy.js": "^6.3.7",
 		"uuid": "^9.0.1"
 	}
-}
+}

+ 22 - 0
src/lib/apis/index.ts

@@ -21,3 +21,25 @@ export const getBackendConfig = async () => {
 
 	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;
+};

+ 90 - 0
src/lib/components/ChangelogModal.svelte

@@ -0,0 +1,90 @@
+<script lang="ts">
+	import Modal from './common/Modal.svelte';
+	import { Confetti } from 'svelte-confetti';
+	import { WEBUI_NAME, WEB_UI_VERSION } from '$lib/constants';
+	import { onMount } from 'svelte';
+	import { getChangelog } from '$lib/apis';
+
+	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">
+				{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=" pb-3 flex items-center mt-2">
+			<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>
+		<hr class=" dark:border-gray-800" />
+		<div class=" overflow-y-scroll max-h-80">
+			<div class="my-3">
+				{#if changelog}
+					{#each Object.keys(changelog) as version}
+						<div class="font-bold text-xl mb-1">
+							v{version} - {changelog[version].date}
+						</div>
+
+						{#each Object.keys(changelog[version]).filter((section) => section !== 'date') as section}
+							<div class="text-lg">
+								<div class="font-bold capitalize">{section}</div>
+
+								<div class="my-2">
+									{#each Object.keys(changelog[version][section]) as item}
+										<div class="text-sm mb-2">
+											<div class="font-semibold">
+												{changelog[version][section][item].title}
+											</div>
+											<div class="my-1.5">{changelog[version][section][item].content}</div>
+										</div>
+									{/each}
+								</div>
+							</div>
+						{/each}
+					{/each}
+				{/if}
+			</div>
+		</div>
+		<div class="flex justify-end pt-3 text-sm font-medium">
+			<button
+				on:click={() => {
+					show = false;
+				}}
+				class=" px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-gray-100 transition rounded"
+			>
+				<span class="relative">Ok, let's go!</span>
+			</button>
+		</div>
+	</div>
+</Modal>

+ 1 - 30
src/lib/components/chat/Settings/Interface.svelte

@@ -1,7 +1,7 @@
 <script lang="ts">
 	import { getBackendConfig } from '$lib/apis';
 	import { setDefaultPromptSuggestions } from '$lib/apis/configs';
-	import { config, models, user, showWhatsChanged } from '$lib/stores';
+	import { config, models, user } from '$lib/stores';
 	import { createEventDispatcher, onMount } from 'svelte';
 	import toast from 'svelte-french-toast';
 	const dispatch = createEventDispatcher();
@@ -18,7 +18,6 @@
 	// Interface
 	let promptSuggestions = [];
 	let showUsername = false;
-	let enableWhatsChanged = true;
 
 	const toggleFullScreenMode = async () => {
 		fullScreenMode = !fullScreenMode;
@@ -30,14 +29,6 @@
 		saveSettings({ showUsername: showUsername });
 	};
 
-	const toggleenableWhatsChanged = async () => {
-		enableWhatsChanged = !enableWhatsChanged;
-		if (enableWhatsChanged) {
-			showWhatsChanged.update((value) => true);
-		}
-		saveSettings({ enableWhatsChanged: enableWhatsChanged });
-	};
-
 	const toggleTitleAutoGenerate = async () => {
 		titleAutoGenerate = !titleAutoGenerate;
 		saveSettings({ titleAutoGenerate: titleAutoGenerate });
@@ -86,7 +77,6 @@
 		titleAutoGenerate = settings.titleAutoGenerate ?? true;
 		responseAutoCopy = settings.responseAutoCopy ?? false;
 		showUsername = settings.showUsername ?? false;
-		enableWhatsChanged = settings.enableWhatsChanged ?? true;
 		fullScreenMode = settings.fullScreenMode ?? false;
 		titleAutoGenerateModel = settings.titleAutoGenerateModel ?? '';
 		titleGenerationPrompt =
@@ -187,25 +177,6 @@
 					</button>
 				</div>
 			</div>
-			<div>
-				<div class=" py-0.5 flex w-full justify-between">
-					<div class=" self-center text-xs font-medium">Show "WhatsChanged" Modal on Startup</div>
-
-					<button
-						class="p-1 px-3 text-xs flex rounded transition"
-						on:click={() => {
-							toggleenableWhatsChanged();
-						}}
-						type="button"
-					>
-						{#if enableWhatsChanged === true}
-							<span class="ml-2 self-center">On</span>
-						{:else}
-							<span class="ml-2 self-center">Off</span>
-						{/if}
-					</button>
-				</div>
-			</div>
 		</div>
 
 		<hr class=" dark:border-gray-700" />

+ 0 - 79
src/lib/components/chat/WhatsChangedModal.svelte

@@ -1,79 +0,0 @@
-<script lang="ts">
-	import Modal from '../common/Modal.svelte';
-	import { Confetti } from 'svelte-confetti';
-	import { WEBUI_NAME, WEB_UI_VERSION, RELEASE_NOTES } from '$lib/constants';
-	import { config, showWhatsChanged } from '$lib/stores';
-
-	export let show = false;
-
-	function toggleVisibility() {
-		showWhatsChanged.update((value) => !value);
-	}
-
-	function handleClick() {
-		toggleVisibility();
-	}
-
-	let hasValidNotes = Array.isArray(RELEASE_NOTES) && RELEASE_NOTES.length > 0;
-</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">
-				{WEBUI_NAME}
-				<Confetti x={[-1, -0.25]} y={[0, 0.5]} />
-			</div>
-			<button class="self-center" on:click={handleClick}>
-				<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=" pb-3 flex items-center mt-2">
-			<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">
-				{$config && $config.version ? $config.version : WEB_UI_VERSION}
-			</div>
-		</div>
-		<hr class=" dark:border-gray-800" />
-		<div class="p-4 overflow-y-scroll max-h-80">
-			{#if !hasValidNotes}
-				<div class="pt-10 text-center font-bold">There are no notes given.</div>
-
-				<div class="pb-10 text-center">
-					Check
-					<a class="text-blue-500" href="https://github.com/open-webui/open-webui" target="_blank">
-						Open WebUI on GitHub</a
-					> for more information.
-				</div>
-			{:else}
-				{#each RELEASE_NOTES as { title, description }}
-					<div class="mt-4">
-						<div class="font-bold">{title}</div>
-						<div>{description}</div>
-					</div>
-				{/each}
-			{/if}
-		</div>
-		<div class="m-4 flex justify-end pt-3 text-sm font-medium">
-			<button
-				on:click={handleClick}
-				class=" rounded px-4 py-2 overflow-hidden group bg-green-600 relative hover:bg-gradient-to-r hover:from-green-600 hover:to-green-500 text-white hover:ring-2 hover:ring-offset-2 hover:ring-green-500 transition-all ease-out duration-300"
-			>
-				<span
-					class="absolute right-0 w-8 h-32 -mt-12 transition-all duration-1000 transform translate-x-12 bg-white opacity-10 rotate-12 group-hover:-translate-x-40 ease"
-				/>
-				<span class="relative">Ok, let's go!</span>
-			</button>
-		</div>
-	</div>
-</Modal>

+ 0 - 23
src/lib/constants.ts

@@ -12,29 +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 WEB_UI_VERSION = APP_VERSION;
-export const RELEASE_NOTES = [
-	{
-		title: ' 🖼️ Image Generation',
-		description:
-			'Generate Images using the stable-difusion-webui API. You can set this up in settings -> images.'
-	},
-	{
-		title: ' 📝 Change title generation prompt',
-		description:
-			'Change the promt used to generate titles for your chats. You can set this up in the settings -> interface.'
-	},
-	{
-		title: ' 🤖 Change embedding model',
-		description:
-			'Change the embedding model used to generate embeddings for your chats in the Dockerfile. Use any sentence transformer model from huggingface.co.'
-	},
-	{
-		title: ' 📢 This Whats Changed Popup',
-		description:
-			'This popup will show you the latest changes. You can edit it in the constants.ts file.'
-	}
-	//...
-];
 export const REQUIRED_OLLAMA_VERSION = '0.1.16';
 
 export const SUPPORTED_FILE_TYPE = [

+ 0 - 13
src/lib/stores/index.ts

@@ -32,16 +32,3 @@ export const documents = writable([
 
 export const settings = writable({});
 export const showSettings = writable(false);
-function createLocalStorageStore(key, startValue) {
-	const storedValue = localStorage.getItem(key);
-	const initialValue = storedValue ? JSON.parse(storedValue) : startValue;
-
-	const store = writable(initialValue);
-
-	store.subscribe((value) => {
-		localStorage.setItem(key, JSON.stringify(value));
-	});
-
-	return store;
-}
-export const showWhatsChanged = createLocalStorageStore('showWhatsChanged', true);

+ 3 - 0
src/routes/(app)/+layout.svelte

@@ -31,6 +31,7 @@
 	import ShortcutsModal from '$lib/components/chat/ShortcutsModal.svelte';
 	import { getDocs } from '$lib/apis/documents';
 	import { getAllChatTags } from '$lib/apis/chats';
+	import ChangelogModal from '$lib/components/ChangelogModal.svelte';
 
 	let ollamaVersion = '';
 	let loaded = false;
@@ -348,6 +349,8 @@
 					</div>
 				</div>
 			</div>
+		{:else}
+			<ChangelogModal show={true} />
 		{/if}
 
 		<div

+ 0 - 5
src/routes/(app)/+page.svelte

@@ -14,7 +14,6 @@
 		chats,
 		chatId,
 		config,
-		showWhatsChanged,
 		tags as _tags
 	} from '$lib/stores';
 	import { copyToClipboard, splitStream } from '$lib/utils';
@@ -36,7 +35,6 @@
 	import Messages from '$lib/components/chat/Messages.svelte';
 	import ModelSelector from '$lib/components/chat/ModelSelector.svelte';
 	import Navbar from '$lib/components/layout/Navbar.svelte';
-	import WhatsChangedModal from '$lib/components/chat//WhatsChangedModal.svelte';
 	import { RAGTemplate } from '$lib/utils/rag';
 
 	let stopResponseFlag = false;
@@ -799,9 +797,6 @@
 </script>
 
 <div class="h-screen max-h-[100dvh] w-full flex flex-col">
-	{#if $showWhatsChanged && !['pending'].includes($user.role) && $settings.enableWhatsChanged}
-		<WhatsChangedModal show={true} />
-	{/if}
 	<Navbar {title} shareEnabled={messages.length > 0} {initNewChat} {tags} {addTag} {deleteTag} />
 	<div class="flex flex-col flex-auto">
 		<div

+ 2 - 1
vite.config.ts

@@ -5,5 +5,6 @@ export default defineConfig({
 	plugins: [sveltekit()],
 	define: {
 		APP_VERSION: JSON.stringify(process.env.npm_package_version)
-	}
+	},
+	assetsInclude: ['**/*.md']
 });