Sfoglia il codice sorgente

feat: save temporary chats

Timothy Jaeryang Baek 1 mese fa
parent
commit
575db66295

+ 10 - 7
backend/open_webui/routers/files.py

@@ -129,13 +129,16 @@ def upload_file(
         id = str(uuid.uuid4())
         name = filename
         filename = f"{id}_{filename}"
-        tags = {
-            "OpenWebUI-User-Email": user.email,
-            "OpenWebUI-User-Id": user.id,
-            "OpenWebUI-User-Name": user.name,
-            "OpenWebUI-File-Id": id,
-        }
-        contents, file_path = Storage.upload_file(file.file, filename, tags)
+        contents, file_path = Storage.upload_file(
+            file.file,
+            filename,
+            {
+                "OpenWebUI-User-Email": user.email,
+                "OpenWebUI-User-Id": user.id,
+                "OpenWebUI-User-Name": user.name,
+                "OpenWebUI-File-Id": id,
+            },
+        )
 
         file_item = Files.insert_new_file(
             user.id,

+ 36 - 0
src/lib/components/chat/Chat.svelte

@@ -2196,6 +2196,42 @@
 						shareEnabled={!!history.currentId}
 						{initNewChat}
 						showBanners={!showCommands}
+						onSaveTempChat={async () => {
+							try {
+								if (!history?.currentId || !Object.keys(history.messages).length) {
+									toast.error($i18n.t('No conversation to save'));
+									return;
+								}
+								const messages = createMessagesList(history, history.currentId);
+								const title =
+									messages.find((m) => m.role === 'user')?.content ?? $i18n.t('New Chat');
+
+								const savedChat = await createNewChat(
+									localStorage.token,
+									{
+										id: uuidv4(),
+										title: title.length > 50 ? `${title.slice(0, 50)}...` : title,
+										models: selectedModels,
+										history: history,
+										messages: messages,
+										timestamp: Date.now()
+									},
+									null
+								);
+
+								if (savedChat) {
+									temporaryChatEnabled.set(false);
+									chatId.set(savedChat.id);
+									chats.set(await getChatList(localStorage.token, $currentChatPage));
+
+									await goto(`/c/${savedChat.id}`);
+									toast.success($i18n.t('Conversation saved successfully'));
+								}
+							} catch (error) {
+								console.error('Error saving conversation:', error);
+								toast.error($i18n.t('Failed to save conversation'));
+							}
+						}}
 					/>
 
 					<div class="flex flex-col flex-auto z-10 w-full @container overflow-auto">

+ 45 - 26
src/lib/components/chat/Navbar.svelte

@@ -18,6 +18,7 @@
 
 	import { slide } from 'svelte/transition';
 	import { page } from '$app/stores';
+	import { goto } from '$app/navigation';
 
 	import ShareChatModal from '../chat/ShareChatModal.svelte';
 	import ModelSelector from '../chat/ModelSelector.svelte';
@@ -34,7 +35,7 @@
 	import ChatBubbleDottedChecked from '../icons/ChatBubbleDottedChecked.svelte';
 
 	import EllipsisHorizontal from '../icons/EllipsisHorizontal.svelte';
-	import { goto } from '$app/navigation';
+	import ChatPlus from '../icons/ChatPlus.svelte';
 
 	const i18n = getContext('i18n');
 
@@ -48,6 +49,8 @@
 	export let showModelSelector = true;
 	export let showBanners = true;
 
+	export let onSaveTempChat: () => {};
+
 	let closedBannerIds = [];
 
 	let showShareChatModal = false;
@@ -105,31 +108,47 @@
 				<div class="self-start flex flex-none items-center text-gray-600 dark:text-gray-400">
 					<!-- <div class="md:hidden flex self-center w-[1px] h-5 mx-2 bg-gray-300 dark:bg-stone-700" /> -->
 
-					{#if !chat?.id && ($user?.role === 'user' ? ($user?.permissions?.chat?.temporary ?? true) && !($user?.permissions?.chat?.temporary_enforced ?? false) : true)}
-						<Tooltip content={$i18n.t(`Temporary Chat`)}>
-							<button
-								class="flex cursor-pointer px-2 py-2 rounded-xl hover:bg-gray-50 dark:hover:bg-gray-850 transition"
-								id="temporary-chat-button"
-								on:click={async () => {
-									temporaryChatEnabled.set(!$temporaryChatEnabled);
-									await goto('/');
-									// add 'temporary-chat=true' to the URL
-									if ($temporaryChatEnabled) {
-										window.history.replaceState(null, '', '?temporary-chat=true');
-									} else {
-										window.history.replaceState(null, '', location.pathname);
-									}
-								}}
-							>
-								<div class=" m-auto self-center">
-									{#if $temporaryChatEnabled}
-										<ChatBubbleDottedChecked className=" size-4.5" strokeWidth="1.5" />
-									{:else}
-										<ChatBubbleDotted className=" size-4.5" strokeWidth="1.5" />
-									{/if}
-								</div>
-							</button>
-						</Tooltip>
+					{#if $user?.role === 'user' ? ($user?.permissions?.chat?.temporary ?? true) && !($user?.permissions?.chat?.temporary_enforced ?? false) : true}
+						{#if !chat?.id}
+							<Tooltip content={$i18n.t(`Temporary Chat`)}>
+								<button
+									class="flex cursor-pointer px-2 py-2 rounded-xl hover:bg-gray-50 dark:hover:bg-gray-850 transition"
+									id="temporary-chat-button"
+									on:click={async () => {
+										temporaryChatEnabled.set(!$temporaryChatEnabled);
+										await goto('/');
+										// add 'temporary-chat=true' to the URL
+										if ($temporaryChatEnabled) {
+											window.history.replaceState(null, '', '?temporary-chat=true');
+										} else {
+											window.history.replaceState(null, '', location.pathname);
+										}
+									}}
+								>
+									<div class=" m-auto self-center">
+										{#if $temporaryChatEnabled}
+											<ChatBubbleDottedChecked className=" size-4.5" strokeWidth="1.5" />
+										{:else}
+											<ChatBubbleDotted className=" size-4.5" strokeWidth="1.5" />
+										{/if}
+									</div>
+								</button>
+							</Tooltip>
+						{:else if $temporaryChatEnabled}
+							<Tooltip content={$i18n.t(`Save Chat`)}>
+								<button
+									class="flex cursor-pointer px-2 py-2 rounded-xl hover:bg-gray-50 dark:hover:bg-gray-850 transition"
+									id="save-temporary-chat-button"
+									on:click={async () => {
+										onSaveTempChat();
+									}}
+								>
+									<div class=" m-auto self-center">
+										<ChatPlus className=" size-4.5" strokeWidth="1.5" />
+									</div>
+								</button>
+							</Tooltip>
+						{/if}
 					{/if}
 
 					{#if shareEnabled && chat && (chat.id || $temporaryChatEnabled)}

+ 19 - 0
src/lib/components/icons/ChatPlus.svelte

@@ -0,0 +1,19 @@
+<script lang="ts">
+	export let className = 'w-4 h-4';
+	export let strokeWidth = '1.5';
+</script>
+
+<svg
+	xmlns="http://www.w3.org/2000/svg"
+	fill="none"
+	viewBox="0 0 24 24"
+	stroke-width={strokeWidth}
+	stroke="currentColor"
+	class={className}
+	><path d="M9 12H12M15 12H12M12 12V9M12 12V15" stroke-linecap="round" stroke-linejoin="round"
+	></path><path
+		d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 13.8214 2.48697 15.5291 3.33782 17L2.5 21.5L7 20.6622C8.47087 21.513 10.1786 22 12 22Z"
+		stroke-linecap="round"
+		stroke-linejoin="round"
+	></path></svg
+>