Skip to content

Commit fe45d0f

Browse files
authored
fix(file-upload): upload presigned url to kb for file upload instead of the whole file, circumvents 4.5MB serverless func limit (#491)
1 parent 8fe5bb9 commit fe45d0f

File tree

1 file changed

+73
-25
lines changed
  • apps/sim/app/w/knowledge/components/create-modal/components/create-form

1 file changed

+73
-25
lines changed

apps/sim/app/w/knowledge/components/create-modal/components/create-form/create-form.tsx

Lines changed: 73 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { useKnowledgeStore } from '@/stores/knowledge/store'
1717

1818
const logger = createLogger('CreateForm')
1919

20-
const MAX_FILE_SIZE = 50 * 1024 * 1024 // 50MB
20+
const MAX_FILE_SIZE = 100 * 1024 * 1024 // 100MB
2121
const ACCEPTED_FILE_TYPES = [
2222
'application/pdf',
2323
'application/msword',
@@ -107,7 +107,7 @@ export function CreateForm({ onClose, onKnowledgeBaseCreated }: CreateFormProps)
107107
for (const file of Array.from(fileList)) {
108108
// Check file size
109109
if (file.size > MAX_FILE_SIZE) {
110-
setFileError(`File ${file.name} is too large. Maximum size is 50MB.`)
110+
setFileError(`File ${file.name} is too large. Maximum size is 100MB per file.`)
111111
hasError = true
112112
continue
113113
}
@@ -259,29 +259,77 @@ export function CreateForm({ onClose, onKnowledgeBaseCreated }: CreateFormProps)
259259
const uploadedFiles: UploadedFile[] = []
260260

261261
for (const file of files) {
262-
const formData = new FormData()
263-
formData.append('file', file)
264-
265-
const uploadResponse = await fetch('/api/files/upload', {
266-
method: 'POST',
267-
body: formData,
268-
})
262+
try {
263+
const presignedResponse = await fetch('/api/files/presigned', {
264+
method: 'POST',
265+
headers: {
266+
'Content-Type': 'application/json',
267+
},
268+
body: JSON.stringify({
269+
fileName: file.name,
270+
contentType: file.type,
271+
fileSize: file.size,
272+
}),
273+
})
269274

270-
if (!uploadResponse.ok) {
271-
const errorData = await uploadResponse.json()
272-
throw new Error(`Failed to upload ${file.name}: ${errorData.error || 'Unknown error'}`)
275+
const presignedData = await presignedResponse.json()
276+
277+
if (presignedResponse.ok && presignedData.directUploadSupported) {
278+
const uploadResponse = await fetch(presignedData.presignedUrl, {
279+
method: 'PUT',
280+
headers: {
281+
'Content-Type': file.type,
282+
},
283+
body: file,
284+
})
285+
286+
if (!uploadResponse.ok) {
287+
throw new Error(
288+
`Direct upload failed: ${uploadResponse.status} ${uploadResponse.statusText}`
289+
)
290+
}
291+
292+
uploadedFiles.push({
293+
filename: file.name,
294+
fileUrl: presignedData.fileInfo.path.startsWith('http')
295+
? presignedData.fileInfo.path
296+
: `${window.location.origin}${presignedData.fileInfo.path}`,
297+
fileSize: file.size,
298+
mimeType: file.type,
299+
fileHash: undefined,
300+
})
301+
} else {
302+
const formData = new FormData()
303+
formData.append('file', file)
304+
305+
const uploadResponse = await fetch('/api/files/upload', {
306+
method: 'POST',
307+
body: formData,
308+
})
309+
310+
if (!uploadResponse.ok) {
311+
const errorData = await uploadResponse.json()
312+
throw new Error(
313+
`Failed to upload ${file.name}: ${errorData.error || 'Unknown error'}`
314+
)
315+
}
316+
317+
const uploadResult = await uploadResponse.json()
318+
uploadedFiles.push({
319+
filename: file.name,
320+
fileUrl: uploadResult.path.startsWith('http')
321+
? uploadResult.path
322+
: `${window.location.origin}${uploadResult.path}`,
323+
fileSize: file.size,
324+
mimeType: file.type,
325+
fileHash: undefined,
326+
})
327+
}
328+
} catch (error) {
329+
throw new Error(
330+
`Failed to upload ${file.name}: ${error instanceof Error ? error.message : 'Unknown error'}`
331+
)
273332
}
274-
275-
const uploadResult = await uploadResponse.json()
276-
uploadedFiles.push({
277-
filename: file.name,
278-
fileUrl: uploadResult.path.startsWith('http')
279-
? uploadResult.path
280-
: `${window.location.origin}${uploadResult.path}`,
281-
fileSize: file.size,
282-
mimeType: file.type,
283-
fileHash: undefined,
284-
})
285333
}
286334

287335
// Start async document processing
@@ -466,7 +514,7 @@ export function CreateForm({ onClose, onKnowledgeBaseCreated }: CreateFormProps)
466514
{isDragging ? 'Drop files here!' : 'Drop files here or click to browse'}
467515
</p>
468516
<p className='text-muted-foreground text-xs'>
469-
Supports PDF, DOC, DOCX, TXT, CSV, XLS, XLSX (max 50MB each)
517+
Supports PDF, DOC, DOCX, TXT, CSV, XLS, XLSX (max 100MB each)
470518
</p>
471519
</div>
472520
</div>
@@ -508,7 +556,7 @@ export function CreateForm({ onClose, onKnowledgeBaseCreated }: CreateFormProps)
508556
: 'Drop more files or click to browse'}
509557
</p>
510558
<p className='text-muted-foreground text-xs'>
511-
PDF, DOC, DOCX, TXT, CSV, XLS, XLSX (max 50MB each)
559+
PDF, DOC, DOCX, TXT, CSV, XLS, XLSX (max 100MB each)
512560
</p>
513561
</div>
514562
</div>

0 commit comments

Comments
 (0)