// Global variables let categories = []; let documents = []; let authToken = null; let currentUser = null; let currentView = 'list'; // Initialize app document.addEventListener('DOMContentLoaded', function() { checkAuth(); setupSidebar(); }); // Sidebar functionality function setupSidebar() { const sidebarToggle = document.getElementById('sidebarToggle'); const sidebar = document.getElementById('sidebar'); const mainContent = document.querySelector('.main-content'); if (sidebarToggle) { sidebarToggle.addEventListener('click', function() { sidebar.classList.toggle('collapsed'); mainContent.classList.toggle('sidebar-collapsed'); }); } // Auto-collapse on mobile if (window.innerWidth <= 768) { sidebar.classList.add('collapsed'); mainContent.classList.add('sidebar-collapsed'); } } // Authentication functions function checkAuth() { authToken = localStorage.getItem('authToken'); currentUser = localStorage.getItem('currentUser'); if (authToken && currentUser) { showMainApp(); document.getElementById('welcomeUser').textContent = `Welcome, ${currentUser}`; loadStats(); loadCategories(); setupFileUploads(); } else { showLoginModal(); } } function showLoginModal() { document.getElementById('loginModal').style.display = 'flex'; document.getElementById('mainApp').style.display = 'none'; } function showMainApp() { document.getElementById('loginModal').style.display = 'none'; document.getElementById('mainApp').style.display = 'block'; } function logout() { localStorage.removeItem('authToken'); localStorage.removeItem('currentUser'); authToken = null; currentUser = null; showLoginModal(); } // Login form handler document.getElementById('loginForm').addEventListener('submit', async (e) => { e.preventDefault(); const username = document.getElementById('username').value; const password = document.getElementById('password').value; const resultDiv = document.getElementById('loginResult'); const formData = new FormData(); formData.append('username', username); formData.append('password', password); try { const response = await fetch('/api/login', { method: 'POST', body: formData }); const result = await response.json(); if (response.ok) { authToken = result.access_token; currentUser = result.username; localStorage.setItem('authToken', authToken); localStorage.setItem('currentUser', currentUser); showMainApp(); document.getElementById('welcomeUser').textContent = `Welcome, ${currentUser}`; loadStats(); loadCategories(); setupFileUploads(); } else { showResult(resultDiv, result.detail, 'error'); } } catch (error) { showResult(resultDiv, 'Login failed: ' + error.message, 'error'); } }); // API request with authentication async function authenticatedFetch(url, options = {}) { if (!authToken) { throw new Error('No authentication token'); } const defaultOptions = { headers: { 'Authorization': `Bearer ${authToken}`, ...options.headers } }; const response = await fetch(url, { ...options, ...defaultOptions }); if (response.status === 401) { logout(); throw new Error('Authentication failed'); } return response; } // Enhanced tab management with sidebar highlighting function showTab(tabName) { // Hide all tabs document.querySelectorAll('.tab-content').forEach(tab => { tab.classList.remove('active'); }); // Remove active class from all sidebar links document.querySelectorAll('.sidebar-nav .nav-link').forEach(link => { link.classList.remove('active'); }); // Show selected tab document.getElementById(tabName).classList.add('active'); // Highlight active sidebar link const activeLink = document.querySelector(`[onclick="showTab('${tabName}')"]`); if (activeLink) { activeLink.classList.add('active'); } // Load data for specific tabs if (tabName === 'browse') { loadCategories(); loadAllDocuments(); } else if (tabName === 'dashboard') { loadStats(); loadRecentActivity(); createCategoryChart(); } } // Setup file upload drag & drop function setupFileUploads() { const uploads = [ { div: 'categoryUpload', input: 'categoryFile' }, { div: 'classifyUpload', input: 'classifyFile' }, { div: 'ocrUpload', input: 'ocrFile' } ]; uploads.forEach(upload => { const uploadDiv = document.getElementById(upload.div); const fileInput = document.getElementById(upload.input); uploadDiv.addEventListener('click', () => fileInput.click()); uploadDiv.addEventListener('dragover', (e) => { e.preventDefault(); uploadDiv.classList.add('dragover'); }); uploadDiv.addEventListener('dragleave', () => { uploadDiv.classList.remove('dragover'); }); uploadDiv.addEventListener('drop', (e) => { e.preventDefault(); uploadDiv.classList.remove('dragover'); const files = e.dataTransfer.files; if (files.length > 0) { fileInput.files = files; uploadDiv.querySelector('p').textContent = files[0].name; } }); fileInput.addEventListener('change', () => { if (fileInput.files.length > 0) { uploadDiv.querySelector('p').textContent = fileInput.files[0].name; } }); }); } // Enhanced stats loading with sidebar display async function loadStats() { try { const response = await authenticatedFetch('/api/stats'); const stats = await response.json(); // Dashboard stats const dashboardStatsHtml = `

${stats.total_categories}

Total Categories

${stats.total_documents}

Documents Archived

35%

Min Confidence

`; // Sidebar stats const sidebarStatsHtml = ` `; document.getElementById('dashboardStats').innerHTML = dashboardStatsHtml; document.getElementById('sidebarStats').innerHTML = sidebarStatsHtml; } catch (error) { console.error('Error loading stats:', error); } } // Enhanced categories loading with sidebar display async function loadCategories() { try { const response = await authenticatedFetch('/api/categories'); const data = await response.json(); categories = data.categories; // Main category buttons const buttonsHtml = ` ${categories.map(cat => ` `).join('')} `; // Sidebar categories const sidebarCategoriesHtml = categories.map(cat => ` `).join(''); document.getElementById('categoryButtons').innerHTML = buttonsHtml; document.getElementById('sidebarCategories').innerHTML = sidebarCategoriesHtml; } catch (error) { console.error('Error loading categories:', error); } } // Load all documents async function loadAllDocuments() { try { const response = await authenticatedFetch('/api/documents'); const data = await response.json(); documents = data.documents; displayDocuments(documents); } catch (error) { console.error('Error loading documents:', error); } } // Filter documents by category async function filterDocuments(category) { // Update active button document.querySelectorAll('.category-btn').forEach(btn => { btn.classList.remove('active'); }); event.target.classList.add('active'); try { let filteredDocs; if (category === 'all') { const response = await authenticatedFetch('/api/documents'); const data = await response.json(); filteredDocs = data.documents; } else { const response = await authenticatedFetch(`/api/documents/${category}`); const data = await response.json(); filteredDocs = data.documents; } displayDocuments(filteredDocs); } catch (error) { console.error('Error filtering documents:', error); } } // Delete document async function deleteDocument(documentId, filename) { if (!confirm(`Are you sure you want to delete "${filename}"? This action cannot be undone.`)) { return; } try { const response = await authenticatedFetch(`/api/documents/${documentId}`, { method: 'DELETE' }); const result = await response.json(); if (response.ok) { // Refresh the current view loadAllDocuments(); loadStats(); loadCategories(); alert('Document deleted successfully'); } else { alert('Failed to delete document: ' + result.detail); } } catch (error) { alert('Error deleting document: ' + error.message); } } // Enhanced document display with image preview function displayDocuments(docs) { const container = document.getElementById('documentsContainer'); if (docs.length === 0) { container.innerHTML = `

No documents found

Upload some documents to get started

`; return; } const docsHtml = docs.map(doc => { const similarityClass = doc.similarity >= 0.7 ? 'similarity-high' : doc.similarity >= 0.5 ? 'similarity-medium' : 'similarity-low'; const confidenceText = doc.similarity >= 0.7 ? 'High' : doc.similarity >= 0.5 ? 'Medium' : 'Low'; return `
${doc.original_filename}
${doc.original_filename}
${doc.category}
Confidence: ${(doc.similarity * 100).toFixed(1)}% ${confidenceText}
${new Date(doc.upload_date).toLocaleDateString()}
`; }).join(''); container.innerHTML = `
${docsHtml}
`; } // Document preview functionality function showDocumentPreview(documentId, filename) { const modal = new bootstrap.Modal(document.getElementById('documentModal')); const preview = document.getElementById('documentPreview'); const details = document.getElementById('documentDetails'); preview.src = `/api/document-preview/${documentId}`; details.innerHTML = `
${filename}
`; modal.show(); } // View toggle functionality function toggleView(viewType) { currentView = viewType; // Update button states document.querySelectorAll('.btn-group .btn').forEach(btn => { btn.classList.remove('active'); }); event.target.classList.add('active'); // Reload documents with new view loadAllDocuments(); } // Create category distribution chart function createCategoryChart() { const ctx = document.getElementById('categoryChart'); if (!ctx) return; // Sample data - you can modify this to use real data const data = { labels: categories.slice(0, 5), // Show top 5 categories datasets: [{ label: 'Documents', data: categories.slice(0, 5).map(() => Math.floor(Math.random() * 20) + 1), backgroundColor: [ 'rgba(13, 110, 253, 0.8)', 'rgba(25, 135, 84, 0.8)', 'rgba(255, 193, 7, 0.8)', 'rgba(220, 53, 69, 0.8)', 'rgba(13, 202, 240, 0.8)' ], borderColor: [ 'rgb(13, 110, 253)', 'rgb(25, 135, 84)', 'rgb(255, 193, 7)', 'rgb(220, 53, 69)', 'rgb(13, 202, 240)' ], borderWidth: 2 }] }; new Chart(ctx, { type: 'doughnut', data: data, options: { responsive: true, plugins: { legend: { position: 'bottom', } } } }); } // Load recent activity function loadRecentActivity() { const recentActivity = document.getElementById('recentActivity'); // Sample recent activity - you can modify this to use real data const activities = [ { action: 'Document classified', item: 'passport.jpg', time: '2 min ago' }, { action: 'Category added', item: 'driver_license', time: '1 hour ago' }, { action: 'Document uploaded', item: 'certificate.pdf', time: '3 hours ago' } ]; const activityHtml = activities.map(activity => `
${activity.action}
${activity.item}
${activity.time}
`).join(''); recentActivity.innerHTML = activityHtml; } // Form submissions document.getElementById('uploadForm').addEventListener('submit', async (e) => { e.preventDefault(); const fileInput = document.getElementById('categoryFile'); const labelInput = document.getElementById('categoryLabel'); const resultDiv = document.getElementById('uploadResult'); if (!fileInput.files[0] || !labelInput.value.trim()) { showResult(resultDiv, 'Please select a file and enter a label.', 'error'); return; } const formData = new FormData(); formData.append('file', fileInput.files[0]); formData.append('label', labelInput.value.trim()); showResult(resultDiv, '
Uploading...', 'info'); try { const response = await authenticatedFetch('/api/upload-category', { method: 'POST', body: formData }); const result = await response.json(); if (response.ok) { showResult(resultDiv, result.message, 'success'); labelInput.value = ''; fileInput.value = ''; document.querySelector('#categoryUpload p').textContent = 'Click to select or drag & drop files here'; loadStats(); loadCategories(); } else { showResult(resultDiv, result.detail, 'error'); } } catch (error) { showResult(resultDiv, 'Upload failed: ' + error.message, 'error'); } }); document.getElementById('classifyForm').addEventListener('submit', async (e) => { e.preventDefault(); const fileInput = document.getElementById('classifyFile'); const resultDiv = document.getElementById('classifyResult'); if (!fileInput.files[0]) { showResult(resultDiv, 'Please select a file to classify.', 'error'); return; } const formData = new FormData(); formData.append('file', fileInput.files[0]); showResult(resultDiv, '
Classifying...', 'info'); try { const response = await authenticatedFetch('/api/classify-document', { method: 'POST', body: formData }); const result = await response.json(); if (response.ok) { const confidenceText = result.confidence === 'high' ? 'āœ… High Confidence' : 'āš ļø Low Confidence'; const savedText = result.document_saved ? '\nšŸ“ Document saved to archive' : ''; let matchesText = '\n\nTop matches:\n'; result.matches.forEach(match => { matchesText += `• ${match.category}: ${(match.similarity * 100).toFixed(1)}%\n`; }); showResult(resultDiv, `šŸŽÆ Classification: ${result.category}\n` + `${confidenceText} (${(result.similarity * 100).toFixed(1)}%)${savedText}${matchesText}`, result.confidence === 'high' ? 'success' : 'warning' ); fileInput.value = ''; document.querySelector('#classifyUpload p').textContent = 'Click to select or drag & drop files here'; loadStats(); loadCategories(); } else { // Handle different error types let errorMessage = result.error || result.detail || 'Classification failed'; if (errorMessage.includes('No categories')) { errorMessage = 'āš ļø Please add some document categories first before classifying documents.'; } else if (errorMessage.includes('Failed to process')) { errorMessage = 'āŒ Could not process the uploaded file. Please ensure it\'s a valid image or PDF.'; } else if (errorMessage.includes('JSON serializable')) { errorMessage = 'šŸ”§ Processing error occurred. Please try again.'; } showResult(resultDiv, errorMessage, 'error'); } } catch (error) { console.error('Classification error:', error); showResult(resultDiv, 'āŒ Network error: Please check your connection and try again.', 'error'); } }); document.getElementById('ocrForm').addEventListener('submit', async (e) => { e.preventDefault(); const fileInput = document.getElementById('ocrFile'); const resultDiv = document.getElementById('ocrResult'); if (!fileInput.files[0]) { showResult(resultDiv, 'Please select a file for OCR.', 'error'); return; } const formData = new FormData(); formData.append('file', fileInput.files[0]); showResult(resultDiv, '
Extracting text with advanced OCR...', 'info'); try { const response = await authenticatedFetch('/api/ocr', { method: 'POST', body: formData }); const result = await response.json(); if (response.ok) { const ocrInfo = result.enhanced_features ? `šŸ¤– Processed with ${result.ocr_method} (Enhanced Features: Tables, LaTeX, Watermarks)\n\n` : `šŸ“ Processed with ${result.ocr_method}\n\n`; showResult(resultDiv, ocrInfo + result.text, 'success'); } else { showResult(resultDiv, result.error || result.detail, 'error'); } } catch (error) { showResult(resultDiv, 'OCR failed: ' + error.message, 'error'); } }); // Utility function to show results function showResult(element, message, type) { const className = type === 'success' ? 'result-success' : type === 'error' ? 'result-error' : type === 'warning' ? 'result-warning' : ''; element.innerHTML = `
${message}
`; }