xacwutao's picture
Add 2 files
a0be895 verified
Raw
History Blame Contribute Delete
15.5 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Advanced Text Processor</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 #ccc;
transition: all 0.3s;
}
.dropzone.active {
border-color: #4f46e5;
background-color: #f0f7ff;
}
.chunk-box {
position: relative;
}
.chunk-box:hover .copy-btn {
opacity: 1;
}
.copy-btn {
opacity: 0;
transition: opacity 0.2s;
}
.progress-bar {
transition: width 0.3s ease;
}
.glow {
animation: glow 1.5s ease-in-out infinite alternate;
}
@keyframes glow {
from {
box-shadow: 0 0 5px rgba(79, 70, 229, 0.5);
}
to {
box-shadow: 0 0 15px rgba(79, 70, 229, 0.8);
}
}
</style>
</head>
<body class="bg-gray-50 min-h-screen">
<div class="container mx-auto px-4 py-8 max-w-4xl">
<div class="text-center mb-8">
<h1 class="text-3xl font-bold text-indigo-700 mb-2">Advanced Text Processor</h1>
<p class="text-gray-600">Upload a TXT file to clean text (removes punctuation and numbers)</p>
</div>
<div class="bg-white rounded-xl shadow-md p-6 mb-8 glow">
<div id="dropzone" class="dropzone rounded-lg p-12 text-center cursor-pointer">
<div class="flex flex-col items-center justify-center">
<i class="fas fa-file-alt text-4xl text-indigo-500 mb-4"></i>
<h3 class="text-lg font-medium text-gray-700 mb-2">Drag & drop your TXT file here</h3>
<p class="text-gray-500 mb-4">or</p>
<label for="fileInput" class="bg-indigo-600 text-white px-4 py-2 rounded-md hover:bg-indigo-700 transition cursor-pointer">
<i class="fas fa-upload mr-2"></i> Select File
</label>
<input id="fileInput" type="file" accept=".txt" class="hidden">
</div>
</div>
<div id="progressContainer" class="mt-4 hidden">
<div class="flex justify-between mb-1">
<span class="text-sm font-medium text-indigo-700">Processing...</span>
<span id="progressPercent" class="text-sm font-medium text-indigo-700">0%</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2.5">
<div id="progressBar" class="progress-bar bg-indigo-600 h-2.5 rounded-full" style="width: 0%"></div>
</div>
</div>
</div>
<div id="resultsSection" class="hidden">
<div class="flex justify-between items-center mb-4">
<h2 class="text-xl font-semibold text-gray-800">Processed Results</h2>
<div class="flex space-x-2">
<button id="copyAllBtn" class="bg-indigo-100 text-indigo-700 px-3 py-1 rounded-md text-sm hover:bg-indigo-200 transition flex items-center">
<i class="fas fa-copy mr-1"></i> Copy All
</button>
<button id="downloadBtn" class="bg-green-100 text-green-700 px-3 py-1 rounded-md text-sm hover:bg-green-200 transition flex items-center">
<i class="fas fa-download mr-1"></i> Download
</button>
</div>
</div>
<div id="fileInfo" class="bg-blue-50 border-l-4 border-blue-500 p-4 mb-6 rounded">
<div class="flex justify-between">
<div>
<h3 class="font-medium text-blue-800" id="fileName"></h3>
<p class="text-sm text-blue-600" id="fileSize"></p>
</div>
<div class="text-right">
<p class="text-sm text-blue-600" id="chunkCount"></p>
<p class="text-sm text-blue-600" id="processingTime"></p>
</div>
</div>
</div>
<div id="chunksContainer" class="space-y-4"></div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const dropzone = document.getElementById('dropzone');
const fileInput = document.getElementById('fileInput');
const resultsSection = document.getElementById('resultsSection');
const chunksContainer = document.getElementById('chunksContainer');
const progressContainer = document.getElementById('progressContainer');
const progressBar = document.getElementById('progressBar');
const progressPercent = document.getElementById('progressPercent');
const copyAllBtn = document.getElementById('copyAllBtn');
const downloadBtn = document.getElementById('downloadBtn');
const fileName = document.getElementById('fileName');
const fileSize = document.getElementById('fileSize');
const chunkCount = document.getElementById('chunkCount');
const processingTime = document.getElementById('processingTime');
// Handle drag and drop events
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
dropzone.addEventListener(eventName, preventDefaults, false);
});
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
['dragenter', 'dragover'].forEach(eventName => {
dropzone.addEventListener(eventName, highlight, false);
});
['dragleave', 'drop'].forEach(eventName => {
dropzone.addEventListener(eventName, unhighlight, false);
});
function highlight() {
dropzone.classList.add('active');
}
function unhighlight() {
dropzone.classList.remove('active');
}
// Handle dropped files
dropzone.addEventListener('drop', handleDrop, false);
fileInput.addEventListener('change', handleFiles);
function handleDrop(e) {
const dt = e.dataTransfer;
const files = dt.files;
handleFiles({ target: { files } });
}
function handleFiles(e) {
const file = e.target.files[0];
if (!file) return;
if (!file.name.endsWith('.txt')) {
alert('Please upload a .txt file');
return;
}
processFile(file);
}
function processFile(file) {
const startTime = performance.now();
progressContainer.classList.remove('hidden');
resultsSection.classList.add('hidden');
chunksContainer.innerHTML = '';
const reader = new FileReader();
reader.onload = function(e) {
let content = e.target.result;
// Advanced text cleaning
// 1. Remove all punctuation (including full-width punctuation)
// Full-width punctuation ranges:
// - Full-width comma, period: \uFF0C-\uFF0E
// - Full-width brackets: \uFF08-\uFF09
// - Full-width exclamation/question: \uFF01-\uFF1F
// - Full-width period: \u3002
content = content.replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,\-.\/:;<=>?@[\]^_`{|}~\uFF0C-\uFF0E\uFF08-\uFF09\uFF01-\uFF1F\u3002]/g, '');
// 2. Remove numeric sequences (like 1. 2. 3. etc.)
content = content.replace(/\b\d+\.?\s*/g, '');
// 3. Remove standalone numbers
content = content.replace(/\b\d+\b/g, '');
// 4. Normalize whitespace (replace multiple spaces/newlines with single space)
content = content.replace(/\s+/g, ' ');
// 5. Trim leading/trailing spaces
content = content.trim();
// Split into 128-byte chunks
const chunks = [];
for (let i = 0; i < content.length; i += 128) {
const chunk = content.substr(i, 128).trim();
if (chunk.length > 0) { // Only add non-empty chunks
chunks.push(chunk);
}
}
// Update progress bar as we process chunks
let processed = 0;
const totalChunks = chunks.length;
// Display file info
fileName.textContent = file.name;
fileSize.textContent = `${(file.size / 1024).toFixed(2)} KB`;
chunkCount.textContent = `${totalChunks} chunks`;
// Process chunks with slight delay to show progress
const processChunk = (index) => {
if (index >= totalChunks) {
const endTime = performance.now();
processingTime.textContent = `Processed in ${((endTime - startTime) / 1000).toFixed(2)}s`;
progressContainer.classList.add('hidden');
resultsSection.classList.remove('hidden');
// Store the cleaned content for download
document.cleanedContent = chunks.join('\n\n');
return;
}
const chunk = chunks[index];
createChunkElement(chunk, index + 1);
processed++;
const percent = Math.round((processed / totalChunks) * 100);
progressBar.style.width = `${percent}%`;
progressPercent.textContent = `${percent}%`;
setTimeout(() => processChunk(index + 1), 10);
};
processChunk(0);
};
reader.readAsText(file);
}
function createChunkElement(chunk, index) {
const chunkElement = document.createElement('div');
chunkElement.className = 'chunk-box bg-white border border-gray-200 rounded-lg p-4 hover:shadow-sm transition';
chunkElement.innerHTML = `
<div class="flex justify-between items-start mb-2">
<span class="text-xs font-medium bg-indigo-100 text-indigo-800 px-2 py-1 rounded">Chunk ${index}</span>
<span class="text-xs text-gray-500">${chunk.length} bytes</span>
</div>
<div class="relative">
<pre class="text-gray-800 whitespace-pre-wrap break-words font-mono text-sm">${chunk}</pre>
<button class="copy-btn absolute top-0 right-0 bg-gray-100 hover:bg-gray-200 p-1 rounded text-gray-600" data-chunk="${index}">
<i class="fas fa-copy text-xs"></i>
</button>
</div>
`;
chunksContainer.appendChild(chunkElement);
}
// Copy functionality
chunksContainer.addEventListener('click', function(e) {
if (e.target.closest('.copy-btn')) {
const btn = e.target.closest('.copy-btn');
const chunkIndex = btn.getAttribute('data-chunk');
const chunkText = btn.closest('.chunk-box').querySelector('pre').textContent;
navigator.clipboard.writeText(chunkText).then(() => {
const originalIcon = btn.innerHTML;
btn.innerHTML = '<i class="fas fa-check text-xs text-green-500"></i>';
setTimeout(() => {
btn.innerHTML = originalIcon;
}, 2000);
});
}
});
// Copy all chunks
copyAllBtn.addEventListener('click', function() {
const allChunks = Array.from(document.querySelectorAll('#chunksContainer pre'))
.map(pre => pre.textContent)
.join('\n\n');
navigator.clipboard.writeText(allChunks).then(() => {
const originalText = copyAllBtn.innerHTML;
copyAllBtn.innerHTML = '<i class="fas fa-check mr-1"></i> Copied!';
setTimeout(() => {
copyAllBtn.innerHTML = originalText;
}, 2000);
});
});
// Download cleaned content
downloadBtn.addEventListener('click', function() {
if (!document.cleanedContent) return;
const blob = new Blob([document.cleanedContent], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'cleaned_' + fileName.textContent;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
// Show download confirmation
const originalText = downloadBtn.innerHTML;
downloadBtn.innerHTML = '<i class="fas fa-check mr-1"></i> Downloaded!';
setTimeout(() => {
downloadBtn.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=xacwutao/advanced-text-processor" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>