// Global variables let categories = []; let documents = []; let authToken = null; let currentUser = null; // Initialize app document.addEventListener('DOMContentLoaded', function() { checkAuth(); }); // 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; } // Tab management function showTab(tabName) { // Hide all tabs document.querySelectorAll('.tab-content').forEach(tab => { tab.classList.remove('active'); }); document.querySelectorAll('.tab-button').forEach(btn => { btn.classList.remove('active'); }); // Show selected tab document.getElementById(tabName).classList.add('active'); event.target.classList.add('active'); // Load data for specific tabs if (tabName === 'browse') { loadCategories(); loadAllDocuments(); } } // 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; } }); }); } // Load dashboard stats async function loadStats() { try { const response = await authenticatedFetch('/api/stats'); const stats = await response.json(); const statsHtml = `

${stats.total_categories}

Total Categories

${stats.total_documents}

Documents Archived

35%

Min Confidence

`; document.getElementById('stats').innerHTML = statsHtml; } catch (error) { console.error('Error loading stats:', error); } } // Load categories async function loadCategories() { try { const response = await authenticatedFetch('/api/categories'); const data = await response.json(); categories = data.categories; const buttonsHtml = ` ${categories.map(cat => ` `).join('')} `; document.getElementById('categoryButtons').innerHTML = buttonsHtml; } 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); } } // Display documents function displayDocuments(docs) { const container = document.getElementById('documentsContainer'); if (docs.length === 0) { container.innerHTML = '

No documents found for this category.

'; return; } const docsHtml = docs.map(doc => { const similarityClass = doc.similarity >= 0.7 ? 'similarity-high' : doc.similarity >= 0.5 ? 'similarity-medium' : 'similarity-low'; return `

${doc.original_filename}

Category: ${doc.category}

Confidence: ${(doc.similarity * 100).toFixed(1)}%

Upload Date: ${new Date(doc.upload_date).toLocaleDateString()}

OCR Preview:

${doc.ocr_text.substring(0, 200)}${doc.ocr_text.length > 200 ? '...' : ''}
`; }).join(''); container.innerHTML = `
${docsHtml}
`; } // 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(); } else { showResult(resultDiv, result.detail, 'error'); } } catch (error) { showResult(resultDiv, 'Classification failed: ' + error.message, '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...', 'info'); try { const response = await authenticatedFetch('/api/ocr', { method: 'POST', body: formData }); const result = await response.json(); if (response.ok) { showResult(resultDiv, result.text, 'success'); } else { showResult(resultDiv, 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}
`; }