// DocStrange Document Extraction - Frontend JavaScript class DocStrangeApp { constructor() { this.selectedFile = null; this.extractionResults = null; this.initializeApp(); } async initializeApp() { await this.loadSystemInfo(); this.initializeEventListeners(); } async loadSystemInfo() { try { const response = await fetch('/api/system-info'); if (response.ok) { const systemInfo = await response.json(); this.updateProcessingModeOptions(systemInfo); } } catch (error) { console.warn('Could not load system info:', error); } } updateProcessingModeOptions(systemInfo) { // Processing mode is now handled automatically - cloud by default, GPU if available and selected // No UI changes needed as processing mode selection has been removed } initializeEventListeners() { // File input change document.getElementById('fileInput').addEventListener('change', (e) => { this.handleFileSelect(e.target.files[0]); }); // Drag and drop events const uploadArea = document.getElementById('fileUploadArea'); uploadArea.addEventListener('dragover', (e) => { e.preventDefault(); uploadArea.classList.add('dragover'); }); uploadArea.addEventListener('dragleave', (e) => { e.preventDefault(); uploadArea.classList.remove('dragover'); }); uploadArea.addEventListener('drop', (e) => { e.preventDefault(); uploadArea.classList.remove('dragover'); const files = e.dataTransfer.files; if (files.length > 0) { this.handleFileSelect(files[0]); } }); // Click on upload area to trigger file input uploadArea.addEventListener('click', () => { document.getElementById('fileInput').click(); }); // Form submission document.getElementById('uploadForm').addEventListener('submit', (e) => { e.preventDefault(); this.handleFormSubmission(); }); // Tab switching document.querySelectorAll('.tab-btn').forEach(btn => { btn.addEventListener('click', (e) => { this.switchTab(e.target.dataset.tab); }); }); } handleFileSelect(file) { if (!file) return; // Validate file type const allowedTypes = [ '.pdf', '.docx', '.doc', '.xlsx', '.xls', '.csv', '.txt', '.png', '.jpg', '.jpeg', '.tiff', '.bmp', '.ppt', '.pptx', '.html', '.htm' ]; const fileExtension = '.' + file.name.split('.').pop().toLowerCase(); if (!allowedTypes.includes(fileExtension)) { this.showError(`Unsupported file type: ${fileExtension}`); return; } // Validate file size (100MB limit) const maxSize = 100 * 1024 * 1024; // 100MB if (file.size > maxSize) { this.showError('File too large. Maximum size is 100MB.'); return; } this.selectedFile = file; this.displayFileInfo(file); this.enableSubmitButton(); } displayFileInfo(file) { const fileInfo = document.getElementById('fileInfo'); const fileName = document.getElementById('fileName'); const fileSize = document.getElementById('fileSize'); const uploadArea = document.getElementById('fileUploadArea'); fileName.textContent = file.name; fileSize.textContent = this.formatFileSize(file.size); fileInfo.style.display = 'flex'; // Hide the drag and drop area when file is selected uploadArea.style.display = 'none'; } formatFileSize(bytes) { if (bytes === 0) return '0 Bytes'; const k = 1024; const sizes = ['Bytes', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; } removeFile() { this.selectedFile = null; const fileInfo = document.getElementById('fileInfo'); const uploadArea = document.getElementById('fileUploadArea'); fileInfo.style.display = 'none'; // Show the drag and drop area again when file is removed uploadArea.style.display = 'block'; document.getElementById('fileInput').value = ''; this.disableSubmitButton(); this.hideResults(); } enableSubmitButton() { const submitBtn = document.getElementById('submitBtn'); submitBtn.disabled = false; } disableSubmitButton() { const submitBtn = document.getElementById('submitBtn'); submitBtn.disabled = true; } async handleFormSubmission() { if (!this.selectedFile) { this.showError('Please select a file first.'); return; } this.showLoading(); this.hideResults(); try { const formData = new FormData(); formData.append('file', this.selectedFile); // Get selected output format const outputFormat = document.querySelector('input[name="outputFormat"]:checked').value; formData.append('output_format', outputFormat); // Use cloud processing mode by default formData.append('processing_mode', 'cloud'); const response = await fetch('/api/extract', { method: 'POST', body: formData }); const result = await response.json(); if (response.ok && result.success) { this.displayResults(result); } else { const errorMessage = result.error || 'Extraction failed'; // Handle specific GPU errors if (errorMessage.includes('GPU') && errorMessage.includes('not available')) { this.showError('GPU mode is not available. Please install PyTorch with CUDA support or use cloud processing.'); } else { this.showError(errorMessage); } } } catch (error) { console.error('Error during extraction:', error); this.showError('Network error. Please try again.'); } finally { this.hideLoading(); } } displayResults(result) { this.extractionResults = result; // Update metadata document.getElementById('fileType').textContent = result.metadata.file_type.toUpperCase(); document.getElementById('pagesProcessed').textContent = `${result.metadata.pages_processed} pages`; document.getElementById('processingTime').textContent = `${result.metadata.processing_time.toFixed(2)}s`; // Add processing mode to metadata if available if (result.metadata.processing_mode) { const processingModeElement = document.getElementById('processingMode'); if (processingModeElement) { processingModeElement.textContent = result.metadata.processing_mode.toUpperCase(); } } // Display content this.updatePreviewContent(result.content); this.updateRawContent(result.content); // Show results section document.getElementById('resultsSection').style.display = 'block'; // Scroll to results document.getElementById('resultsSection').scrollIntoView({ behavior: 'smooth', block: 'start' }); } updatePreviewContent(content) { const previewContent = document.getElementById('previewContent'); // Format content based on output type const outputFormat = document.querySelector('input[name="outputFormat"]:checked').value; if (outputFormat === 'json' || outputFormat === 'flat-json') { try { const formatted = JSON.stringify(JSON.parse(content), null, 2); previewContent.innerHTML = `
${this.escapeHtml(formatted)}`;
} catch (e) {
previewContent.textContent = content;
}
} else if (outputFormat === 'html') {
previewContent.innerHTML = content;
} else {
previewContent.textContent = content;
}
}
updateRawContent(content) {
const rawContent = document.getElementById('rawContent');
rawContent.textContent = content;
}
escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
switchTab(tabName) {
// Update tab buttons
document.querySelectorAll('.tab-btn').forEach(btn => {
btn.classList.remove('active');
});
document.querySelector(`[data-tab="${tabName}"]`).classList.add('active');
// Update tab content
document.querySelectorAll('.tab-pane').forEach(pane => {
pane.classList.remove('active');
});
document.getElementById(tabName).classList.add('active');
}
showLoading() {
const submitBtn = document.getElementById('submitBtn');
const btnText = submitBtn.querySelector('.btn-text');
const spinner = submitBtn.querySelector('.spinner');
btnText.textContent = 'Processing...';
spinner.style.display = 'block';
submitBtn.disabled = true;
}
hideLoading() {
const submitBtn = document.getElementById('submitBtn');
const btnText = submitBtn.querySelector('.btn-text');
const spinner = submitBtn.querySelector('.spinner');
btnText.textContent = 'Extract Content';
spinner.style.display = 'none';
submitBtn.disabled = false;
}
showError(message) {
// Create error notification
const notification = document.createElement('div');
notification.className = 'error-notification';
notification.innerHTML = `