From dd59f6e6be33865c0c893395b00e2781de75f2e7 Mon Sep 17 00:00:00 2001 From: kalpadhwaryu Date: Mon, 18 Nov 2024 19:25:57 +0530 Subject: [PATCH 01/36] Upload files from frontend to server --- frontend/src/routes/_authenticated/chat.tsx | 115 +++++++++++++++++++- server/ai/context.ts | 14 +-- server/api/chat.ts | 28 ++++- server/api/search.ts | 5 + server/bun.lockb | Bin 191401 -> 191401 bytes server/server.ts | 7 ++ 6 files changed, 158 insertions(+), 11 deletions(-) diff --git a/frontend/src/routes/_authenticated/chat.tsx b/frontend/src/routes/_authenticated/chat.tsx index e0138e13..92c9b0b5 100644 --- a/frontend/src/routes/_authenticated/chat.tsx +++ b/frontend/src/routes/_authenticated/chat.tsx @@ -43,6 +43,8 @@ export const ChatPage = ({ user, workspace }: ChatPageProps) => { : "/_authenticated/chat", }) + const fileInputRef = useRef(null) + const [query, setQuery] = useState("") const [messages, setMessages] = useState( isWithChatId ? data?.messages || [] : [], @@ -67,6 +69,7 @@ export const ChatPage = ({ user, workspace }: ChatPageProps) => { const [userHasScrolled, setUserHasScrolled] = useState(false) const [dots, setDots] = useState("") const [isStreaming, setIsStreaming] = useState(false) + const [stagedFiles, setStagedFiles] = useState([]) useEffect(() => { if (inputRef.current) { @@ -111,6 +114,11 @@ export const ChatPage = ({ user, workspace }: ChatPageProps) => { const handleSend = async () => { if (!query) return // Avoid empty messages + // Upload files if any before + if (stagedFiles.length !== 0) { + await handleFileUpload() + } + // Append the user's message to the chat setMessages((prevMessages) => [ ...prevMessages, @@ -337,6 +345,78 @@ export const ChatPage = ({ user, workspace }: ChatPageProps) => { ) } + + const handleFileSelection = (event) => { + const files = Array.from(event.target!.files) + setStagedFiles((prev) => [...prev, ...files]) + event.target.value = "" // Reset input value to allow re-selecting the same file + } + + function handleFileRemove(index: number) { + setStagedFiles((prev) => prev.filter((_, i) => i !== index)) + } + + const isSupportedFileType = (fileType: string): boolean => { + if (fileType === "application/pdf") { + return true + } else { + return false + } + } + + const handleFileUpload = async () => { + if (stagedFiles.length === 0) { + alert("No files selected for upload.") + return + } + + const formData = new FormData() + // Append each file to the FormData object + Array.from(stagedFiles).forEach((file) => { + // Ignore and remove large and not supported files + // File size check, 20 MB is the limit + const fileSizeInMB = file?.size / (1024 * 1024) + if (fileSizeInMB > 20) { + // todo maybe show toast here + // File is too large + console.error(`Ignored ${file.name} as file is too large`) + return + } else if (!isSupportedFileType(file?.type)) { + // todo file is not supported + console.error(`Ignored ${file.name} as file type is not supported`) + return + } else { + formData.append("files", file) + } + }) + + try { + // todo change this + const response = await fetch("/api/v1/chat/upload", { + method: "POST", + body: formData, + }) + + // const response = await api.chat.upload.$post({ + // body: formData, + // // headers: { + // // "Content-Type": "multipart/form-data", // Important for file uploads + // // }, + // }) + + const result = await response.json() + if (response.ok) { + // addFilesToChat(result.files) // Add uploaded files to chat + setStagedFiles([]) // Clear the staging area + } else { + alert("File upload failed. Please try again.") + } + } catch (error) { + console.error("Error uploading files:", error) + alert("An unexpected error occurred.") + } + } + return (
@@ -397,7 +477,29 @@ export const ChatPage = ({ user, workspace }: ChatPageProps) => { {/* Bottom Bar with Input and Icons */}
{/* Expanding Input Area */} -
+
+
+ {/* File Staging Area */} + {/* todo fix the ui */} + {stagedFiles.length > 0 && ( +
+ {/*

Selected Files:

*/} +
    + {stagedFiles.map((file, index) => ( +
  • + {file.name} + +
  • + ))} +
+
+ )} +