diff --git a/app.py b/app.py index 9e13bf7..47cda0c 100644 --- a/app.py +++ b/app.py @@ -4,7 +4,12 @@ import os import time import threading import logging +import json +import re from pathlib import Path +import glob +from PIL import Image +import pdf2image # Configure logging logging.basicConfig(level=logging.INFO, @@ -358,6 +363,143 @@ def run_manual_command(): logger.error(f"Error running manual command: {str(e)}") return jsonify({'success': False, 'error': str(e)}), 500 +# NEW ROUTES TO SUPPORT ENHANCED UI + +@app.route('/generate-preview', methods=['POST']) +def generate_preview(): + """Generate a preview image of a PDF page""" + try: + # Get parameters + pdf_file = request.form.get('pdf_file') + page_num = int(request.form.get('page_num', 1)) + + if not pdf_file or not os.path.exists(pdf_file): + return jsonify({'success': False, 'error': 'PDF file not found'}), 400 + + # Ensure results directory exists + results_dir = ensure_results_folder() + preview_path = results_dir / f"preview_{os.path.basename(pdf_file)}_{page_num}.png" + + # Convert PDF page to image + try: + # Get total page count + from pdf2image.pdf2image import pdfinfo_from_path + pdf_info = pdfinfo_from_path(pdf_file) + page_count = pdf_info["Pages"] + + # Ensure the page number is valid + if page_num > page_count: + return jsonify({'success': False, 'error': f'Page number {page_num} exceeds total pages {page_count}'}), 400 + + # Convert the page + images = pdf2image.convert_from_path( + pdf_file, + dpi=150, # Lower DPI for preview + first_page=page_num, + last_page=page_num + ) + + if images: + # Resize for preview if too large + MAX_HEIGHT = 600 + img = images[0] + ratio = MAX_HEIGHT / img.height if img.height > MAX_HEIGHT else 1 + if ratio < 1: + new_width = int(img.width * ratio) + img = img.resize((new_width, MAX_HEIGHT), Image.Resampling.LANCZOS) + + # Save the preview + img.save(preview_path) + + return jsonify({ + 'success': True, + 'preview_image': f'/results/{preview_path.name}', + 'page_count': page_count + }) + else: + return jsonify({'success': False, 'error': 'Failed to convert PDF page'}), 500 + + except Exception as e: + logger.error(f"Error converting PDF: {str(e)}") + return jsonify({'success': False, 'error': str(e)}), 500 + + except Exception as e: + logger.error(f"Error generating preview: {str(e)}") + return jsonify({'success': False, 'error': str(e)}), 500 + +@app.route('/get-doctags-content') +def get_doctags_content(): + """Get the content of a DocTags file""" + try: + path = request.args.get('path') + if not path or not os.path.exists(path): + # Try prepending 'results/' if the path doesn't exist + if not path.startswith('results/'): + path = f"results/{path}" + + if not os.path.exists(path): + return "DocTags file not found", 404 + + with open(path, 'r', encoding='utf-8') as f: + content = f.read() + + return content + except Exception as e: + logger.error(f"Error reading DocTags file: {str(e)}") + return f"Error: {str(e)}", 500 + +@app.route('/get-extracted-images') +def get_extracted_images(): + """Get a list of extracted images for a specific PDF page""" + try: + pdf_file = request.args.get('pdf') + page_num = request.args.get('page', 1) + + if not pdf_file: + return jsonify({'success': False, 'error': 'PDF file not specified'}), 400 + + # Get the base name of the PDF without extension + pdf_basename = os.path.splitext(os.path.basename(pdf_file))[0] + + # Look for extracted images in the results/pictures directory + pictures_dir = Path("results") / "pictures" + + if not pictures_dir.exists(): + return jsonify({'success': True, 'images': []}) + + # Pattern to match: picture_*.* + image_pattern = pictures_dir / "picture_*.png" + image_files = glob.glob(str(image_pattern)) + + images = [] + for image_file in image_files: + img_path = Path(image_file) + img_id = "unknown" + img_caption = "" + + # Try to extract ID from filename (picture_1_caption.png) + match = re.search(r'picture_(\d+)', img_path.name) + if match: + img_id = match.group(1) + + # Look for a matching caption file + caption_file = img_path.with_suffix('.txt') + if caption_file.exists(): + with open(caption_file, 'r', encoding='utf-8') as f: + img_caption = f.read().strip() + + images.append({ + 'id': img_id, + 'path': f'/results/pictures/{img_path.name}', + 'caption': img_caption + }) + + return jsonify({'success': True, 'images': images}) + + except Exception as e: + logger.error(f"Error getting extracted images: {str(e)}") + return jsonify({'success': False, 'error': str(e)}), 500 + if __name__ == '__main__': ensure_results_folder() app.run(debug=True, host='127.0.0.1', port=5000) \ No newline at end of file diff --git a/dat-isia.pdf b/dat-isia.pdf new file mode 100644 index 0000000..d89c84e Binary files /dev/null and b/dat-isia.pdf differ diff --git a/index.html b/index.html index 63bb9ec..5100b85 100644 --- a/index.html +++ b/index.html @@ -5,133 +5,363 @@ DocTags Tools -

