Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Slide Summary Generator</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| .dropzone { | |
| border: 2px dashed #9CA3AF; | |
| transition: all 0.3s ease; | |
| } | |
| .dropzone.active { | |
| border-color: #3B82F6; | |
| background-color: #EFF6FF; | |
| } | |
| .slide-preview { | |
| transition: all 0.3s ease; | |
| } | |
| .slide-preview:hover { | |
| transform: translateY(-5px); | |
| box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1); | |
| } | |
| .summary-card { | |
| background: linear-gradient(135deg, #F9FAFB 0%, #F3F4F6 100%); | |
| } | |
| .progress-bar { | |
| transition: width 0.5s ease; | |
| } | |
| @keyframes pulse { | |
| 0%, 100% { opacity: 1; } | |
| 50% { opacity: 0.5; } | |
| } | |
| .animate-pulse { | |
| animation: pulse 2s infinite; | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gray-50 min-h-screen"> | |
| <div class="container mx-auto px-4 py-8"> | |
| <!-- Header --> | |
| <header class="mb-10 text-center"> | |
| <h1 class="text-4xl font-bold text-blue-600 mb-2">Slide Summary Generator</h1> | |
| <p class="text-gray-600 max-w-2xl mx-auto">Upload your presentation slides and get a concise summary automatically generated for you.</p> | |
| </header> | |
| <!-- Main Content --> | |
| <div class="flex flex-col lg:flex-row gap-8"> | |
| <!-- Upload Section --> | |
| <div class="w-full lg:w-1/2"> | |
| <div id="dropzone" class="dropzone rounded-xl p-8 mb-6 text-center cursor-pointer"> | |
| <div class="flex flex-col items-center justify-center space-y-4"> | |
| <i class="fas fa-cloud-upload-alt text-5xl text-blue-400"></i> | |
| <h3 class="text-xl font-semibold text-gray-700">Drag & Drop Your Slides Here</h3> | |
| <p class="text-gray-500">or click to browse files</p> | |
| <input type="file" id="fileInput" class="hidden" accept="image/*,.pdf" multiple> | |
| <button id="uploadBtn" class="bg-blue-600 hover:bg-blue-700 text-white px-6 py-2 rounded-lg transition"> | |
| Select Files | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Upload Progress --> | |
| <div id="uploadProgress" class="hidden bg-white rounded-xl shadow p-6 mb-6"> | |
| <div class="flex justify-between mb-2"> | |
| <span class="font-medium">Processing...</span> | |
| <span id="progressPercent" class="text-blue-600">0%</span> | |
| </div> | |
| <div class="w-full bg-gray-200 rounded-full h-2.5"> | |
| <div id="progressBar" class="progress-bar bg-blue-600 h-2.5 rounded-full" style="width: 0%"></div> | |
| </div> | |
| </div> | |
| <!-- Slide Previews --> | |
| <div id="slidePreviews" class="hidden"> | |
| <h3 class="text-xl font-semibold mb-4 text-gray-700">Your Slides</h3> | |
| <div id="previewContainer" class="grid grid-cols-2 md:grid-cols-3 gap-4"> | |
| <!-- Slide previews will be added here --> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Summary Section --> | |
| <div class="w-full lg:w-1/2"> | |
| <div class="bg-white rounded-xl shadow p-6"> | |
| <div class="flex items-center justify-between mb-4"> | |
| <h2 class="text-2xl font-bold text-gray-800">Presentation Summary</h2> | |
| <button id="generateBtn" class="bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded-lg transition flex items-center disabled:opacity-50" disabled> | |
| <i class="fas fa-magic mr-2"></i> Generate Summary | |
| </button> | |
| </div> | |
| <!-- Summary Loading State --> | |
| <div id="summaryLoading" class="hidden p-8 text-center"> | |
| <div class="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-blue-500 mx-auto mb-4"></div> | |
| <p class="text-gray-600">Analyzing your slides and generating summary...</p> | |
| <div class="mt-4 space-y-2"> | |
| <div class="h-4 bg-gray-200 rounded animate-pulse"></div> | |
| <div class="h-4 bg-gray-200 rounded animate-pulse w-5/6 mx-auto"></div> | |
| <div class="h-4 bg-gray-200 rounded animate-pulse w-2/3 mx-auto"></div> | |
| </div> | |
| </div> | |
| <!-- Summary Content --> | |
| <div id="summaryContent" class="hidden"> | |
| <div class="mb-4"> | |
| <h3 class="font-semibold text-lg text-gray-800 mb-2">Key Points</h3> | |
| <ul id="keyPoints" class="list-disc pl-5 space-y-1 text-gray-700"> | |
| <!-- Key points will be added here --> | |
| </ul> | |
| </div> | |
| <div class="mb-4"> | |
| <h3 class="font-semibold text-lg text-gray-800 mb-2">Detailed Summary</h3> | |
| <div id="detailedSummary" class="text-gray-700 space-y-3"> | |
| <!-- Detailed summary will be added here --> | |
| </div> | |
| </div> | |
| <div class="flex justify-end mt-6"> | |
| <button id="copyBtn" class="flex items-center text-blue-600 hover:text-blue-800"> | |
| <i class="fas fa-copy mr-2"></i> Copy Summary | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Empty State --> | |
| <div id="emptyState" class="p-8 text-center"> | |
| <i class="fas fa-file-alt text-4xl text-gray-300 mb-4"></i> | |
| <h3 class="text-lg font-medium text-gray-500 mb-2">No Summary Yet</h3> | |
| <p class="text-gray-400">Upload your slides and click "Generate Summary" to get started.</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // DOM Elements | |
| const dropzone = document.getElementById('dropzone'); | |
| const fileInput = document.getElementById('fileInput'); | |
| const uploadBtn = document.getElementById('uploadBtn'); | |
| const uploadProgress = document.getElementById('uploadProgress'); | |
| const progressBar = document.getElementById('progressBar'); | |
| const progressPercent = document.getElementById('progressPercent'); | |
| const slidePreviews = document.getElementById('slidePreviews'); | |
| const previewContainer = document.getElementById('previewContainer'); | |
| const generateBtn = document.getElementById('generateBtn'); | |
| const summaryLoading = document.getElementById('summaryLoading'); | |
| const summaryContent = document.getElementById('summaryContent'); | |
| const emptyState = document.getElementById('emptyState'); | |
| const keyPoints = document.getElementById('keyPoints'); | |
| const detailedSummary = document.getElementById('detailedSummary'); | |
| const copyBtn = document.getElementById('copyBtn'); | |
| let uploadedFiles = []; | |
| // Event Listeners | |
| uploadBtn.addEventListener('click', () => fileInput.click()); | |
| fileInput.addEventListener('change', handleFileSelect); | |
| dropzone.addEventListener('dragover', handleDragOver); | |
| dropzone.addEventListener('dragleave', handleDragLeave); | |
| dropzone.addEventListener('drop', handleDrop); | |
| generateBtn.addEventListener('click', generateSummary); | |
| copyBtn.addEventListener('click', copySummary); | |
| // Functions | |
| function handleFileSelect(e) { | |
| const files = e.target.files; | |
| if (files.length > 0) { | |
| processFiles(files); | |
| } | |
| } | |
| function handleDragOver(e) { | |
| e.preventDefault(); | |
| dropzone.classList.add('active'); | |
| } | |
| function handleDragLeave() { | |
| dropzone.classList.remove('active'); | |
| } | |
| function handleDrop(e) { | |
| e.preventDefault(); | |
| dropzone.classList.remove('active'); | |
| const files = e.dataTransfer.files; | |
| if (files.length > 0) { | |
| processFiles(files); | |
| } | |
| } | |
| function processFiles(files) { | |
| // Reset previous uploads | |
| uploadedFiles = []; | |
| previewContainer.innerHTML = ''; | |
| // Show upload progress | |
| uploadProgress.classList.remove('hidden'); | |
| // Simulate upload progress | |
| let progress = 0; | |
| const interval = setInterval(() => { | |
| progress += 5; | |
| progressBar.style.width = `${progress}%`; | |
| progressPercent.textContent = `${progress}%`; | |
| if (progress >= 100) { | |
| clearInterval(interval); | |
| uploadProgress.classList.add('hidden'); | |
| // Process each file | |
| Array.from(files).forEach((file, index) => { | |
| // In a real app, you would upload to a server here | |
| // For demo, we'll just create previews | |
| uploadedFiles.push(file); | |
| createPreview(file, index); | |
| }); | |
| slidePreviews.classList.remove('hidden'); | |
| generateBtn.disabled = false; | |
| } | |
| }, 100); | |
| } | |
| function createPreview(file, index) { | |
| const reader = new FileReader(); | |
| reader.onload = function(e) { | |
| const preview = document.createElement('div'); | |
| preview.className = 'slide-preview bg-white rounded-lg overflow-hidden shadow-md relative'; | |
| if (file.type.startsWith('image/')) { | |
| preview.innerHTML = ` | |
| <img src="${e.target.result}" alt="Slide ${index + 1}" class="w-full h-32 object-cover"> | |
| <div class="p-2"> | |
| <p class="text-sm font-medium truncate">${file.name}</p> | |
| <p class="text-xs text-gray-500">Slide ${index + 1}</p> | |
| </div> | |
| <div class="absolute top-2 right-2 bg-blue-600 text-white text-xs px-2 py-1 rounded-full"> | |
| ${index + 1} | |
| </div> | |
| `; | |
| } else if (file.type === 'application/pdf') { | |
| preview.innerHTML = ` | |
| <div class="bg-red-100 h-32 flex items-center justify-center"> | |
| <i class="fas fa-file-pdf text-4xl text-red-500"></i> | |
| </div> | |
| <div class="p-2"> | |
| <p class="text-sm font-medium truncate">${file.name}</p> | |
| <p class="text-xs text-gray-500">PDF Document</p> | |
| </div> | |
| <div class="absolute top-2 right-2 bg-blue-600 text-white text-xs px-2 py-1 rounded-full"> | |
| ${index + 1} | |
| </div> | |
| `; | |
| } | |
| previewContainer.appendChild(preview); | |
| }; | |
| reader.readAsDataURL(file); | |
| } | |
| function generateSummary() { | |
| // Show loading state | |
| summaryLoading.classList.remove('hidden'); | |
| emptyState.classList.add('hidden'); | |
| summaryContent.classList.add('hidden'); | |
| generateBtn.disabled = true; | |
| // Simulate API call delay | |
| setTimeout(() => { | |
| // Hide loading state | |
| summaryLoading.classList.add('hidden'); | |
| // Show summary content | |
| summaryContent.classList.remove('hidden'); | |
| // Generate mock summary (in a real app, this would come from an API) | |
| const mockKeyPoints = [ | |
| "Introduction to machine learning concepts", | |
| "Types of machine learning: supervised, unsupervised, reinforcement", | |
| "Key algorithms: linear regression, decision trees, neural networks", | |
| "Applications in healthcare, finance, and automation", | |
| "Future trends and ethical considerations" | |
| ]; | |
| const mockDetailedSummary = ` | |
| <p>The presentation begins with an introduction to machine learning, defining it as a subset of artificial intelligence that enables systems to learn from data without being explicitly programmed.</p> | |
| <p>It covers the three main types of machine learning: supervised learning (where models learn from labeled data), unsupervised learning (finding patterns in unlabeled data), and reinforcement learning (learning through rewards and punishments).</p> | |
| <p>Key algorithms discussed include linear regression for predicting continuous values, decision trees for classification tasks, and neural networks for complex pattern recognition. The presentation highlights real-world applications in healthcare (diagnosis prediction), finance (fraud detection), and industrial automation.</p> | |
| <p>Finally, it explores future trends like federated learning and the growing importance of addressing ethical considerations such as bias in algorithms and data privacy concerns.</p> | |
| `; | |
| // Populate summary | |
| keyPoints.innerHTML = mockKeyPoints.map(point => `<li>${point}</li>`).join(''); | |
| detailedSummary.innerHTML = mockDetailedSummary; | |
| // Enable generate button again | |
| generateBtn.disabled = false; | |
| }, 3000); | |
| } | |
| function copySummary() { | |
| const summaryText = Array.from(keyPoints.querySelectorAll('li')) | |
| .map(li => `• ${li.textContent}`) | |
| .join('\n') + '\n\n' + detailedSummary.textContent; | |
| navigator.clipboard.writeText(summaryText).then(() => { | |
| // Show copied feedback | |
| const originalText = copyBtn.innerHTML; | |
| copyBtn.innerHTML = '<i class="fas fa-check mr-2"></i> Copied!'; | |
| setTimeout(() => { | |
| copyBtn.innerHTML = originalText; | |
| }, 2000); | |
| }); | |
| } | |
| }); | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=zeynep7/slide-summary-generator" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |