瀏覽代碼

feat: delete all user chats

Timothy J. Baek 1 年之前
父節點
當前提交
d5dc36b2a9
共有 3 個文件被更改,包括 189 次插入123 次删除
  1. 20 0
      backend/apps/web/routers/chats.py
  2. 32 0
      src/lib/apis/chats/index.ts
  3. 137 123
      src/lib/components/chat/SettingsModal.svelte

+ 20 - 0
backend/apps/web/routers/chats.py

@@ -159,3 +159,23 @@ async def delete_chat_by_id(id: str, cred=Depends(bearer_scheme)):
             status_code=status.HTTP_401_UNAUTHORIZED,
             detail=ERROR_MESSAGES.INVALID_TOKEN,
         )
+
+
+############################
+# DeleteAllChats
+############################
+
+
+@router.delete("/", response_model=bool)
+async def delete_all_user_chats(cred=Depends(bearer_scheme)):
+    token = cred.credentials
+    user = Users.get_user_by_token(token)
+
+    if user:
+        result = Chats.delete_chats_by_user_id(user.id)
+        return result
+    else:
+        raise HTTPException(
+            status_code=status.HTTP_401_UNAUTHORIZED,
+            detail=ERROR_MESSAGES.INVALID_TOKEN,
+        )

+ 32 - 0
src/lib/apis/chats/index.ts

@@ -191,3 +191,35 @@ export const deleteChatById = async (token: string, id: string) => {
 
 	return res;
 };
+
+export const deleteAllChats = async (token: string) => {
+	let error = null;
+
+	const res = await fetch(`${WEBUI_API_BASE_URL}/chats/`, {
+		method: 'DELETE',
+		headers: {
+			Accept: 'application/json',
+			'Content-Type': 'application/json',
+			...(token && { authorization: `Bearer ${token}` })
+		}
+	})
+		.then(async (res) => {
+			if (!res.ok) throw await res.json();
+			return res.json();
+		})
+		.then((json) => {
+			return json;
+		})
+		.catch((err) => {
+			error = err;
+
+			console.log(err);
+			return null;
+		});
+
+	if (error) {
+		throw error;
+	}
+
+	return res;
+};

+ 137 - 123
src/lib/components/chat/SettingsModal.svelte

@@ -8,7 +8,7 @@
 	import { splitStream, getGravatarURL } from '$lib/utils';
 
 	import { getOllamaVersion } from '$lib/apis/ollama';
