| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>RAG Chunking Calculator</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"> |
| <script> |
| tailwind.config = { |
| theme: { |
| extend: { |
| colors: { |
| primary: { |
| 50: '#f5f3ff', |
| 100: '#ede9fe', |
| 200: '#ddd6fe', |
| 300: '#c4b5fd', |
| 400: '#a78bfa', |
| 500: '#8b5cf6', |
| 600: '#7c3aed', |
| 700: '#6d28d9', |
| 800: '#5b21b6', |
| 900: '#4c1d95', |
| }, |
| secondary: { |
| 50: '#fffbeb', |
| 100: '#fef3c7', |
| 200: '#fde68a', |
| 300: '#fcd34d', |
| 400: '#fbbf24', |
| 500: '#f59e0b', |
| 600: '#d97706', |
| 700: '#b45309', |
| 800: '#92400e', |
| 900: '#78350f', |
| } |
| } |
| } |
| } |
| } |
| </script> |
| <style> |
| .chunk-highlight { |
| background-color: rgba(167, 139, 250, 0.15); |
| border-left: 3px solid rgb(139, 92, 246); |
| padding: 12px 16px; |
| margin: 8px 0; |
| border-radius: 6px; |
| transition: all 0.2s ease; |
| } |
| .chunk-highlight:hover { |
| background-color: rgba(167, 139, 250, 0.25); |
| transform: translateX(2px); |
| } |
| .overlap-highlight { |
| background-color: rgba(251, 191, 36, 0.15); |
| border-left: 3px solid rgb(245, 158, 11); |
| padding: 12px 16px; |
| margin: 8px 0; |
| border-radius: 6px; |
| transition: all 0.2s ease; |
| } |
| .overlap-highlight:hover { |
| background-color: rgba(251, 191, 36, 0.25); |
| transform: translateX(2px); |
| } |
| .slider-thumb::-webkit-slider-thumb { |
| -webkit-appearance: none; |
| width: 20px; |
| height: 20px; |
| border-radius: 50%; |
| background: #8b5cf6; |
| cursor: pointer; |
| box-shadow: 0 2px 6px rgba(0,0,0,0.2); |
| transition: all 0.2s ease; |
| } |
| .slider-thumb::-webkit-slider-thumb:hover { |
| transform: scale(1.1); |
| box-shadow: 0 3px 8px rgba(0,0,0,0.3); |
| } |
| .slider-thumb::-moz-range-thumb { |
| width: 20px; |
| height: 20px; |
| border-radius: 50%; |
| background: #8b5cf6; |
| cursor: pointer; |
| box-shadow: 0 2px 6px rgba(0,0,0,0.2); |
| transition: all 0.2s ease; |
| } |
| .slider-thumb::-moz-range-thumb:hover { |
| transform: scale(1.1); |
| box-shadow: 0 3px 8px rgba(0,0,0,0.3); |
| } |
| .text-area-container { |
| position: relative; |
| } |
| .word-counter { |
| position: absolute; |
| bottom: 12px; |
| right: 12px; |
| background: rgba(255,255,255,0.9); |
| padding: 3px 10px; |
| border-radius: 12px; |
| font-size: 12px; |
| color: #4b5563; |
| box-shadow: 0 1px 3px rgba(0,0,0,0.1); |
| } |
| .stat-card { |
| transition: all 0.3s ease; |
| } |
| .stat-card:hover { |
| transform: translateY(-2px); |
| box-shadow: 0 4px 12px rgba(0,0,0,0.08); |
| } |
| .tooltip { |
| position: relative; |
| display: inline-block; |
| } |
| .tooltip .tooltip-text { |
| visibility: hidden; |
| width: 200px; |
| background-color: #333; |
| color: #fff; |
| text-align: center; |
| border-radius: 6px; |
| padding: 8px; |
| position: absolute; |
| z-index: 1; |
| bottom: 125%; |
| left: 50%; |
| margin-left: -100px; |
| opacity: 0; |
| transition: opacity 0.3s; |
| font-size: 13px; |
| } |
| .tooltip:hover .tooltip-text { |
| visibility: visible; |
| opacity: 1; |
| } |
| .fade-in { |
| animation: fadeIn 0.3s ease-in; |
| } |
| @keyframes fadeIn { |
| from { opacity: 0; transform: translateY(10px); } |
| to { opacity: 1; transform: translateY(0); } |
| } |
| .scrollbar-custom::-webkit-scrollbar { |
| width: 8px; |
| height: 8px; |
| } |
| .scrollbar-custom::-webkit-scrollbar-track { |
| background: #f1f1f1; |
| border-radius: 10px; |
| } |
| .scrollbar-custom::-webkit-scrollbar-thumb { |
| background: #c4b5fd; |
| border-radius: 10px; |
| } |
| .scrollbar-custom::-webkit-scrollbar-thumb:hover { |
| background: #8b5cf6; |
| } |
| </style> |
| </head> |
| <body class="bg-gray-50 min-h-screen font-sans antialiased"> |
| <div class="container mx-auto px-4 py-8 max-w-6xl"> |
| |
| <div class="text-center mb-10"> |
| <div class="inline-flex items-center justify-center bg-gradient-to-r from-primary-500 to-secondary-500 text-white px-6 py-3 rounded-full shadow-md mb-4"> |
| <i class="fas fa-brain mr-2"></i> |
| <span class="font-bold">RAG CHUNKING CALCULATOR</span> |
| </div> |
| <h1 class="text-4xl font-bold text-gray-800 mb-3">Optimize Your Document Chunks</h1> |
| <p class="text-gray-600 max-w-2xl mx-auto text-lg"> |
| Enhance your Retrieval-Augmented Generation pipeline by experimenting with different chunking strategies. |
| </p> |
| </div> |
|
|
| |
| <div class="bg-white rounded-xl shadow-lg overflow-hidden mb-8 border border-gray-100"> |
| <div class="p-6 bg-gradient-to-r from-primary-50 to-secondary-50 border-b border-gray-200"> |
| <div class="flex items-center mb-2"> |
| <div class="bg-primary-500 text-white p-2 rounded-lg mr-3"> |
| <i class="fas fa-align-left"></i> |
| </div> |
| <h2 class="text-xl font-semibold text-gray-800">Input Text</h2> |
| </div> |
| <p class="text-sm text-gray-500 ml-12">Paste your document content below (max 1000 words)</p> |
| </div> |
| <div class="p-6"> |
| <div class="text-area-container"> |
| <textarea id="inputText" rows="8" class="w-full p-4 border border-gray-200 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500 transition-all placeholder-gray-400" placeholder="Example: Retrieval-Augmented Generation (RAG) combines pre-trained language models with information retrieval systems to produce more accurate and contextually relevant responses..."></textarea> |
| <div class="word-counter"> |
| <span id="wordCount">0</span>/1000 words |
| </div> |
| </div> |
| <div class="mt-4 flex items-center text-sm text-gray-500"> |
| <i class="fas fa-info-circle mr-2 text-primary-500"></i> |
| <span>For best results, use well-structured text with complete sentences.</span> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8"> |
| |
| <div class="bg-white rounded-xl shadow-md overflow-hidden border border-gray-100 stat-card"> |
| <div class="p-6"> |
| <div class="flex items-center mb-4"> |
| <div class="bg-primary-100 text-primary-600 p-2 rounded-lg mr-3"> |
| <i class="fas fa-ruler"></i> |
| </div> |
| <div> |
| <h2 class="text-lg font-semibold text-gray-800">Chunk Size</h2> |
| <p class="text-sm text-gray-500">Words per chunk</p> |
| </div> |
| </div> |
| <div class="mb-2"> |
| <input type="range" id="chunkSize" min="50" max="500" value="200" step="10" class="w-full slider-thumb"> |
| <div class="flex justify-between text-sm text-gray-600 mt-1"> |
| <span>50</span> |
| <span class="font-medium text-primary-600" id="chunkSizeValue">200</span> |
| <span>500</span> |
| </div> |
| </div> |
| <div class="flex items-center text-sm text-gray-500"> |
| <i class="fas fa-info-circle mr-2 text-primary-500"></i> |
| <span>Larger chunks provide more context but may be less precise.</span> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="bg-white rounded-xl shadow-md overflow-hidden border border-gray-100 stat-card"> |
| <div class="p-6"> |
| <div class="flex items-center mb-4"> |
| <div class="bg-secondary-100 text-secondary-600 p-2 rounded-lg mr-3"> |
| <i class="fas fa-layer-group"></i> |
| </div> |
| <div> |
| <h2 class="text-lg font-semibold text-gray-800">Overlap</h2> |
| <p class="text-sm text-gray-500">Words between chunks</p> |
| </div> |
| </div> |
| <div class="mb-2"> |
| <input type="range" id="overlapSize" min="0" max="100" value="20" step="5" class="w-full slider-thumb"> |
| <div class="flex justify-between text-sm text-gray-600 mt-1"> |
| <span>0</span> |
| <span class="font-medium text-secondary-600" id="overlapSizeValue">20</span> |
| <span>100</span> |
| </div> |
| </div> |
| <div class="flex items-center text-sm text-gray-500"> |
| <i class="fas fa-info-circle mr-2 text-secondary-500"></i> |
| <span>Higher overlap reduces context loss but increases redundancy.</span> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="bg-white rounded-xl shadow-md overflow-hidden border border-gray-100 stat-card"> |
| <div class="p-6"> |
| <div class="flex items-center mb-4"> |
| <div class="bg-purple-100 text-purple-600 p-2 rounded-lg mr-3"> |
| <i class="fas fa-chart-pie"></i> |
| </div> |
| <div> |
| <h2 class="text-lg font-semibold text-gray-800">Statistics</h2> |
| <p class="text-sm text-gray-500">Current configuration</p> |
| </div> |
| </div> |
| <div class="space-y-3"> |
| <div class="flex justify-between items-center"> |
| <div class="flex items-center"> |
| <span class="text-gray-600">Total Chunks:</span> |
| <div class="tooltip ml-1"> |
| <i class="fas fa-question-circle text-gray-400 text-xs"></i> |
| <span class="tooltip-text">Total number of chunks generated from your text</span> |
| </div> |
| </div> |
| <span id="totalChunks" class="font-medium text-gray-800 bg-primary-50 px-3 py-1 rounded-full">0</span> |
| </div> |
| <div class="flex justify-between items-center"> |
| <div class="flex items-center"> |
| <span class="text-gray-600">Avg Chunk Size:</span> |
| <div class="tooltip ml-1"> |
| <i class="fas fa-question-circle text-gray-400 text-xs"></i> |
| <span class="tooltip-text">Average word count per chunk</span> |
| </div> |
| </div> |
| <span id="avgChunkSize" class="font-medium text-gray-800 bg-primary-50 px-3 py-1 rounded-full">0</span> |
| </div> |
| <div class="flex justify-between items-center"> |
| <div class="flex items-center"> |
| <span class="text-gray-600">Redundancy:</span> |
| <div class="tooltip ml-1"> |
| <i class="fas fa-question-circle text-gray-400 text-xs"></i> |
| <span class="tooltip-text">Percentage of repeated words due to overlap</span> |
| </div> |
| </div> |
| <span id="redundancy" class="font-medium text-gray-800 bg-primary-50 px-3 py-1 rounded-full">0%</span> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="bg-white rounded-xl shadow-lg overflow-hidden border border-gray-100 mb-8"> |
| <div class="p-6 border-b border-gray-200 bg-gradient-to-r from-primary-50 to-secondary-50"> |
| <div class="flex flex-col md:flex-row md:items-center md:justify-between mb-2"> |
| <div class="flex items-center mb-3 md:mb-0"> |
| <div class="bg-primary-500 text-white p-2 rounded-lg mr-3"> |
| <i class="fas fa-cubes"></i> |
| </div> |
| <h2 class="text-xl font-semibold text-gray-800">Generated Chunks</h2> |
| </div> |
| <div class="flex items-center space-x-4"> |
| <div class="flex items-center"> |
| <span class="w-4 h-4 rounded-full bg-primary-300 mr-2"></span> |
| <span class="text-sm">Chunk</span> |
| </div> |
| <div class="flex items-center"> |
| <span class="w-4 h-4 rounded-full bg-secondary-300 mr-2"></span> |
| <span class="text-sm">Overlap</span> |
| </div> |
| <button id="copyAllBtn" class="text-sm bg-gray-100 hover:bg-gray-200 text-gray-700 px-3 py-1 rounded-lg transition-all flex items-center"> |
| <i class="fas fa-copy mr-1"></i> Copy All |
| </button> |
| </div> |
| </div> |
| <p class="text-sm text-gray-500 ml-12">Preview how your document will be split based on current settings</p> |
| </div> |
| |
| <div id="chunksContainer" class="border-b border-gray-200 p-6 bg-gray-50 max-h-[500px] overflow-y-auto scrollbar-custom"> |
| <div class="text-center text-gray-500 py-10"> |
| <i class="fas fa-cubes text-4xl mb-3 text-gray-300"></i> |
| <h3 class="text-lg font-medium text-gray-400 mb-1">No chunks generated yet</h3> |
| <p class="max-w-md mx-auto">Paste your text above and adjust the sliders to see how it will be divided into chunks</p> |
| </div> |
| </div> |
|
|
| <div class="p-4 bg-gray-50 border-t border-gray-200 flex justify-between items-center"> |
| <div class="text-sm text-gray-500"> |
| <span id="visibleChunks">0</span> of <span id="totalVisibleChunks">0</span> chunks displayed |
| </div> |
| <div class="flex space-x-2"> |
| <button id="prevChunkBtn" class="px-3 py-1 bg-gray-200 rounded-lg text-gray-700 disabled:opacity-50" disabled> |
| <i class="fas fa-chevron-left"></i> |
| </button> |
| <button id="nextChunkBtn" class="px-3 py-1 bg-gray-200 rounded-lg text-gray-700 disabled:opacity-50" disabled> |
| <i class="fas fa-chevron-right"></i> |
| </button> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="bg-gradient-to-r from-primary-50 to-secondary-50 rounded-xl p-6 shadow-sm border border-gray-200"> |
| <div class="flex items-center mb-4"> |
| <div class="bg-gradient-to-r from-primary-500 to-secondary-500 text-white p-2 rounded-lg mr-3"> |
| <i class="fas fa-lightbulb"></i> |
| </div> |
| <h3 class="text-xl font-semibold text-gray-800">Chunking Strategy Recommendations</h3> |
| </div> |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-4"> |
| <div class="bg-white p-5 rounded-lg shadow-sm border border-gray-100 hover:shadow-md transition-all"> |
| <div class="flex items-start mb-2"> |
| <div class="bg-primary-100 text-primary-600 p-2 rounded-lg mr-3"> |
| <i class="fas fa-bars"></i> |
| </div> |
| <div> |
| <div class="font-medium text-primary-700 mb-1">Small Chunks (50-150 words)</div> |
| <p class="text-sm text-gray-600">Best for precise retrieval of facts or when working with short documents like FAQs or product descriptions. Use overlap of 10-20 words.</p> |
| </div> |
| </div> |
| </div> |
| <div class="bg-white p-5 rounded-lg shadow-sm border border-gray-100 hover:shadow-md transition-all"> |
| <div class="flex items-start mb-2"> |
| <div class="bg-primary-100 text-primary-600 p-2 rounded-lg mr-3"> |
| <i class="fas fa-th-large"></i> |
| </div> |
| <div> |
| <div class="font-medium text-primary-700 mb-1">Medium Chunks (150-300 words)</div> |
| <p class="text-sm text-gray-600">Good balance for most documents, providing enough context while maintaining retrieval precision. Use overlap of 20-40 words.</p> |
| </div> |
| </div> |
| </div> |
| <div class="bg-white p-5 rounded-lg shadow-sm border border-gray-100 hover:shadow-md transition-all"> |
| <div class="flex items-start mb-2"> |
| <div class="bg-primary-100 text-primary-600 p-2 rounded-lg mr-3"> |
| <i class="fas fa-th"></i> |
| </div> |
| <div> |
| <div class="font-medium text-primary-700 mb-1">Large Chunks (300-500 words)</div> |
| <p class="text-sm text-gray-600">Useful for complex topics requiring more context, like research papers or technical documentation. Use overlap of 40-60 words.</p> |
| </div> |
| </div> |
| </div> |
| <div class="bg-white p-5 rounded-lg shadow-sm border border-gray-100 hover:shadow-md transition-all"> |
| <div class="flex items-start mb-2"> |
| <div class="bg-secondary-100 text-secondary-600 p-2 rounded-lg mr-3"> |
| <i class="fas fa-random"></i> |
| </div> |
| <div> |
| <div class="font-medium text-secondary-700 mb-1">Advanced Strategies</div> |
| <p class="text-sm text-gray-600">Consider semantic chunking for complex documents, or hybrid approaches combining fixed-size chunks with paragraph boundaries.</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="mt-10 text-center text-gray-500 text-sm"> |
| <p>RAG Chunking Calculator v1.0 | Designed for AI pipeline optimization</p> |
| <p class="mt-1">Use this tool to experiment with different chunking strategies for your Retrieval-Augmented Generation systems</p> |
| </div> |
| </div> |
|
|
| <script> |
| document.addEventListener('DOMContentLoaded', function() { |
| |
| const inputText = document.getElementById('inputText'); |
| const chunkSizeSlider = document.getElementById('chunkSize'); |
| const overlapSizeSlider = document.getElementById('overlapSize'); |
| const chunkSizeValue = document.getElementById('chunkSizeValue'); |
| const overlapSizeValue = document.getElementById('overlapSizeValue'); |
| const chunksContainer = document.getElementById('chunksContainer'); |
| const wordCount = document.getElementById('wordCount'); |
| const totalChunks = document.getElementById('totalChunks'); |
| const avgChunkSize = document.getElementById('avgChunkSize'); |
| const redundancy = document.getElementById('redundancy'); |
| const copyAllBtn = document.getElementById('copyAllBtn'); |
| const prevChunkBtn = document.getElementById('prevChunkBtn'); |
| const nextChunkBtn = document.getElementById('nextChunkBtn'); |
| const visibleChunks = document.getElementById('visibleChunks'); |
| const totalVisibleChunks = document.getElementById('totalVisibleChunks'); |
| |
| |
| let currentChunks = []; |
| let currentVisibleIndex = 0; |
| const chunksPerPage = 3; |
| |
| |
| updateSliderValues(); |
| |
| |
| chunkSizeSlider.addEventListener('input', updateChunking); |
| overlapSizeSlider.addEventListener('input', updateChunking); |
| inputText.addEventListener('input', updateChunking); |
| copyAllBtn.addEventListener('click', copyAllChunks); |
| prevChunkBtn.addEventListener('click', showPreviousChunks); |
| nextChunkBtn.addEventListener('click', showNextChunks); |
| |
| |
| function updateSliderValues() { |
| chunkSizeValue.textContent = chunkSizeSlider.value; |
| overlapSizeValue.textContent = overlapSizeSlider.value; |
| } |
| |
| function updateWordCount() { |
| const text = inputText.value.trim(); |
| const words = text ? text.split(/\s+/).filter(word => word.length > 0).length : 0; |
| wordCount.textContent = words; |
| |
| |
| if (words > 1000) { |
| wordCount.classList.add('text-red-500'); |
| |
| const truncatedText = text.split(/\s+/).slice(0, 1000).join(' '); |
| inputText.value = truncatedText; |
| setTimeout(() => { |
| wordCount.textContent = '1000'; |
| }, 0); |
| } else { |
| wordCount.classList.remove('text-red-500'); |
| } |
| } |
| |
| function updateChunking() { |
| updateSliderValues(); |
| updateWordCount(); |
| |
| const text = inputText.value.trim(); |
| if (!text) { |
| chunksContainer.innerHTML = ` |
| <div class="text-center text-gray-500 py-10"> |
| <i class="fas fa-cubes text-4xl mb-3 text-gray-300"></i> |
| <h3 class="text-lg font-medium text-gray-400 mb-1">No chunks generated yet</h3> |
| <p class="max-w-md mx-auto">Paste your text above and adjust the sliders to see how it will be divided into chunks</p> |
| </div> |
| `; |
| totalChunks.textContent = '0'; |
| avgChunkSize.textContent = '0'; |
| redundancy.textContent = '0%'; |
| visibleChunks.textContent = '0'; |
| totalVisibleChunks.textContent = '0'; |
| prevChunkBtn.disabled = true; |
| nextChunkBtn.disabled = true; |
| currentChunks = []; |
| return; |
| } |
| |
| const chunkSize = parseInt(chunkSizeSlider.value); |
| const overlap = parseInt(overlapSizeSlider.value); |
| |
| |
| const words = text.split(/\s+/).filter(word => word.length > 0); |
| |
| |
| const chunks = []; |
| let start = 0; |
| |
| while (start < words.length) { |
| const end = Math.min(start + chunkSize, words.length); |
| chunks.push({ |
| start, |
| end, |
| text: words.slice(start, end).join(' ') |
| }); |
| |
| |
| start += (chunkSize - overlap); |
| } |
| |
| |
| totalChunks.textContent = chunks.length; |
| |
| const avgSize = chunks.reduce((sum, chunk) => sum + (chunk.end - chunk.start), 0) / chunks.length; |
| avgChunkSize.textContent = Math.round(avgSize); |
| |
| const totalWords = words.length; |
| const uniqueWords = new Set(words).size; |
| const redundancyPercent = Math.round(((totalWords - uniqueWords) / totalWords) * 100); |
| redundancy.textContent = `${redundancyPercent}%`; |
| |
| |
| currentChunks = chunks; |
| currentVisibleIndex = 0; |
| displayVisibleChunks(); |
| } |
| |
| function displayVisibleChunks() { |
| if (currentChunks.length === 0) { |
| chunksContainer.innerHTML = '<p class="text-gray-500">No chunks generated.</p>'; |
| return; |
| } |
| |
| const startIdx = currentVisibleIndex; |
| const endIdx = Math.min(currentVisibleIndex + chunksPerPage, currentChunks.length); |
| const visibleChunksArray = currentChunks.slice(startIdx, endIdx); |
| |
| chunksContainer.innerHTML = ''; |
| |
| visibleChunksArray.forEach((chunk, index) => { |
| const chunkElement = document.createElement('div'); |
| chunkElement.className = 'mb-8 fade-in'; |
| |
| |
| const header = document.createElement('div'); |
| header.className = 'flex justify-between items-center mb-3 px-2'; |
| |
| const title = document.createElement('span'); |
| title.className = 'font-medium text-primary-700 flex items-center'; |
| |
| const chunkNumber = document.createElement('span'); |
| chunkNumber.className = 'bg-primary-500 text-white text-sm px-2 py-1 rounded mr-2'; |
| chunkNumber.textContent = `#${startIdx + index + 1}`; |
| |
| title.appendChild(chunkNumber); |
| title.appendChild(document.createTextNode(` Words ${chunk.start + 1}-${chunk.end}`)); |
| |
| const wordCount = document.createElement('span'); |
| wordCount.className = 'text-sm bg-primary-100 text-primary-800 px-3 py-1 rounded-full'; |
| wordCount.textContent = `${chunk.end - chunk.start} words`; |
| |
| header.appendChild(title); |
| header.appendChild(wordCount); |
| chunkElement.appendChild(header); |
| |
| |
| const content = document.createElement('div'); |
| content.className = 'bg-white p-5 rounded-lg border border-gray-200 shadow-sm hover:shadow-md transition-all'; |
| |
| |
| const chunkText = document.createElement('div'); |
| chunkText.className = 'chunk-highlight'; |
| chunkText.textContent = chunk.text; |
| content.appendChild(chunkText); |
| |
| |
| const globalIndex = startIdx + index; |
| if (globalIndex < currentChunks.length - 1 && overlapSizeSlider.value > 0) { |
| const nextChunk = currentChunks[globalIndex + 1]; |
| const overlapStart = nextChunk.start; |
| const overlapEnd = Math.min(chunk.end, nextChunk.end); |
| |
| if (overlapStart < overlapEnd) { |
| const overlapText = currentChunks[0].text.split(/\s+/).slice(overlapStart, overlapEnd).join(' '); |
| |
| const overlapLabel = document.createElement('div'); |
| overlapLabel.className = 'text-xs text-secondary-700 mt-4 mb-2 font-medium flex items-center'; |
| overlapLabel.innerHTML = `<i class="fas fa-link mr-1"></i> Overlap with Chunk #${globalIndex + 2}:`; |
| content.appendChild(overlapLabel); |
| |
| const overlapElement = document.createElement('div'); |
| overlapElement.className = 'overlap-highlight'; |
| overlapElement.textContent = overlapText; |
| content.appendChild(overlapElement); |
| } |
| } |
| |
| chunkElement.appendChild(content); |
| chunksContainer.appendChild(chunkElement); |
| }); |
| |
| |
| visibleChunks.textContent = `${startIdx + 1}-${endIdx}`; |
| totalVisibleChunks.textContent = currentChunks.length; |
| prevChunkBtn.disabled = currentVisibleIndex === 0; |
| nextChunkBtn.disabled = endIdx >= currentChunks.length; |
| } |
| |
| function showPreviousChunks() { |
| if (currentVisibleIndex > 0) { |
| currentVisibleIndex = Math.max(0, currentVisibleIndex - chunksPerPage); |
| displayVisibleChunks(); |
| } |
| } |
| |
| function showNextChunks() { |
| if (currentVisibleIndex + chunksPerPage < currentChunks.length) { |
| currentVisibleIndex += chunksPerPage; |
| displayVisibleChunks(); |
| } |
| } |
| |
| function copyAllChunks() { |
| if (currentChunks.length === 0) return; |
| |
| const chunksText = currentChunks.map((chunk, index) => { |
| return `=== Chunk ${index + 1} (Words ${chunk.start + 1}-${chunk.end}) ===\n${chunk.text}\n`; |
| }).join('\n'); |
| |
| navigator.clipboard.writeText(chunksText).then(() => { |
| |
| const originalText = copyAllBtn.innerHTML; |
| copyAllBtn.innerHTML = '<i class="fas fa-check mr-1"></i> Copied!'; |
| copyAllBtn.classList.remove('bg-gray-100', 'hover:bg-gray-200'); |
| copyAllBtn.classList.add('bg-green-100', 'text-green-700'); |
| |
| setTimeout(() => { |
| copyAllBtn.innerHTML = originalText; |
| copyAllBtn.classList.remove('bg-green-100', 'text-green-700'); |
| copyAllBtn.classList.add('bg-gray-100', 'hover:bg-gray-200'); |
| }, 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=Kobish44/jackspace" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
| </html> |