main #11

Merged
mstoeck3 merged 66 commits from main into forensic-ai 2025-08-11 12:02:56 +00:00
2 changed files with 41 additions and 17 deletions
Showing only changes of commit 3f9d1860aa - Show all commits

View File

@ -142,6 +142,7 @@ WantedBy=multi-user.target
server { server {
listen 80; listen 80;
server_name forensic-pathways.yourdomain.com; server_name forensic-pathways.yourdomain.com;
client_max_body_size 50M; # Important for uploads
location / { location / {
proxy_pass http://localhost:4321; proxy_pass http://localhost:4321;

View File

@ -310,6 +310,13 @@ class KnowledgebaseForm {
private handleFiles(files: File[]) { private handleFiles(files: File[]) {
files.forEach(file => { files.forEach(file => {
// Client-side validation before upload
const validation = this.validateFileBeforeUpload(file);
if (!validation.valid) {
this.showMessage('error', `Cannot upload ${file.name}: ${validation.error}`);
return;
}
const fileId = Date.now() + '-' + Math.random().toString(36).substr(2, 9); const fileId = Date.now() + '-' + Math.random().toString(36).substr(2, 9);
const newFile: UploadedFile = { const newFile: UploadedFile = {
id: fileId, id: fileId,
@ -323,6 +330,38 @@ class KnowledgebaseForm {
this.renderFileList(); this.renderFileList();
} }
private validateFileBeforeUpload(file: File): { valid: boolean; error?: string } {
const maxSizeBytes = 50 * 1024 * 1024; // 50MB
if (file.size > maxSizeBytes) {
const sizeMB = (file.size / 1024 / 1024).toFixed(1);
const maxMB = (maxSizeBytes / 1024 / 1024).toFixed(0);
return {
valid: false,
error: `File too large (${sizeMB}MB). Maximum size: ${maxMB}MB`
};
}
// Check file type
const allowedExtensions = [
'.pdf', '.doc', '.docx', '.txt', '.md', '.markdown', '.csv', '.json',
'.xml', '.html', '.rtf', '.yaml', '.yml', '.zip', '.tar', '.gz',
'.rar', '.7z', '.png', '.jpg', '.jpeg', '.gif', '.webp', '.svg',
'.mp4', '.webm', '.mov', '.avi'
];
const fileName = file.name.toLowerCase();
const hasValidExtension = allowedExtensions.some(ext => fileName.endsWith(ext));
if (!hasValidExtension) {
return {
valid: false,
error: `File type not allowed. Allowed: ${allowedExtensions.join(', ')}`
};
}
return { valid: true };
}
private async uploadFile(fileId: string) { private async uploadFile(fileId: string) {
const fileItem = this.uploadedFiles.find(f => f.id === fileId); const fileItem = this.uploadedFiles.find(f => f.id === fileId);
if (!fileItem) { if (!fileItem) {
@ -345,22 +384,17 @@ class KnowledgebaseForm {
}); });
console.log('[UPLOAD] Response status:', response.status); console.log('[UPLOAD] Response status:', response.status);
console.log('[UPLOAD] Response headers:', Object.fromEntries(response.headers.entries()));
// FIXED: Read the response body only once
let responseData: any;
let responseText: string; let responseText: string;
let responseData: any;
try { try {
// Try to read as text first (works for both JSON and plain text)
responseText = await response.text(); responseText = await response.text();
console.log('[UPLOAD] Raw response:', responseText.substring(0, 200)); console.log('[UPLOAD] Raw response:', responseText.substring(0, 200));
// Then try to parse as JSON
try { try {
responseData = JSON.parse(responseText); responseData = JSON.parse(responseText);
} catch (parseError) { } catch (parseError) {
// If JSON parsing fails, treat as plain text
responseData = { error: responseText }; responseData = { error: responseText };
} }
} catch (readError) { } catch (readError) {
@ -377,22 +411,11 @@ class KnowledgebaseForm {
this.showMessage('success', `Successfully uploaded ${fileItem.name}`); this.showMessage('success', `Successfully uploaded ${fileItem.name}`);
} else { } else {
// Enhanced error handling with single response read
let errorMessage = `Upload failed with status ${response.status}`;
if (responseData && responseData.error) {
errorMessage = responseData.error;
} else if (responseText) {
errorMessage += ` (${responseText.substring(0, 100)})`;
}
// Log additional details if available
if (responseData && responseData.details) { if (responseData && responseData.details) {
console.error('[UPLOAD] Error details:', responseData.details); console.error('[UPLOAD] Error details:', responseData.details);
errorMessage += ` (Details: ${responseData.details.join(', ')})`;
} }
throw new Error(errorMessage);
} }
} catch (error) { } catch (error) {
console.error('[UPLOAD] Upload error for', fileItem.name, ':', error); console.error('[UPLOAD] Upload error for', fileItem.name, ':', error);