瀏覽代碼

feat: documents backend integration

Timothy J. Baek 1 年之前
父節點
當前提交
eddb6fc7b7

+ 3 - 2
backend/apps/web/models/documents.py

@@ -105,9 +105,10 @@ class DocumentsTable:
             ).where(Document.name == name)
             query.execute()
 
-            doc = Document.get(Document.name == name)
+            doc = Document.get(Document.name == form_data.name)
             return DocumentModel(**model_to_dict(doc))
-        except:
+        except Exception as e:
+            print(e)
             return None
 
     def delete_doc_by_name(self, name: str) -> bool:

+ 2 - 2
backend/apps/web/routers/documents.py

@@ -97,8 +97,8 @@ async def update_doc_by_name(
         return doc
     else:
         raise HTTPException(
-            status_code=status.HTTP_401_UNAUTHORIZED,
-            detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
+            status_code=status.HTTP_400_BAD_REQUEST,
+            detail=ERROR_MESSAGES.NAME_TAG_TAKEN,
         )
 
 

+ 1 - 0
backend/constants.py

@@ -18,6 +18,7 @@ class ERROR_MESSAGES(str, Enum):
         "Uh-oh! This username is already registered. Please choose another username."
     )
     COMMAND_TAKEN = "Uh-oh! This command is already registered. Please choose another command string."
+    NAME_TAG_TAKEN = "Uh-oh! This name tag is already registered. Please choose another name tag string."
     INVALID_TOKEN = (
         "Your session has expired or the token is invalid. Please sign in again."
     )

+ 1 - 1
src/lib/apis/documents/index.ts

