Sum / templates /index.html
harshdhane's picture
Upload 3 files
1e6c2a6 verified
Raw
History Blame Contribute Delete
22.9 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PDF Summarizer | AI-Powered Document Analysis</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap" rel="stylesheet">
</head>
<body>
<div class="container">
<!-- Header -->
<header class="header">
<div class="logo">
<i class="fas fa-file-pdf"></i>
<h1>PDF Summarizer</h1>
</div>
<p class="tagline">Extract key insights from your documents in seconds</p>
</header>
<!-- Main Content -->
<div class="main-content">
<!-- Left Panel - Upload & Controls -->
<div class="left-panel">
<div class="upload-section card">
<h2><i class="fas fa-upload"></i> Upload PDF</h2>
<p class="description">Upload your PDF document to generate an AI-powered summary</p>
<div class="upload-area" id="dropArea">
<i class="fas fa-cloud-upload-alt upload-icon"></i>
<p class="upload-text">Drag & Drop your PDF file here</p>
<p class="upload-subtext">or click to browse</p>
<input type="file" id="pdfInput" accept=".pdf" hidden>
<button class="btn btn-primary" id="browseBtn">
<i class="fas fa-folder-open"></i> Browse Files
</button>
<p class="file-info">Max file size: 16MB</p>
</div>
<div id="fileInfo" class="file-info-container" style="display: none;">
<div class="selected-file">
<i class="fas fa-file-pdf"></i>
<span id="fileName"></span>
<button class="btn-remove" id="removeFile">
<i class="fas fa-times"></i>
</button>
</div>
</div>
</div>
<!-- Controls Section -->
<div class="controls-section card">
<h2><i class="fas fa-sliders-h"></i> Summary Settings</h2>
<div class="control-group">
<label for="summaryRatio">
<i class="fas fa-compress-alt"></i> Summary Ratio
<span id="ratioValue">30%</span>
</label>
<input type="range" id="summaryRatio" min="10" max="70" value="30" step="5">
<div class="range-labels">
<span>Brief</span>
<span>Detailed</span>
</div>
</div>
<div class="btn-group">
<button class="btn btn-primary" id="summarizeBtn" disabled>
<i class="fas fa-magic"></i> Generate Summary
</button>
<button class="btn btn-secondary" id="resetBtn">
<i class="fas fa-redo"></i> Reset
</button>
</div>
</div>
<!-- Statistics Section -->
<div class="stats-section card">
<h2><i class="fas fa-chart-bar"></i> Document Statistics</h2>
<div id="statsContent">
<div class="stats-placeholder">
<i class="fas fa-chart-pie"></i>
<p>Upload a PDF to view statistics</p>
</div>
</div>
</div>
</div>
<!-- Right Panel - Results -->
<div class="right-panel">
<div class="results-section card">
<div class="results-header">
<h2><i class="fas fa-file-alt"></i> Summary</h2>
<div class="actions" id="downloadActions" style="display: none;">
<button class="btn btn-download" id="downloadPdf">
<i class="fas fa-file-pdf"></i> Save as PDF
</button>
<button class="btn btn-download" id="downloadTxt">
<i class="fas fa-file-text"></i> Save as TXT
</button>
<button class="btn btn-copy" id="copyBtn">
<i class="far fa-copy"></i> Copy
</button>
</div>
</div>
<div class="results-content">
<div id="summaryPlaceholder">
<div class="placeholder-content">
<i class="fas fa-search"></i>
<h3>No Summary Yet</h3>
<p>Upload a PDF file and click "Generate Summary" to see the results here.</p>
</div>
</div>
<div id="summaryContent" style="display: none;">
<div class="summary-header">
<h3 id="summaryTitle"></h3>
<div class="summary-meta">
<span class="badge" id="compressionBadge">
<i class="fas fa-compress-alt"></i> <span id="compressionValue">0%</span> compressed
</span>
<span class="badge" id="lengthBadge">
<i class="fas fa-text-width"></i> <span id="wordCount">0</span> words
</span>
</div>
</div>
<div class="summary-text" id="summaryText"></div>
</div>
<div id="errorMessage" class="error-message" style="display: none;">
<i class="fas fa-exclamation-triangle"></i>
<h3>Error Processing PDF</h3>
<p id="errorText"></p>
</div>
</div>
<div class="loader" id="loader" style="display: none;">
<div class="spinner"></div>
<p>Analyzing your document...</p>
</div>
</div>
<!-- Tips Section -->
<div class="tips-section card">
<h2><i class="fas fa-lightbulb"></i> Tips for Better Results</h2>
<ul class="tips-list">
<li><i class="fas fa-check-circle"></i> Use text-based PDFs for best results</li>
<li><i class="fas fa-check-circle"></i> For scanned PDFs, use OCR software first</li>
<li><i class="fas fa-check-circle"></i> Adjust summary ratio based on document length</li>
<li><i class="fas fa-check-circle"></i> Longer documents may take more time to process</li>
<li><i class="fas fa-check-circle"></i> Results are more accurate with well-structured documents</li>
</ul>
</div>
</div>
</div>
<!-- Footer -->
<footer class="footer">
<p>© 2024 PDF Summarizer | Built with Flask & NLTK | <i class="fas fa-heart"></i> Made with passion</p>
</footer>
</div>
<!-- Notification Toast -->
<div id="toast" class="toast"></div>
<script>
// DOM Elements
const pdfInput = document.getElementById('pdfInput');
const browseBtn = document.getElementById('browseBtn');
const dropArea = document.getElementById('dropArea');
const summarizeBtn = document.getElementById('summarizeBtn');
const resetBtn = document.getElementById('resetBtn');
const summaryRatio = document.getElementById('summaryRatio');
const ratioValue = document.getElementById('ratioValue');
const fileInfo = document.getElementById('fileInfo');
const fileName = document.getElementById('fileName');
const removeFile = document.getElementById('removeFile');
const summaryPlaceholder = document.getElementById('summaryPlaceholder');
const summaryContent = document.getElementById('summaryContent');
const summaryText = document.getElementById('summaryText');
const summaryTitle = document.getElementById('summaryTitle');
const compressionValue = document.getElementById('compressionValue');
const wordCount = document.getElementById('wordCount');
const downloadActions = document.getElementById('downloadActions');
const downloadPdf = document.getElementById('downloadPdf');
const downloadTxt = document.getElementById('downloadTxt');
const copyBtn = document.getElementById('copyBtn');
const errorMessage = document.getElementById('errorMessage');
const errorText = document.getElementById('errorText');
const loader = document.getElementById('loader');
const statsContent = document.getElementById('statsContent');
const toast = document.getElementById('toast');
let currentFile = null;
// Event Listeners
browseBtn.addEventListener('click', () => pdfInput.click());
pdfInput.addEventListener('change', handleFileSelect);
summarizeBtn.addEventListener('click', processPDF);
resetBtn.addEventListener('click', resetAll);
removeFile.addEventListener('click', removeSelectedFile);
summaryRatio.addEventListener('input', updateRatioValue);
downloadPdf.addEventListener('click', () => downloadSummary('pdf'));
downloadTxt.addEventListener('click', () => downloadSummary('txt'));
copyBtn.addEventListener('click', copySummary);
// Drag and Drop functionality
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
dropArea.addEventListener(eventName, preventDefaults, false);
});
['dragenter', 'dragover'].forEach(eventName => {
dropArea.addEventListener(eventName, highlight, false);
});
['dragleave', 'drop'].forEach(eventName => {
dropArea.addEventListener(eventName, unhighlight, false);
});
dropArea.addEventListener('drop', handleDrop, false);
// Functions
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
function highlight() {
dropArea.classList.add('highlight');
}
function unhighlight() {
dropArea.classList.remove('highlight');
}
function handleDrop(e) {
const dt = e.dataTransfer;
const file = dt.files[0];
if (file && file.type === 'application/pdf') {
handleFile(file);
} else {
showToast('Please drop a valid PDF file', 'error');
}
}
function handleFileSelect(e) {
const file = e.target.files[0];
if (file) {
handleFile(file);
}
}
function handleFile(file) {
if (file.size > 16 * 1024 * 1024) {
showToast('File size exceeds 16MB limit', 'error');
return;
}
currentFile = file;
fileName.textContent = file.name;
fileInfo.style.display = 'block';
summarizeBtn.disabled = false;
dropArea.style.display = 'none';
showToast('PDF uploaded successfully!', 'success');
}
function removeSelectedFile() {
currentFile = null;
pdfInput.value = '';
fileInfo.style.display = 'none';
summarizeBtn.disabled = true;
dropArea.style.display = 'flex';
}
function updateRatioValue() {
const value = summaryRatio.value;
ratioValue.textContent = `${value}%`;
}
async function processPDF() {
if (!currentFile) return;
showLoader(true);
hideError();
hideSummary();
const formData = new FormData();
formData.append('pdf_file', currentFile);
formData.append('summary_ratio', summaryRatio.value / 100);
try {
const response = await fetch('/upload', {
method: 'POST',
body: formData
});
const data = await response.json();
if (data.success) {
displaySummary(data);
displayStatistics(data.statistics, data.compression_ratio, data.summary_length);
showToast('Summary generated successfully!', 'success');
} else {
showError(data.error || 'Failed to process PDF');
}
} catch (error) {
showError('Network error. Please try again.');
} finally {
showLoader(false);
}
}
function displaySummary(data) {
summaryTitle.textContent = `Summary of ${data.filename}`;
summaryText.textContent = data.summary;
compressionValue.textContent = `${data.compression_ratio}%`;
wordCount.textContent = data.summary_length;
summaryPlaceholder.style.display = 'none';
summaryContent.style.display = 'block';
downloadActions.style.display = 'flex';
// Update badges based on compression
const compressionBadge = document.getElementById('compressionBadge');
if (data.compression_ratio > 70) {
compressionBadge.className = 'badge badge-high';
} else if (data.compression_ratio > 40) {
compressionBadge.className = 'badge badge-medium';
} else {
compressionBadge.className = 'badge badge-low';
}
}
function displayStatistics(stats, compressionRatio, summaryLength) {
statsContent.innerHTML = `
<div class="stats-grid">
<div class="stat-item">
<div class="stat-icon">
<i class="fas fa-file"></i>
</div>
<div class="stat-info">
<span class="stat-label">Pages</span>
<span class="stat-value">${stats.page_count}</span>
</div>
</div>
<div class="stat-item">
<div class="stat-icon">
<i class="fas fa-paragraph"></i>
</div>
<div class="stat-info">
<span class="stat-label">Sentences</span>
<span class="stat-value">${stats.sentence_count}</span>
</div>
</div>
<div class="stat-item">
<div class="stat-icon">
<i class="fas fa-font"></i>
</div>
<div class="stat-info">
<span class="stat-label">Words</span>
<span class="stat-value">${stats.word_count}</span>
</div>
</div>
<div class="stat-item">
<div class="stat-icon">
<i class="fas fa-ruler"></i>
</div>
<div class="stat-info">
<span class="stat-label">Avg. Word Length</span>
<span class="stat-value">${stats.avg_word_length.toFixed(1)}</span>
</div>
</div>
<div class="stat-item">
<div class="stat-icon">
<i class="fas fa-compress-alt"></i>
</div>
<div class="stat-info">
<span class="stat-label">Compression</span>
<span class="stat-value">${compressionRatio}%</span>
</div>
</div>
<div class="stat-item">
<div class="stat-icon">
<i class="fas fa-text-height"></i>
</div>
<div class="stat-info">
<span class="stat-label">Summary Words</span>
<span class="stat-value">${summaryLength}</span>
</div>
</div>
</div>
`;
}
async function downloadSummary(format) {
if (!summaryText.textContent) return;
try {
if (format === 'pdf') {
const response = await fetch('/download', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
summary: summaryText.textContent,
filename: currentFile.name
})
});
if (response.ok) {
const blob = await response.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = currentFile.name.replace('.pdf', '_summary.pdf');
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
document.body.removeChild(a);
showToast('PDF downloaded successfully!', 'success');
}
} else if (format === 'txt') {
const response = await fetch('/export', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
summary: summaryText.textContent
})
});
if (response.ok) {
const blob = await response.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'summary.txt';
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
document.body.removeChild(a);
showToast('Text file downloaded successfully!', 'success');
}
}
} catch (error) {
showToast('Failed to download file', 'error');
}
}
function copySummary() {
const text = summaryText.textContent;
navigator.clipboard.writeText(text)
.then(() => showToast('Summary copied to clipboard!', 'success'))
.catch(() => showToast('Failed to copy text', 'error'));
}
function resetAll() {
currentFile = null;
pdfInput.value = '';
fileInfo.style.display = 'none';
summarizeBtn.disabled = true;
dropArea.style.display = 'flex';
hideSummary();
hideError();
showLoader(false);
statsContent.innerHTML = `
<div class="stats-placeholder">
<i class="fas fa-chart-pie"></i>
<p>Upload a PDF to view statistics</p>
</div>
`;
summaryRatio.value = 30;
updateRatioValue();
showToast('All fields have been reset', 'info');
}
function hideSummary() {
summaryPlaceholder.style.display = 'flex';
summaryContent.style.display = 'none';
downloadActions.style.display = 'none';
}
function showError(message) {
errorText.textContent = message;
errorMessage.style.display = 'block';
hideSummary();
}
function hideError() {
errorMessage.style.display = 'none';
}
function showLoader(show) {
loader.style.display = show ? 'flex' : 'none';
}
function showToast(message, type = 'info') {
toast.textContent = message;
toast.className = `toast toast-${type} show`;
setTimeout(() => {
toast.classList.remove('show');
}, 3000);
}
// Initialize
updateRatioValue();
</script>
</body>
</html>