-	import { createNewChat, getAllChats, getChatList } from '$lib/apis/chats';
+	import { createNewChat, deleteAllChats, getAllChats, getChatList } from '$lib/apis/chats';
 	import {
 		WEB_UI_VERSION,
 		OLLAMA_API_BASE_URL,
@@ -19,6 +19,7 @@
 	import Advanced from './Settings/Advanced.svelte';
 	import Modal from '../common/Modal.svelte';
 	import { updateUserPassword } from '$lib/apis/auths';
+	import { goto } from '$app/navigation';
 
 	export let show = false;
 
@@ -83,7 +84,7 @@
 	// Chats
 
 	let importFiles;
-	let showDeleteHistoryConfirm = false;
+	let showDeleteConfirm = false;
 
 	const importChats = async (_chats) => {
 		for (const chat of _chats) {
@@ -114,6 +115,12 @@
 		reader.readAsText(importFiles[0]);
 	}
 
+	const deleteChats = async () => {
+		await goto('/');
+		await deleteAllChats(localStorage.token);
+		await chats.set(await getChatList(localStorage.token));
+	};
+
 	// Auth
 	let authEnabled = false;
 	let authType = 'Basic';
@@ -1618,147 +1625,154 @@
 					</form>
 				{:else if selectedTab === 'chats'}
 					<div class="flex flex-col h-full justify-between space-y-3 text-sm">
-						<div class="flex flex-col">
-							<input
-								id="chat-import-input"
-								bind:files={importFiles}
-								type="file"
-								accept=".json"
-								hidden
-							/>
-							<button
-								class=" flex rounded-md py-2 px-3.5 w-full hover:bg-gray-200 dark:hover:bg-gray-800 transition"
-								on:click={() => {
-									document.getElementById('chat-import-input').click();
-								}}
-							>
-								<div class=" self-center mr-3">
-									<svg
-										xmlns="http://www.w3.org/2000/svg"
-										viewBox="0 0 16 16"
-										fill="currentColor"
-										class="w-4 h-4"
-									>
-										<path
-											fill-rule="evenodd"
-											d="M4 2a1.5 1.5 0 0 0-1.5 1.5v9A1.5 1.5 0 0 0 4 14h8a1.5 1.5 0 0 0 1.5-1.5V6.621a1.5 1.5 0 0 0-.44-1.06L9.94 2.439A1.5 1.5 0 0 0 8.878 2H4Zm4 9.5a.75.75 0 0 1-.75-.75V8.06l-.72.72a.75.75 0 0 1-1.06-1.06l2-2a.75.75 0 0 1 1.06 0l2 2a.75.75 0 1 1-1.06 1.06l-.72-.72v2.69a.75.75 0 0 1-.75.75Z"
-											clip-rule="evenodd"
-										/>
-									</svg>
-								</div>
-								<div class=" self-center text-sm font-medium">Import Chats</div>
-							</button>
-							<button
-								class=" flex rounded-md py-2 px-3.5 w-full hover:bg-gray-200 dark:hover:bg-gray-800 transition"
-								on:click={() => {
-									exportChats();
-								}}
-							>
-								<div class=" self-center mr-3">
-									<svg
-										xmlns="http://www.w3.org/2000/svg"
-										viewBox="0 0 16 16"
-										fill="currentColor"
-										class="w-4 h-4"
-									>
-										<path
-											fill-rule="evenodd"
-											d="M4 2a1.5 1.5 0 0 0-1.5 1.5v9A1.5 1.5 0 0 0 4 14h8a1.5 1.5 0 0 0 1.5-1.5V6.621a1.5 1.5 0 0 0-.44-1.06L9.94 2.439A1.5 1.5 0 0 0 8.878 2H4Zm4 3.5a.75.75 0 0 1 .75.75v2.69l.72-.72a.75.75 0 1 1 1.06 1.06l-2 2a.75.75 0 0 1-1.06 0l-2-2a.75.75 0 0 1 1.06-1.06l.72.72V6.25A.75.75 0 0 1 8 5.5Z"
-											clip-rule="evenodd"
-										/>
-									</svg>
-								</div>
-								<div class=" self-center text-sm font-medium">Export Chats</div>
-							</button>
-						</div>
-						<!-- {#if showDeleteHistoryConfirm}
-							<div
-								class="flex justify-between rounded-md items-center py-3 px-3.5 w-full transition"
-							>
-								<div class="flex items-center">
-									<svg
-										xmlns="http://www.w3.org/2000/svg"
-										fill="none"
-										viewBox="0 0 24 24"
-										stroke-width="1.5"
-										stroke="currentColor"
-										class="w-5 h-5 mr-3"
-									>
-										<path
-											stroke-linecap="round"
-											stroke-linejoin="round"
-											d="M14.74 9l-.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 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0"
-										/>
-									</svg>
-									<span>Are you sure?</span>
-								</div>
-
-								<div class="flex space-x-1.5 items-center">
-									<button
-										class="hover:text-white transition"
-										on:click={() => {
-											deleteChatHistory();
-											showDeleteHistoryConfirm = false;
-										}}
-									>
+						<div class=" space-y-2">
+							<div class="flex flex-col">
+								<input
+									id="chat-import-input"
+									bind:files={importFiles}
+									type="file"
+									accept=".json"
+									hidden
+								/>
+								<button
+									class=" flex rounded-md py-2 px-3.5 w-full hover:bg-gray-200 dark:hover:bg-gray-800 transition"
+									on:click={() => {
+										document.getElementById('chat-import-input').click();
+									}}
+								>
+									<div class=" self-center mr-3">
 										<svg
 											xmlns="http://www.w3.org/2000/svg"
-											viewBox="0 0 20 20"
+											viewBox="0 0 16 16"
 											fill="currentColor"
 											class="w-4 h-4"
 										>
 											<path
 												fill-rule="evenodd"
-												d="M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z"
+												d="M4 2a1.5 1.5 0 0 0-1.5 1.5v9A1.5 1.5 0 0 0 4 14h8a1.5 1.5 0 0 0 1.5-1.5V6.621a1.5 1.5 0 0 0-.44-1.06L9.94 2.439A1.5 1.5 0 0 0 8.878 2H4Zm4 9.5a.75.75 0 0 1-.75-.75V8.06l-.72.72a.75.75 0 0 1-1.06-1.06l2-2a.75.75 0 0 1 1.06 0l2 2a.75.75 0 1 1-1.06 1.06l-.72-.72v2.69a.75.75 0 0 1-.75.75Z"
 												clip-rule="evenodd"
 											/>
 										</svg>
-									</button>
-									<button
-										class="hover:text-white transition"
-										on:click={() => {
-											showDeleteHistoryConfirm = false;
-										}}
-									>
+									</div>
+									<div class=" self-center text-sm font-medium">Import Chats</div>
+								</button>
+								<button
+									class=" flex rounded-md py-2 px-3.5 w-full hover:bg-gray-200 dark:hover:bg-gray-800 transition"
+									on:click={() => {
+										exportChats();
+									}}
+								>
+									<div class=" self-center mr-3">
 										<svg
 											xmlns="http://www.w3.org/2000/svg"
-											viewBox="0 0 20 20"
+											viewBox="0 0 16 16"
 											fill="currentColor"
 											class="w-4 h-4"
 										>
 											<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"
+												fill-rule="evenodd"
+												d="M4 2a1.5 1.5 0 0 0-1.5 1.5v9A1.5 1.5 0 0 0 4 14h8a1.5 1.5 0 0 0 1.5-1.5V6.621a1.5 1.5 0 0 0-.44-1.06L9.94 2.439A1.5 1.5 0 0 0 8.878 2H4Zm4 3.5a.75.75 0 0 1 .75.75v2.69l.72-.72a.75.75 0 1 1 1.06 1.06l-2 2a.75.75 0 0 1-1.06 0l-2-2a.75.75 0 0 1 1.06-1.06l.72.72V6.25A.75.75 0 0 1 8 5.5Z"
+												clip-rule="evenodd"
 											/>
 										</svg>
-									</button>
-								</div>
+									</div>
+									<div class=" self-center text-sm font-medium">Export Chats</div>
+								</button>
 							</div>
-						{:else}
-							<button
-								class=" flex rounded-md py-3 px-3.5 w-full hover:bg-gray-900 transition"
-								on:click={() => {
-									showDeleteHistoryConfirm = true;
-								}}
-							>
-								<div class="mr-3">
-									<svg
-										xmlns="http://www.w3.org/2000/svg"
-										fill="none"
-										viewBox="0 0 24 24"
-										stroke-width="1.5"
-										stroke="currentColor"
-										class="w-5 h-5"
-									>
-										<path
-											stroke-linecap="round"
-											stroke-linejoin="round"
-											d="M14.74 9l-.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 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0"
-										/>
-									</svg>
+
+							<hr class=" dark:border-gray-700" />
+
+							{#if showDeleteConfirm}
+								<div
+									class="flex justify-between rounded-md items-center py-2 px-3.5 w-full transition"
+								>
+									<div class="flex items-center space-x-3">
+										<svg
+											xmlns="http://www.w3.org/2000/svg"
+											viewBox="0 0 16 16"
+											fill="currentColor"
+											class="w-4 h-4"
+										>
+											<path
+												d="M2 3a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3Z"
+											/>
+											<path
+												fill-rule="evenodd"
+												d="M13 6H3v6a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V6ZM5.72 7.47a.75.75 0 0 1 1.06 0L8 8.69l1.22-1.22a.75.75 0 1 1 1.06 1.06L9.06 9.75l1.22 1.22a.75.75 0 1 1-1.06 1.06L8 10.81l-1.22 1.22a.75.75 0 0 1-1.06-1.06l1.22-1.22-1.22-1.22a.75.75 0 0 1 0-1.06Z"
+												clip-rule="evenodd"
+											/>
+										</svg>
+										<span>Are you sure?</span>
+									</div>
+
+									<div class="flex space-x-1.5 items-center">
+										<button
+											class="hover:text-white transition"
+											on:click={() => {
+												deleteChats();
+												showDeleteConfirm = false;
+											}}
+										>
+											<svg
+												xmlns="http://www.w3.org/2000/svg"
+												viewBox="0 0 20 20"
+												fill="currentColor"
+												class="w-4 h-4"
+											>
+												<path
+													fill-rule="evenodd"
+													d="M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z"
+													clip-rule="evenodd"
+												/>
+											</svg>
+										</button>
+										<button
+											class="hover:text-white transition"
+											on:click={() => {
+												showDeleteConfirm = false;
+											}}
+										>
+											<svg
+												xmlns="http://www.w3.org/2000/svg"
+												viewBox="0 0 20 20"
+												fill="currentColor"
+												class="w-4 h-4"
+											>
+												<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>
-								<span>Clear conversations</span>
-							</button>
-						{/if} -->
+							{:else}
+								<button
+									class=" flex rounded-md py-2 px-3.5 w-full hover:bg-gray-200 dark:hover:bg-gray-800 transition"
+									on:click={() => {
+										showDeleteConfirm = true;
+									}}
+								>
+									<div class=" self-center mr-3">
+										<svg
+											xmlns="http://www.w3.org/2000/svg"
+											viewBox="0 0 16 16"
+											fill="currentColor"
+											class="w-4 h-4"
+										>
+											<path
+												d="M2 3a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3Z"
+											/>
+											<path
+												fill-rule="evenodd"
+												d="M13 6H3v6a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V6ZM5.72 7.47a.75.75 0 0 1 1.06 0L8 8.69l1.22-1.22a.75.75 0 1 1 1.06 1.06L9.06 9.75l1.22 1.22a.75.75 0 1 1-1.06 1.06L8 10.81l-1.22 1.22a.75.75 0 0 1-1.06-1.06l1.22-1.22-1.22-1.22a.75.75 0 0 1 0-1.06Z"
+												clip-rule="evenodd"
+											/>
+										</svg>
+									</div>
+									<div class=" self-center text-sm font-medium">Delete All Chats</div>
+								</button>
+							{/if}
+						</div>
 					</div>
 				{:else if selectedTab === 'auth'}
 					<form