Fix file upload
Browse files- data/knowledgebridge.db +0 -0
- server/document-routes.ts +88 -21
- server/file-upload.ts +16 -2
- server/vite.ts +2 -2
data/knowledgebridge.db
CHANGED
Binary files a/data/knowledgebridge.db and b/data/knowledgebridge.db differ
|
|
server/document-routes.ts
CHANGED
@@ -10,12 +10,73 @@ const router = Router();
|
|
10 |
/**
|
11 |
* Upload documents (multiple files supported)
|
12 |
*/
|
13 |
-
router.post('/upload',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
try {
|
15 |
const files = req.files as Express.Multer.File[];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
const uploadedDocuments = [];
|
17 |
|
18 |
for (const file of files) {
|
|
|
|
|
19 |
// Extract title from filename or use provided title
|
20 |
const title = req.body.title || path.basename(file.originalname, path.extname(file.originalname));
|
21 |
const source = req.body.source || `Uploaded file: ${file.originalname}`;
|
@@ -42,27 +103,33 @@ router.post('/upload', upload.array('files', 10), validateUpload, async (req, re
|
|
42 |
}
|
43 |
|
44 |
// Create document record
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
54 |
mimeType: file.mimetype,
|
55 |
-
|
56 |
-
}
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
}
|
64 |
-
|
65 |
-
uploadedDocuments.push(document);
|
66 |
}
|
67 |
|
68 |
res.status(201).json({
|
|
|
10 |
/**
|
11 |
* Upload documents (multiple files supported)
|
12 |
*/
|
13 |
+
router.post('/upload', (req, res, next) => {
|
14 |
+
upload.array('files', 10)(req, res, (err) => {
|
15 |
+
if (err) {
|
16 |
+
console.error('Multer upload error:', err);
|
17 |
+
|
18 |
+
// Handle specific multer errors
|
19 |
+
if (err.code === 'LIMIT_FILE_SIZE') {
|
20 |
+
return res.status(400).json({
|
21 |
+
success: false,
|
22 |
+
error: 'File too large',
|
23 |
+
message: `File size exceeds the maximum limit of 50MB. File: ${err.field}`
|
24 |
+
});
|
25 |
+
}
|
26 |
+
|
27 |
+
if (err.code === 'LIMIT_FILE_COUNT') {
|
28 |
+
return res.status(400).json({
|
29 |
+
success: false,
|
30 |
+
error: 'Too many files',
|
31 |
+
message: 'Maximum 10 files allowed per upload'
|
32 |
+
});
|
33 |
+
}
|
34 |
+
|
35 |
+
if (err.code === 'LIMIT_UNEXPECTED_FILE') {
|
36 |
+
return res.status(400).json({
|
37 |
+
success: false,
|
38 |
+
error: 'Unexpected file field',
|
39 |
+
message: `Unexpected file field: ${err.field}`
|
40 |
+
});
|
41 |
+
}
|
42 |
+
|
43 |
+
// Handle file type errors
|
44 |
+
if (err.message && err.message.includes('Unsupported file type')) {
|
45 |
+
return res.status(400).json({
|
46 |
+
success: false,
|
47 |
+
error: 'Unsupported file type',
|
48 |
+
message: err.message
|
49 |
+
});
|
50 |
+
}
|
51 |
+
|
52 |
+
// Generic multer error
|
53 |
+
return res.status(400).json({
|
54 |
+
success: false,
|
55 |
+
error: 'File upload error',
|
56 |
+
message: err.message || 'Unknown upload error'
|
57 |
+
});
|
58 |
+
}
|
59 |
+
|
60 |
+
next();
|
61 |
+
});
|
62 |
+
}, validateUpload, async (req, res) => {
|
63 |
try {
|
64 |
const files = req.files as Express.Multer.File[];
|
65 |
+
|
66 |
+
if (!files || files.length === 0) {
|
67 |
+
return res.status(400).json({
|
68 |
+
success: false,
|
69 |
+
error: 'No files received',
|
70 |
+
message: 'No files were received by the server'
|
71 |
+
});
|
72 |
+
}
|
73 |
+
|
74 |
+
console.log(`Processing ${files.length} uploaded files`);
|
75 |
const uploadedDocuments = [];
|
76 |
|
77 |
for (const file of files) {
|
78 |
+
console.log(`Processing file: ${file.originalname}, size: ${file.size} bytes, type: ${file.mimetype}`);
|
79 |
+
|
80 |
// Extract title from filename or use provided title
|
81 |
const title = req.body.title || path.basename(file.originalname, path.extname(file.originalname));
|
82 |
const source = req.body.source || `Uploaded file: ${file.originalname}`;
|
|
|
103 |
}
|
104 |
|
105 |
// Create document record
|
106 |
+
try {
|
107 |
+
const document = await storage.createDocument({
|
108 |
+
title,
|
109 |
+
content,
|
110 |
+
source,
|
111 |
+
sourceType,
|
112 |
+
url: null,
|
113 |
+
metadata: {
|
114 |
+
originalName: file.originalname,
|
115 |
+
uploadedAt: new Date().toISOString(),
|
116 |
+
mimeType: file.mimetype,
|
117 |
+
size: file.size
|
118 |
+
},
|
119 |
+
embedding: null,
|
120 |
+
filePath: file.path,
|
121 |
+
fileName: file.originalname,
|
122 |
+
fileSize: file.size,
|
123 |
mimeType: file.mimetype,
|
124 |
+
processingStatus: FileProcessor.requiresOCR(file.mimetype) ? 'pending' : 'completed'
|
125 |
+
} as any);
|
126 |
+
|
127 |
+
console.log(`Successfully created document record for ${file.originalname} with ID ${document.id}`);
|
128 |
+
uploadedDocuments.push(document);
|
129 |
+
} catch (dbError) {
|
130 |
+
console.error(`Failed to create document record for ${file.originalname}:`, dbError);
|
131 |
+
throw new Error(`Database error while saving ${file.originalname}: ${dbError instanceof Error ? dbError.message : 'Unknown database error'}`);
|
132 |
+
}
|
|
|
|
|
133 |
}
|
134 |
|
135 |
res.status(201).json({
|
server/file-upload.ts
CHANGED
@@ -14,10 +14,20 @@ const uploadsDir = process.env.NODE_ENV === 'production'
|
|
14 |
try {
|
15 |
if (!fs.existsSync(uploadsDir)) {
|
16 |
fs.mkdirSync(uploadsDir, { recursive: true });
|
|
|
|
|
|
|
17 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
} catch (error) {
|
19 |
-
console.warn(
|
20 |
-
console.log('File uploads
|
21 |
}
|
22 |
|
23 |
// Configure multer for file uploads
|
@@ -28,13 +38,17 @@ const storage = multer.diskStorage({
|
|
28 |
const dateDir = new Date().toISOString().split('T')[0];
|
29 |
const fullPath = path.join(uploadsDir, dateDir);
|
30 |
|
|
|
|
|
31 |
if (!fs.existsSync(fullPath)) {
|
32 |
fs.mkdirSync(fullPath, { recursive: true });
|
|
|
33 |
}
|
34 |
|
35 |
cb(null, fullPath);
|
36 |
} catch (error) {
|
37 |
console.error('Failed to create upload directory:', error);
|
|
|
38 |
// Fallback to base uploads directory
|
39 |
cb(null, uploadsDir);
|
40 |
}
|
|
|
14 |
try {
|
15 |
if (!fs.existsSync(uploadsDir)) {
|
16 |
fs.mkdirSync(uploadsDir, { recursive: true });
|
17 |
+
console.log(`β
Created uploads directory: ${uploadsDir}`);
|
18 |
+
} else {
|
19 |
+
console.log(`β
Uploads directory exists: ${uploadsDir}`);
|
20 |
}
|
21 |
+
|
22 |
+
// Test write permissions
|
23 |
+
const testFile = path.join(uploadsDir, 'test-permissions.txt');
|
24 |
+
fs.writeFileSync(testFile, 'test');
|
25 |
+
fs.unlinkSync(testFile);
|
26 |
+
console.log(`β
Upload directory is writable: ${uploadsDir}`);
|
27 |
+
|
28 |
} catch (error) {
|
29 |
+
console.warn(`β Failed to create or write to uploads directory at ${uploadsDir}:`, error);
|
30 |
+
console.log('File uploads may not work properly');
|
31 |
}
|
32 |
|
33 |
// Configure multer for file uploads
|
|
|
38 |
const dateDir = new Date().toISOString().split('T')[0];
|
39 |
const fullPath = path.join(uploadsDir, dateDir);
|
40 |
|
41 |
+
console.log(`Creating upload destination: ${fullPath} for file: ${file.originalname}`);
|
42 |
+
|
43 |
if (!fs.existsSync(fullPath)) {
|
44 |
fs.mkdirSync(fullPath, { recursive: true });
|
45 |
+
console.log(`Created upload subdirectory: ${fullPath}`);
|
46 |
}
|
47 |
|
48 |
cb(null, fullPath);
|
49 |
} catch (error) {
|
50 |
console.error('Failed to create upload directory:', error);
|
51 |
+
console.log(`Falling back to base directory: ${uploadsDir}`);
|
52 |
// Fallback to base uploads directory
|
53 |
cb(null, uploadsDir);
|
54 |
}
|
server/vite.ts
CHANGED
@@ -35,8 +35,8 @@ export async function setupVite(app: Express, server: Server) {
|
|
35 |
customLogger: {
|
36 |
...viteLogger,
|
37 |
error: (msg, options) => {
|
38 |
-
|
39 |
-
|
40 |
},
|
41 |
},
|
42 |
server: serverOptions,
|
|
|
35 |
customLogger: {
|
36 |
...viteLogger,
|
37 |
error: (msg, options) => {
|
38 |
+
console.warn('Vite error (non-fatal):', msg);
|
39 |
+
// Don't exit on Vite errors - they're often non-critical
|
40 |
},
|
41 |
},
|
42 |
server: serverOptions,
|