DocTags Analyzer and Visualizer

+
+

DocTags Analyzer and Visualizer

+
+
@@ -150,37 +380,75 @@
-
-
-

Step 1: Analyze PDF

+ +
+ +
+

1 Analyze PDF

Extract DocTags structure from the PDF page

+ + +
-
-

Step 2: Generate Visualization

+ +
+

2 Generate Visualization

Create visual representation of the extracted DocTags

- +
+ + +
-
-

Step 3: Extract Pictures

+ +
+

3 Extract Pictures

Extract images from the document based on DocTags

- +
+ + +
- - - + +
+

Advanced Options

@@ -189,6 +457,7 @@ // Keep track of active tasks const activeTasks = {}; let pollingInterval = null; + let pdfPages = {}; // Load PDF files on page load window.addEventListener('DOMContentLoaded', function() { @@ -216,16 +485,74 @@ select.appendChild(option); }); pdfStatus.innerHTML = 'Loaded ' + data.length + ' PDF files'; + + // Load the preview for the first PDF + if (data.length > 0) { + loadPdfPreview(data[0], 1); + } }) .catch(error => { console.error('Error loading PDFs:', error); pdfStatus.innerHTML = 'Error: ' + error.message + ''; }); + // Add event listeners for PDF and page selection changes + document.getElementById('pdf_file').addEventListener('change', function() { + const pageNum = document.getElementById('page_num').value; + loadPdfPreview(this.value, pageNum); + }); + + document.getElementById('page_num').addEventListener('change', function() { + const pdfFile = document.getElementById('pdf_file').value; + if (pdfFile) { + loadPdfPreview(pdfFile, this.value); + } + }); + // Run an environment check on startup checkEnvironment(); }); + // Function to load PDF preview + function loadPdfPreview(pdfFile, pageNum) { + const previewContainer = document.getElementById('pdf-preview'); + previewContainer.innerHTML = '
Loading PDF preview...'; + + // Generate a temp preview for the PDF page + const formData = new FormData(); + formData.append('pdf_file', pdfFile); + formData.append('page_num', pageNum); + + fetch('/generate-preview', { + method: 'POST', + body: formData + }) + .then(response => response.json()) + .then(data => { + if (data.success && data.preview_image) { + const img = document.createElement('img'); + img.src = data.preview_image + '?t=' + new Date().getTime(); // Add timestamp to prevent caching + img.alt = `Page ${pageNum} of ${pdfFile}`; + + // Clear previous content and add the new image + previewContainer.innerHTML = ''; + previewContainer.appendChild(img); + + // Store page count if available + if (data.page_count) { + pdfPages[pdfFile] = data.page_count; + document.getElementById('page_num').max = data.page_count; + } + } else { + previewContainer.innerHTML = '
Failed to load preview: ' + (data.error || 'Unknown error') + '
'; + } + }) + .catch(error => { + console.error('Error loading PDF preview:', error); + previewContainer.innerHTML = '
Error loading preview: ' + error.message + '
'; + }); + } + // Check the environment function checkEnvironment() { const envDiv = document.getElementById('environment-check'); @@ -331,6 +658,77 @@ } } + // Function to load DocTags preview + function loadDocTagsPreview(doctagsPath) { + fetch('/get-doctags-content?path=' + encodeURIComponent(doctagsPath)) + .then(response => response.text()) + .then(content => { + const doctagsPreview = document.getElementById('doctags-preview'); + doctagsPreview.textContent = content; + document.getElementById('analyze-preview-section').classList.remove('hidden'); + }) + .catch(error => { + console.error('Error loading DocTags content:', error); + }); + } + + // Function to load visualization preview + function loadVisualizationPreview(imagePath) { + const container = document.getElementById('visualization-preview'); + const img = document.createElement('img'); + img.src = imagePath + '?t=' + new Date().getTime(); + img.alt = 'DocTags Visualization'; + + container.innerHTML = ''; + container.appendChild(img); + document.getElementById('visualize-preview-section').classList.remove('hidden'); + } + + // Function to load extracted images preview + function loadExtractedImagesPreview() { + const pdfFile = document.getElementById('pdf_file').value; + const pageNum = document.getElementById('page_num').value; + + // Request the extracted images list + fetch(`/get-extracted-images?pdf=${encodeURIComponent(pdfFile)}&page=${pageNum}`) + .then(response => response.json()) + .then(data => { + const container = document.getElementById('extracted-images-preview'); + container.innerHTML = ''; + + if (data.success && data.images && data.images.length > 0) { + data.images.forEach(image => { + const imageDiv = document.createElement('div'); + imageDiv.className = 'extracted-image'; + + const img = document.createElement('img'); + img.src = image.path + '?t=' + new Date().getTime(); + img.alt = image.caption || `Extracted image ${image.id}`; + + imageDiv.appendChild(img); + + if (image.caption) { + const caption = document.createElement('div'); + caption.className = 'caption'; + caption.textContent = image.caption; + imageDiv.appendChild(caption); + } + + container.appendChild(imageDiv); + }); + } else { + container.innerHTML = '
No extracted images found
'; + } + + document.getElementById('extract-preview-section').classList.remove('hidden'); + }) + .catch(error => { + console.error('Error loading extracted images:', error); + const container = document.getElementById('extracted-images-preview'); + container.innerHTML = '
Error loading images: ' + error.message + '
'; + }); + } + // Poll for task updates function pollTasks() { for (const taskId in activeTasks) { @@ -360,18 +758,25 @@ outputDiv.textContent = data.output; outputDiv.classList.remove('hidden'); - // Show image if available for visualizer - if (taskInfo.type === 'visualizer' && data.image_file) { - document.getElementById('result-image').src = '/' + data.image_file + '?t=' + new Date().getTime(); - document.getElementById('image-container').classList.remove('hidden'); - } - - // Enable next step button if applicable + // Update preview based on task type if (taskInfo.type === 'analyzer') { + // Load DocTags preview + loadDocTagsPreview(data.doctags_file); + + // Enable next step button document.getElementById('visualizer-btn').disabled = false; - } else if (taskInfo.type === 'visualizer') { + } + else if (taskInfo.type === 'visualizer' && data.image_file) { + // Load visualization preview + loadVisualizationPreview('/' + data.image_file); + + // Enable next step button document.getElementById('extractor-btn').disabled = false; } + else if (taskInfo.type === 'extractor') { + // Load extracted images preview + loadExtractedImagesPreview(); + } // Remove from active tasks delete activeTasks[taskId]; @@ -428,11 +833,6 @@ // Clear previous output document.getElementById('output').classList.add('hidden'); - // Hide previous image if not running visualizer - if (script !== 'visualizer') { - document.getElementById('image-container').classList.add('hidden'); - } - // Determine endpoint let endpoint; switch(script) {