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

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) { if (overlayText == null) {
dropzone.classList.add('dragover'); dropzone.classList.add('dragover');
var overlayText = document.createElement("div"); 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.className = "dropzone-overlay";
overlayText.id = "dropzone-overlay"; overlayText.id = "dropzone-overlay";
dropzone.appendChild(overlayText); 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'); const fileInput = document.createElement('input');
fileInput.type = 'file'; fileInput.type = 'file';
fileInput.multiple = true;
fileInput.addEventListener('change', function() { fileInput.addEventListener('change', function() {
const selectedFile = fileInput.files[0]; const selectedFiles = fileInput.files;
uploadDataForIndexing(selectedFile); uploadDataForIndexing(selectedFiles);
}); });
// Remove overlay text after file input is closed // 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(); fileInput.click();
} }
function uploadDataForIndexing(file) { function uploadDataForIndexing(files) {
var dropzone = document.getElementById('chat-body'); var dropzone = document.getElementById('chat-body');
var badfiles = [];
if (!file || (!allowedExtensions.includes(file.type) && !allowedFileEndings.includes(file.name.split('.').pop()))) { var goodfiles = [];
dropzone.classList.remove('dragover');
if (file) {
alert("Sorry, that file type is not yet supported");
}
var overlayText = document.getElementById("dropzone-overlay"); 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; if (badfiles.length > 0) {
var fileContents = null; alert("The following files are not supported yet:\n" + badfiles.join('\n'));
}
var reader = new FileReader();
const formData = new FormData(); const formData = new FormData();
var overlayText = document.getElementById("dropzone-overlay"); var overlayText = document.getElementById("dropzone-overlay");
if (overlayText != null) { if (overlayText != null) {
// Display loading spinner // Display loading spinner
var loadingSpinner = document.createElement("div"); var loadingSpinner = document.createElement("div");
overlayText.innerHTML = "Uploading file for indexing"; overlayText.innerHTML = "Uploading file(s) for indexing";
loadingSpinner.className = "spinner"; loadingSpinner.className = "spinner";
overlayText.appendChild(loadingSpinner); 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) { reader.onload = function (event) {
fileContents = event.target.result; let fileContents = event.target.result;
let fileType = file.type; let fileType = file.type;
let fileName = file.name;
if (fileType === "") { if (fileType === "") {
if (fileName.split('.').pop() === "org") { let fileExtension = fileName.split('.').pop();
if (fileExtension === "org") {
fileType = "text/org"; fileType = "text/org";
} else if (fileName.split('.').pop() === "md") { } else if (fileExtension === "md") {
fileType = "text/markdown"; fileType = "text/markdown";
} else if (fileName.split('.').pop() === "txt") { } else if (fileExtension === "txt") {
fileType = "text/plain"; fileType = "text/plain";
} else if (fileName.split('.').pop() === "html") { } else if (fileExtension === "html") {
fileType = "text/html"; fileType = "text/html";
} else if (fileName.split('.').pop() === "pdf") { } else if (fileExtension === "pdf") {
fileType = "application/pdf"; fileType = "application/pdf";
} else {
// Skip this file if its type is not supported
resolve();
return;
} }
} }
let fileObj = new Blob([fileContents], { type: fileType }); let fileObj = new Blob([fileContents], { type: fileType });
formData.append("files", fileObj, file.name); 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", method: "POST",
body: formData, body: formData,
});
}) })
.then((data) => { .then((data) => {
console.log(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 // Display indexing success message
flashStatusInChatInput("✅ File indexed successfully"); flashStatusInChatInput("✅ File indexed successfully");
renderAllFiles(); renderAllFiles();
addFileFilterToConversation(fileName); for (let file of goodfiles) {
addFileFilterToConversation(file.name);
loadFileFiltersFromConversation(); loadFileFiltersFromConversation();
}
}) })
.catch((error) => { .catch((error) => {
console.log(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 // Display indexing failure message
flashStatusInChatInput("⛔️ Failed to upload file for indexing"); flashStatusInChatInput("⛔️ Failed to upload file for indexing");
}); });
};
reader.readAsArrayBuffer(file);
} }
function setupDropZone() { function setupDropZone() {
var dropzone = document.getElementById('chat-body'); var dropzone = document.getElementById('chat-body');