From 40e884b3ece02c5f696e4c1ace62d7e56f2b9a03 Mon Sep 17 00:00:00 2001 From: Danny Avila Date: Thu, 7 Mar 2024 12:27:42 -0500 Subject: [PATCH] =?UTF-8?q?=F0=9F=96=BC=EF=B8=8F=20fix:=20Clipboard=20File?= =?UTF-8?q?s=20&=20File=20Name=20Issues=20(#2015)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: ensure image handling fetchs image to base64 for multiple images * fix: append file_id's when writing uploaded files * feat: timestamp files uploaded from clipboard * chore: add a different fileid+name separator --- api/server/services/Files/Firebase/images.js | 4 ++-- api/server/services/Files/Local/images.js | 6 +++-- api/server/services/Files/images/encode.js | 23 ++++++++++---------- api/server/services/Files/process.js | 7 +++++- client/src/hooks/Input/useTextarea.ts | 9 +++++++- 5 files changed, 31 insertions(+), 18 deletions(-) diff --git a/api/server/services/Files/Firebase/images.js b/api/server/services/Files/Firebase/images.js index e9c432db39..f06718063c 100644 --- a/api/server/services/Files/Firebase/images.js +++ b/api/server/services/Files/Firebase/images.js @@ -26,7 +26,7 @@ const { logger } = require('~/config'); * - width: The width of the converted image. * - height: The height of the converted image. */ -async function uploadImageToFirebase({ req, file, endpoint, resolution = 'high' }) { +async function uploadImageToFirebase({ req, file, file_id, endpoint, resolution = 'high' }) { const inputFilePath = file.path; const inputBuffer = await fs.promises.readFile(inputFilePath); const { @@ -38,7 +38,7 @@ async function uploadImageToFirebase({ req, file, endpoint, resolution = 'high' const userId = req.user.id; let webPBuffer; - let fileName = path.basename(inputFilePath); + let fileName = `${file_id}__${path.basename(inputFilePath)}`; if (extension.toLowerCase() === '.webp') { webPBuffer = resizedBuffer; } else { diff --git a/api/server/services/Files/Local/images.js b/api/server/services/Files/Local/images.js index 3dbdae840d..4d5b9565f1 100644 --- a/api/server/services/Files/Local/images.js +++ b/api/server/services/Files/Local/images.js @@ -18,6 +18,7 @@ const { updateFile } = require('~/models/File'); * representing the user, and an `app.locals.paths` object with an `imageOutput` path. * @param {Express.Multer.File} params.file - The file object, which is part of the request. The file object should * have a `path` property that points to the location of the uploaded file. + * @param {string} params.file_id - The file ID. * @param {EModelEndpoint} params.endpoint - The params object. * @param {string} [params.resolution='high'] - Optional. The desired resolution for the image resizing. Default is 'high'. * @@ -28,7 +29,7 @@ const { updateFile } = require('~/models/File'); * - width: The width of the converted image. * - height: The height of the converted image. */ -async function uploadLocalImage({ req, file, endpoint, resolution = 'high' }) { +async function uploadLocalImage({ req, file, file_id, endpoint, resolution = 'high' }) { const inputFilePath = file.path; const inputBuffer = await fs.promises.readFile(inputFilePath); const { @@ -45,7 +46,8 @@ async function uploadLocalImage({ req, file, endpoint, resolution = 'high' }) { fs.mkdirSync(userPath, { recursive: true }); } - const newPath = path.join(userPath, path.basename(inputFilePath)); + const fileName = `${file_id}__${path.basename(inputFilePath)}`; + const newPath = path.join(userPath, fileName); if (extension.toLowerCase() === '.webp') { const bytes = Buffer.byteLength(resizedBuffer); diff --git a/api/server/services/Files/images/encode.js b/api/server/services/Files/images/encode.js index 0b9ededfd4..aa152cf75a 100644 --- a/api/server/services/Files/images/encode.js +++ b/api/server/services/Files/images/encode.js @@ -39,25 +39,24 @@ async function encodeAndFormat(req, files, endpoint) { for (let file of files) { const source = file.source ?? FileSources.local; - if (encodingMethods[source]) { - promises.push(encodingMethods[source](req, file)); - continue; + if (!encodingMethods[source]) { + const { prepareImagePayload } = getStrategyFunctions(source); + if (!prepareImagePayload) { + throw new Error(`Encoding function not implemented for ${source}`); + } + + encodingMethods[source] = prepareImagePayload; } - const { prepareImagePayload } = getStrategyFunctions(source); - if (!prepareImagePayload) { - throw new Error(`Encoding function not implemented for ${source}`); - } + const preparePayload = encodingMethods[source]; - encodingMethods[source] = prepareImagePayload; - - /* Google doesn't support passing URLs to payload */ + /* Google & Anthropic don't support passing URLs to payload */ if (source !== FileSources.local && base64Only.has(endpoint)) { - const [_file, imageURL] = await prepareImagePayload(req, file); + const [_file, imageURL] = await preparePayload(req, file); promises.push([_file, await fetchImageToBase64(imageURL)]); continue; } - promises.push(prepareImagePayload(req, file)); + promises.push(preparePayload(req, file)); } const detail = req.body.imageDetail ?? 'auto'; diff --git a/api/server/services/Files/process.js b/api/server/services/Files/process.js index de6c470cfb..6ed2fb3615 100644 --- a/api/server/services/Files/process.js +++ b/api/server/services/Files/process.js @@ -185,7 +185,12 @@ const processImageFile = async ({ req, res, file, metadata }) => { const source = req.app.locals.fileStrategy; const { handleImageUpload } = getStrategyFunctions(source); const { file_id, temp_file_id, endpoint } = metadata; - const { filepath, bytes, width, height } = await handleImageUpload({ req, file, endpoint }); + const { filepath, bytes, width, height } = await handleImageUpload({ + req, + file, + file_id, + endpoint, + }); const result = await createFile( { user: req.user.id, diff --git a/client/src/hooks/Input/useTextarea.ts b/client/src/hooks/Input/useTextarea.ts index 92cfb9fd57..6b4cca25b5 100644 --- a/client/src/hooks/Input/useTextarea.ts +++ b/client/src/hooks/Input/useTextarea.ts @@ -179,7 +179,14 @@ export default function useTextarea({ if (e.clipboardData && e.clipboardData.files.length > 0) { e.preventDefault(); setFilesLoading(true); - handleFiles(e.clipboardData.files); + const timestampedFiles: File[] = []; + for (const file of e.clipboardData.files) { + const newFile = new File([file], `clipboard_${+new Date()}_${file.name}`, { + type: file.type, + }); + timestampedFiles.push(newFile); + } + handleFiles(timestampedFiles); } }, [handleFiles, setFilesLoading, setText],