| |
|
|
| 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) { |
| |
| |
| } |
|
|
| initializeEventListeners() { |
| |
| document.getElementById('fileInput').addEventListener('change', (e) => { |
| this.handleFileSelect(e.target.files[0]); |
| }); |
|
|
| |
| 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]); |
| } |
| }); |
|
|
| |
| uploadArea.addEventListener('click', () => { |
| document.getElementById('fileInput').click(); |
| }); |
|
|
| |
| document.getElementById('uploadForm').addEventListener('submit', (e) => { |
| e.preventDefault(); |
| this.handleFormSubmission(); |
| }); |
|
|
| |
| document.querySelectorAll('.tab-btn').forEach(btn => { |
| btn.addEventListener('click', (e) => { |
| this.switchTab(e.target.dataset.tab); |
| }); |
| }); |
| } |
|
|
| handleFileSelect(file) { |
| if (!file) return; |
|
|
| |
| 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; |
| } |
|
|
| |
| const maxSize = 100 * 1024 * 1024; |
| 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'; |
| |
| |
| 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'; |
| |
| 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); |
| |
| |
| const outputFormat = document.querySelector('input[name="outputFormat"]:checked').value; |
| formData.append('output_format', outputFormat); |
|
|
| |
| 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'; |
| |
| |
| 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; |
| |
| |
| 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`; |
|
|
| |
| if (result.metadata.processing_mode) { |
| const processingModeElement = document.getElementById('processingMode'); |
| if (processingModeElement) { |
| processingModeElement.textContent = result.metadata.processing_mode.toUpperCase(); |
| } |
| } |
|
|
| |
| this.updatePreviewContent(result.content); |
| this.updateRawContent(result.content); |
| |
| |
| document.getElementById('resultsSection').style.display = 'block'; |
| |
| |
| document.getElementById('resultsSection').scrollIntoView({ |
| behavior: 'smooth', |
| block: 'start' |
| }); |
| } |
|
|
| updatePreviewContent(content) { |
| const previewContent = document.getElementById('previewContent'); |
| |
| |
| 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 = `<pre class="json-preview">${this.escapeHtml(formatted)}</pre>`; |
| } 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) { |
| |
| document.querySelectorAll('.tab-btn').forEach(btn => { |
| btn.classList.remove('active'); |
| }); |
| document.querySelector(`[data-tab="${tabName}"]`).classList.add('active'); |
|
|
| |
| 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) { |
| |
| const notification = document.createElement('div'); |
| notification.className = 'error-notification'; |
| notification.innerHTML = ` |
| <div class="error-content"> |
| <span class="error-icon">⚠️</span> |
| <span class="error-message">${message}</span> |
| <button class="error-close" onclick="this.parentElement.parentElement.remove()">×</button> |
| </div> |
| `; |
| |
| |
| notification.style.cssText = ` |
| position: fixed; |
| top: 20px; |
| right: 20px; |
| background: #D02B2B; |
| color: white; |
| padding: 16px; |
| border-radius: 8px; |
| box-shadow: 0 4px 12px rgba(0,0,0,0.15); |
| z-index: 1000; |
| max-width: 400px; |
| `; |
| |
| notification.querySelector('.error-content').style.cssText = ` |
| display: flex; |
| align-items: center; |
| gap: 12px; |
| `; |
| |
| notification.querySelector('.error-close').style.cssText = ` |
| background: none; |
| border: none; |
| color: white; |
| font-size: 20px; |
| cursor: pointer; |
| margin-left: auto; |
| `; |
| |
| document.body.appendChild(notification); |
| |
| |
| setTimeout(() => { |
| if (notification.parentElement) { |
| notification.remove(); |
| } |
| }, 5000); |
| } |
|
|
| hideResults() { |
| document.getElementById('resultsSection').style.display = 'none'; |
| } |
| } |
|
|
| |
| function removeFile() { |
| if (window.docStrangeApp) { |
| window.docStrangeApp.removeFile(); |
| } |
| } |
|
|
| function downloadAsText() { |
| if (window.docStrangeApp && window.docStrangeApp.extractionResults) { |
| const content = window.docStrangeApp.extractionResults.content; |
| const fileName = window.docStrangeApp.selectedFile.name; |
| const outputFormat = document.querySelector('input[name="outputFormat"]:checked').value; |
| const extension = outputFormat === 'json' ? 'json' : outputFormat === 'html' ? 'html' : 'txt'; |
| |
| const blob = new Blob([content], { type: 'text/plain' }); |
| const url = URL.createObjectURL(blob); |
| const a = document.createElement('a'); |
| a.href = url; |
| a.download = `${fileName.split('.')[0]}_extracted.${extension}`; |
| document.body.appendChild(a); |
| a.click(); |
| document.body.removeChild(a); |
| URL.revokeObjectURL(url); |
| } |
| } |
|
|
| function downloadAsJson() { |
| if (window.docStrangeApp && window.docStrangeApp.extractionResults) { |
| const result = { |
| content: window.docStrangeApp.extractionResults.content, |
| metadata: window.docStrangeApp.extractionResults.metadata, |
| original_file: window.docStrangeApp.selectedFile.name |
| }; |
| |
| const fileName = window.docStrangeApp.selectedFile.name; |
| const blob = new Blob([JSON.stringify(result, null, 2)], { type: 'application/json' }); |
| const url = URL.createObjectURL(blob); |
| const a = document.createElement('a'); |
| a.href = url; |
| a.download = `${fileName.split('.')[0]}_extraction_result.json`; |
| document.body.appendChild(a); |
| a.click(); |
| document.body.removeChild(a); |
| URL.revokeObjectURL(url); |
| } |
| } |
|
|
| |
| document.addEventListener('DOMContentLoaded', () => { |
| window.docStrangeApp = new DocStrangeApp(); |
| }); |