SaaS_Backend / src /routes /knowledge-base.ts
ChiragPatankar's picture
Upload 33 files
1cf0854 verified
import express from 'express';
import multer from 'multer';
import path from 'path';
import fs from 'fs';
import { database } from '../db/database';
import { AuthenticatedRequest } from '../middleware/auth';
const router = express.Router();
// Configure multer for file uploads
const storage = multer.diskStorage({
destination: (req, file, cb) => {
const uploadDir = process.env.UPLOAD_DIR || './uploads';
if (!fs.existsSync(uploadDir)) {
fs.mkdirSync(uploadDir, { recursive: true });
}
cb(null, uploadDir);
},
filename: (req, file, cb) => {
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
cb(null, file.fieldname + '-' + uniqueSuffix + path.extname(file.originalname));
}
});
const upload = multer({
storage,
limits: {
fileSize: parseInt(process.env.MAX_FILE_SIZE || '10485760') // 10MB default
},
fileFilter: (req, file, cb) => {
const allowedTypes = ['.pdf', '.docx', '.txt', '.md'];
const ext = path.extname(file.originalname).toLowerCase();
if (allowedTypes.includes(ext)) {
cb(null, true);
} else {
cb(new Error('Invalid file type. Only PDF, DOCX, TXT, and MD files are allowed.'));
}
}
});
// Get knowledge base documents
router.get('/', async (req: AuthenticatedRequest, res) => {
try {
const { tenantId } = req.user!;
const documents = await database.query(
'SELECT id, name, type, source, status, size, created_at, updated_at FROM knowledge_base WHERE tenant_id = ? ORDER BY created_at DESC',
[tenantId]
);
res.json({ documents });
} catch (error) {
console.error('Get knowledge base error:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
// Upload document
router.post('/upload', upload.single('document'), async (req: AuthenticatedRequest, res) => {
try {
const { tenantId } = req.user!;
if (!req.file) {
return res.status(400).json({ error: 'No file uploaded' });
}
const { originalname, filename, size, mimetype } = req.file;
const fileType = path.extname(originalname).toLowerCase().substring(1);
// Save to database
const result = await database.run(
'INSERT INTO knowledge_base (tenant_id, name, type, source, status, size, metadata) VALUES (?, ?, ?, ?, ?, ?, ?)',
[
tenantId,
originalname,
fileType,
filename,
'processing',
size,
JSON.stringify({ mimetype, uploadedAt: new Date().toISOString() })
]
);
// Log analytics event
await database.run(
'INSERT INTO analytics_events (tenant_id, event_type, event_data) VALUES (?, ?, ?)',
[tenantId, 'document_uploaded', JSON.stringify({
documentId: result.lastID,
type: fileType,
size
})]
);
res.status(201).json({
id: result.lastID,
name: originalname,
type: fileType,
status: 'processing',
message: 'Document uploaded successfully'
});
} catch (error) {
console.error('Upload document error:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
// Add website URL
router.post('/url', async (req: AuthenticatedRequest, res) => {
try {
const { tenantId } = req.user!;
const { url, name } = req.body;
if (!url) {
return res.status(400).json({ error: 'URL is required' });
}
// Basic URL validation
try {
new URL(url);
} catch {
return res.status(400).json({ error: 'Invalid URL format' });
}
const displayName = name || new URL(url).hostname;
// Save to database
const result = await database.run(
'INSERT INTO knowledge_base (tenant_id, name, type, source, status, metadata) VALUES (?, ?, ?, ?, ?, ?)',
[
tenantId,
displayName,
'website',
url,
'processing',
JSON.stringify({ addedAt: new Date().toISOString() })
]
);
// Log analytics event
await database.run(
'INSERT INTO analytics_events (tenant_id, event_type, event_data) VALUES (?, ?, ?)',
[tenantId, 'website_added', JSON.stringify({
documentId: result.lastID,
url
})]
);
res.status(201).json({
id: result.lastID,
name: displayName,
type: 'website',
source: url,
status: 'processing',
message: 'Website added successfully'
});
} catch (error) {
console.error('Add URL error:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
// Delete document
router.delete('/:documentId', async (req: AuthenticatedRequest, res) => {
try {
const { tenantId } = req.user!;
const { documentId } = req.params;
// Get document info
const document = await database.get(
'SELECT * FROM knowledge_base WHERE id = ? AND tenant_id = ?',
[documentId, tenantId]
);
if (!document) {
return res.status(404).json({ error: 'Document not found' });
}
// Delete file if it's a uploaded document
if (document.type !== 'website') {
const filePath = path.join(process.env.UPLOAD_DIR || './uploads', document.source);
if (fs.existsSync(filePath)) {
fs.unlinkSync(filePath);
}
}
// Delete from database
await database.run(
'DELETE FROM knowledge_base WHERE id = ? AND tenant_id = ?',
[documentId, tenantId]
);
// Log analytics event
await database.run(
'INSERT INTO analytics_events (tenant_id, event_type, event_data) VALUES (?, ?, ?)',
[tenantId, 'document_deleted', JSON.stringify({
documentId,
name: document.name,
type: document.type
})]
);
res.json({ message: 'Document deleted successfully' });
} catch (error) {
console.error('Delete document error:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
// Update document status (for processing updates)
router.put('/:documentId/status', async (req: AuthenticatedRequest, res) => {
try {
const { tenantId } = req.user!;
const { documentId } = req.params;
const { status } = req.body;
if (!['processing', 'active', 'error'].includes(status)) {
return res.status(400).json({ error: 'Invalid status' });
}
await database.run(
'UPDATE knowledge_base SET status = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ? AND tenant_id = ?',
[status, documentId, tenantId]
);
res.json({ message: 'Document status updated successfully' });
} catch (error) {
console.error('Update document status error:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
// Get document by ID
router.get('/:documentId', async (req: AuthenticatedRequest, res) => {
try {
const { tenantId } = req.user!;
const { documentId } = req.params;
const document = await database.get(
'SELECT * FROM knowledge_base WHERE id = ? AND tenant_id = ?',
[documentId, tenantId]
);
if (!document) {
return res.status(404).json({ error: 'Document not found' });
}
res.json({
...document,
metadata: JSON.parse(document.metadata || '{}')
});
} catch (error) {
console.error('Get document error:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
export default router;