mirror of
				https://github.com/open-webui/open-webui
				synced 2025-06-26 18:26:48 +00:00 
			
		
		
		
	feat: documents backend integration
This commit is contained in:
		
							parent
							
								
									fe997abc6d
								
							
						
					
					
						commit
						eddb6fc7b7
					
				@ -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:
 | 
			
		||||
 | 
			
		||||
@ -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,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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."
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
@ -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
									
								
								src/lib/components/documents/EditDocModal.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								src/lib/components/documents/EditDocModal.svelte
									
									
									
									
									
										Normal file
									
								
							@ -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>
 | 
			
		||||
@ -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"
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user