@@ -111,7 +111,7 @@ type DocUpdateForm = {
 export const updateDocByName = async (token: string, name: string, form: DocUpdateForm) => {
 	let error = null;
 
-	const res = await fetch(`${WEBUI_API_BASE_URL}/prompts/name/${name}/update`, {
+	const res = await fetch(`${WEBUI_API_BASE_URL}/documents/name/${name}/update`, {
 		method: 'POST',
 		headers: {
 			Accept: 'application/json',

+ 151 - 0
src/lib/components/documents/EditDocModal.svelte

@@ -0,0 +1,151 @@
+<script lang="ts">
+	import toast from 'svelte-french-toast';
+	import dayjs from 'dayjs';
+	import { onMount } from 'svelte';
+
+	import { getDocs, updateDocByName } from '$lib/apis/documents';
+	import Modal from '../common/Modal.svelte';
+	import { documents } from '$lib/stores';
+
+	export let show = false;
+	export let selectedDoc;
+
+	let doc = {
+		name: '',
+		title: ''
+	};
+
+	const submitHandler = async () => {
+		const res = await updateDocByName(localStorage.token, selectedDoc.name, {
+			title: doc.title,
+			name: doc.name
+		}).catch((error) => {
+			toast.error(error);
+		});
+
+		if (res) {
+			show = false;
+
+			documents.set(await getDocs(localStorage.token));
+		}
+	};
+
+	onMount(() => {
+		if (selectedDoc) {
+			doc = JSON.parse(JSON.stringify(selectedDoc));
+		}
+	});
+</script>
+
+<Modal size="sm" bind:show>
+	<div>
+		<div class=" flex justify-between dark:text-gray-300 px-5 py-4">
+			<div class=" text-lg font-medium self-center">Edit Doc</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>
+		<hr class=" dark:border-gray-800" />
+
+		<div class="flex flex-col md:flex-row w-full p-5 md:space-x-4 dark:text-gray-200">
+			<div class=" flex flex-col w-full sm:flex-row sm:justify-center sm:space-x-6">
+				<form
+					class="flex flex-col w-full"
+					on:submit|preventDefault={() => {
+						submitHandler();
+					}}
+				>
+					<div class=" flex flex-col space-y-1.5">
+						<div class="flex flex-col w-full">
+							<div class=" mb-1 text-xs text-gray-500">Name Tag</div>
+
+							<div class="flex flex-1">
+								<div
+									class="bg-gray-200 dark:bg-gray-600 font-bold px-3 py-1 border border-r-0 dark:border-gray-600 rounded-l-lg"
+								>
+									#
+								</div>
+								<input
+									class="w-full rounded-r-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-800 disabled:text-gray-500 dark:disabled:text-gray-500 outline-none"
+									type="text"
+									bind:value={doc.name}
+									autocomplete="off"
+									required
+								/>
+							</div>
+
+							<!-- <div class="flex-1">
+								<input
+									class="w-full rounded py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-800 disabled:text-gray-500 dark:disabled:text-gray-500 outline-none"
+									type="text"
+									bind:value={doc.name}
+									autocomplete="off"
+									required
+								/>
+							</div> -->
+						</div>
+
+						<div class="flex flex-col w-full">
+							<div class=" mb-1 text-xs text-gray-500">Title</div>
+
+							<div class="flex-1">
+								<input
+									class="w-full rounded py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-800 outline-none"
+									type="text"
+									bind:value={doc.title}
+									autocomplete="off"
+									required
+								/>
+							</div>
+						</div>
+					</div>
+
+					<div class="flex justify-end pt-3 text-sm font-medium">
+						<button
+							class=" px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-gray-100 transition rounded"
+							type="submit"
+						>
+							Save
+						</button>
+					</div>
+				</form>
+			</div>
+		</div>
+	</div>
+</Modal>
+
+<style>
+	input::-webkit-outer-spin-button,
+	input::-webkit-inner-spin-button {
+		/* display: none; <- Crashes Chrome on hover */
+		-webkit-appearance: none;
+		margin: 0; /* <-- Apparently some margin are still there even though it's hidden */
+	}
+
+	.tabs::-webkit-scrollbar {
+		display: none; /* for Chrome, Safari and Opera */
+	}
+
+	.tabs {
+		-ms-overflow-style: none; /* IE and Edge */
+		scrollbar-width: none; /* Firefox */
+	}
+
+	input[type='number'] {
+		-moz-appearance: textfield; /* Firefox */
+	}
+</style>

+ 16 - 4
src/routes/(app)/documents/+page.svelte

@@ -11,11 +11,16 @@
 	import { uploadDocToVectorDB } from '$lib/apis/rag';
 	import { transformFileName } from '$lib/utils';
 
+	import EditDocModal from '$lib/components/documents/EditDocModal.svelte';
+
 	let importFiles = '';
 
 	let inputFiles = '';
 	let query = '';
 
+	let showEditDocModal = false;
+	let selectedDoc;
+
 	let dragged = false;
 
 	const deleteDoc = async (name) => {
@@ -70,6 +75,10 @@
 	};
 </script>
 
+{#key selectedDoc}
+	<EditDocModal bind:show={showEditDocModal} {selectedDoc} />
+{/key}
+
 <div class="min-h-screen w-full flex justify-center dark:text-white">
 	<div class=" py-2.5 flex flex-col justify-between w-full">
 		<div class="max-w-2xl mx-auto w-full px-3 md:px-0 my-10">
@@ -156,7 +165,7 @@
 						<div class="text-center dark:text-white text-2xl font-semibold z-50">Add Files</div>
 
 						<div class=" mt-2 text-center text-sm dark:text-gray-200 w-full">
-							Drop any files here to add to the conversation
+							Drop any files here to add to my documents
 						</div>
 					</div>
 				</div>
@@ -232,10 +241,13 @@
 						</div>
 					</div>
 					<div class="flex flex-row space-x-1 self-center">
-						<a
+						<button
 							class="self-center w-fit text-sm px-2 py-2 border dark:border-gray-600 rounded-xl"
 							type="button"
-							href={`/prompts/edit?command=${encodeURIComponent(doc.name)}`}
+							on:click={async () => {
+								showEditDocModal = !showEditDocModal;
+								selectedDoc = doc;
+							}}
 						>
 							<svg
 								xmlns="http://www.w3.org/2000/svg"
@@ -251,7 +263,7 @@
 									d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L6.832 19.82a4.5 4.5 0 01-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 011.13-1.897L16.863 4.487zm0 0L19.5 7.125"
 								/>
 							</svg>
-						</a>
+						</button>
 
 						<!-- <button
 									class="self-center w-fit text-sm px-2 py-2 border dark:border-gray-600 rounded-xl"