Fix: Adding Support for Uploading Multiple Files (#803)

* added support for uploading multiple files at a time.

* optimized multiple file upload to use a batch upload

* allowing files to upload even if there is one unsupported file
This commit is contained in:
Raghav Tirumale 2024-06-12 06:21:35 -04:00 committed by GitHub
parent 6afbd8032e
commit 673d0d367c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -810,7 +810,7 @@ To get started, just start typing below. You can also type / to see a list of co
if (overlayText == null) {
dropzone.classList.add('dragover');
var overlayText = document.createElement("div");
overlayText.innerHTML = "Select a file or drag + drop it here to share it with Khoj";
overlayText.innerHTML = "Select file(s) or drag + drop it here to share it with Khoj";
overlayText.className = "dropzone-overlay";
overlayText.id = "dropzone-overlay";
dropzone.appendChild(overlayText);
@ -818,9 +818,10 @@ To get started, just start typing below. You can also type / to see a list of co
const fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.multiple = true;
fileInput.addEventListener('change', function() {
const selectedFile = fileInput.files[0];
uploadDataForIndexing(selectedFile);
const selectedFiles = fileInput.files;
uploadDataForIndexing(selectedFiles);
});
// Remove overlay text after file input is closed
@ -844,61 +845,80 @@ To get started, just start typing below. You can also type / to see a list of co
fileInput.click();
}
function uploadDataForIndexing(file) {
function uploadDataForIndexing(files) {
var dropzone = document.getElementById('chat-body');
if (!file || (!allowedExtensions.includes(file.type) && !allowedFileEndings.includes(file.name.split('.').pop()))) {
dropzone.classList.remove('dragover');
if (file) {
alert("Sorry, that file type is not yet supported");
}
var badfiles = [];
var goodfiles = [];
var overlayText = document.getElementById("dropzone-overlay");
if (overlayText != null) {
overlayText.remove();
for (let file of files) {
if (!file || (!allowedExtensions.includes(file.type) && !allowedFileEndings.includes(file.name.split('.').pop()))) {
if (file) {
badfiles.push(file.name);
}
} else {
goodfiles.push(file);
}
return;
}
const fileName = file.name;
var fileContents = null;
if (badfiles.length > 0) {
alert("The following files are not supported yet:\n" + badfiles.join('\n'));
}
var reader = new FileReader();
const formData = new FormData();
var overlayText = document.getElementById("dropzone-overlay");
if (overlayText != null) {
// Display loading spinner
var loadingSpinner = document.createElement("div");
overlayText.innerHTML = "Uploading file for indexing";
overlayText.innerHTML = "Uploading file(s) for indexing";
loadingSpinner.className = "spinner";
overlayText.appendChild(loadingSpinner);
}
// Create an array of Promises for file reading
const fileReadPromises = Array.from(goodfiles).map(file => {
return new Promise((resolve, reject) => {
let reader = new FileReader();
reader.onload = function (event) {
fileContents = event.target.result;
let fileContents = event.target.result;
let fileType = file.type;
let fileName = file.name;
if (fileType === "") {
if (fileName.split('.').pop() === "org") {
let fileExtension = fileName.split('.').pop();
if (fileExtension === "org") {
fileType = "text/org";
} else if (fileName.split('.').pop() === "md") {
} else if (fileExtension === "md") {
fileType = "text/markdown";
} else if (fileName.split('.').pop() === "txt") {
} else if (fileExtension === "txt") {
fileType = "text/plain";
} else if (fileName.split('.').pop() === "html") {
} else if (fileExtension === "html") {
fileType = "text/html";
} else if (fileName.split('.').pop() === "pdf") {
} else if (fileExtension === "pdf") {
fileType = "application/pdf";
} else {
// Skip this file if its type is not supported
resolve();
return;
}
}
let fileObj = new Blob([fileContents], { type: fileType });
formData.append("files", fileObj, file.name);
console.log(formData);
resolve();
};
reader.onerror = reject;
reader.readAsArrayBuffer(file);
});
});
fetch("/api/v1/index/update?force=false&client=web", {
// Wait for all files to be read before making the fetch request
Promise.all(fileReadPromises)
.then(() => {
return fetch("/api/v1/index/update?force=false&client=web", {
method: "POST",
body: formData,
});
})
.then((data) => {
console.log(data);
@ -910,8 +930,10 @@ To get started, just start typing below. You can also type / to see a list of co
// Display indexing success message
flashStatusInChatInput("✅ File indexed successfully");
renderAllFiles();
addFileFilterToConversation(fileName);
for (let file of goodfiles) {
addFileFilterToConversation(file.name);
loadFileFiltersFromConversation();
}
})
.catch((error) => {
console.log(error);
@ -923,11 +945,9 @@ To get started, just start typing below. You can also type / to see a list of co
// Display indexing failure message
flashStatusInChatInput("⛔️ Failed to upload file for indexing");
});
};
reader.readAsArrayBuffer(file);
}
function setupDropZone() {
var dropzone = document.getElementById('chat-body');