// Debug helpers function debug(message) { console.log(`[Debug] ${message}`); } document.addEventListener('DOMContentLoaded', function() { // Debug print debug("UI initialized"); // Get DOM elements const urlForm = document.getElementById('url-form'); const pdfForm = document.getElementById('pdf-form'); const tabButtons = document.querySelectorAll('.tab-btn'); const tabPanes = document.querySelectorAll('.tab-pane'); const fileInput = document.getElementById('pdf-file'); const fileNameDisplay = document.querySelector('.file-name'); const resultsContainer = document.getElementById('results'); const resultsGrid = document.querySelector('.results-grid'); const progressContainer = document.querySelector('.progress-container'); const progressText = document.querySelector('.progress-text'); const progressFill = document.querySelector('.progress-fill'); const tryNowBtn = document.getElementById('try-now-btn'); // Handle Try Now button click if (tryNowBtn) { tryNowBtn.addEventListener('click', function() { const translatorSection = document.getElementById('translator'); translatorSection.scrollIntoView({ behavior: 'smooth' }); }); } // Handle tab switching tabButtons.forEach(button => { button.addEventListener('click', function() { // Get the target tab const tabId = this.getAttribute('data-tab'); // Remove active class from all tabs and panes tabButtons.forEach(btn => btn.classList.remove('active')); tabPanes.forEach(pane => pane.classList.remove('active')); // Add active class to current tab and pane this.classList.add('active'); document.getElementById(tabId).classList.add('active'); debug(`Switched to tab: ${tabId}`); }); }); // Handle file input change if (fileInput) { fileInput.addEventListener('change', function() { if (this.files.length > 0) { const fileName = this.files[0].name; fileNameDisplay.textContent = fileName; debug(`Selected file: ${fileName}`); } else { fileNameDisplay.textContent = 'No file chosen'; } }); } // Handle URL form submission if (urlForm) { urlForm.addEventListener('submit', async function(e) { e.preventDefault(); // Get form data const url = document.getElementById('manga-url').value; const srcLang = document.getElementById('url-src-lang').value; const tgtLang = document.getElementById('url-tgt-lang').value; debug(`Submitting URL form with url=${url}, srcLang=${srcLang}, tgtLang=${tgtLang}`); // Show progress bar resultsGrid.innerHTML = ''; progressFill.style.width = '0%'; progressText.textContent = 'Preparing translation...'; progressContainer.style.display = 'block'; // Submit form data to API try { // Create the request body const requestBody = { url: url, src_lang: srcLang, tgt_lang: tgtLang, translator: 'google' }; // Call the API with streaming response await handleTranslation('/translate/url', requestBody); } catch (error) { debug(`Error during URL translation: ${error}`); showError("An error occurred during translation. Please try again."); } }); } // Handle PDF form submission if (pdfForm) { pdfForm.addEventListener('submit', async function(e) { e.preventDefault(); // Check if a file is selected if (!fileInput.files[0]) { showError("Please select a PDF file first."); return; } // Get form data const file = fileInput.files[0]; const srcLang = document.getElementById('pdf-src-lang').value; const tgtLang = document.getElementById('pdf-tgt-lang').value; debug(`Submitting PDF form with file=${file.name}, srcLang=${srcLang}, tgtLang=${tgtLang}`); // Show progress bar resultsGrid.innerHTML = ''; progressFill.style.width = '0%'; progressText.textContent = 'Preparing PDF translation...'; progressContainer.style.display = 'block'; // Create FormData const formData = new FormData(); formData.append('file', file); formData.append('src_lang', srcLang); formData.append('tgt_lang', tgtLang); formData.append('translator', 'google'); // Submit form data to API try { // Call the translation endpoint with streaming response await handlePdfTranslation('/translate/pdf', formData); } catch (error) { debug(`Error during PDF translation: ${error}`); showError("An error occurred during translation. Please try again."); } }); } // Function to handle URL translation with streaming response async function handleTranslation(endpoint, requestBody) { try { const response = await fetch(endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(requestBody) }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const reader = response.body.getReader(); const decoder = new TextDecoder(); let receivedImages = 0; let totalImages = 5; // Default assumption, will be updated if more info is available while (true) { const { value, done } = await reader.read(); if (done) { break; } // Process the streamed response const text = decoder.decode(value, { stream: true }); const lines = text.split('\n\n'); for (const line of lines) { if (line.startsWith('data: ')) { try { const data = JSON.parse(line.substring(6)); processTranslationUpdate(data, receivedImages, totalImages); if (data.status === 'success' && data.image_url) { receivedImages++; updateProgress(receivedImages, totalImages); } else if (data.status === 'complete') { progressContainer.style.display = 'none'; } } catch (e) { debug(`Error parsing JSON: ${e}`); } } } } } catch (error) { debug(`Error during translation: ${error}`); showError("An error occurred during translation. Please try again."); } } // Function to handle PDF translation with streaming response async function handlePdfTranslation(endpoint, formData) { try { const response = await fetch(endpoint, { method: 'POST', body: formData }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const reader = response.body.getReader(); const decoder = new TextDecoder(); let receivedImages = 0; let totalImages = 5; // Default assumption, will be updated if more info is available while (true) { const { value, done } = await reader.read(); if (done) { break; } // Process the streamed response const text = decoder.decode(value, { stream: true }); const lines = text.split('\n\n'); for (const line of lines) { if (line.startsWith('data: ')) { try { const data = JSON.parse(line.substring(6)); processTranslationUpdate(data, receivedImages, totalImages); if (data.status === 'success' && data.image_url) { receivedImages++; updateProgress(receivedImages, totalImages); } else if (data.status === 'complete') { progressContainer.style.display = 'none'; } } catch (e) { debug(`Error parsing JSON: ${e}`); } } } } } catch (error) { debug(`Error during translation: ${error}`); showError("An error occurred during translation. Please try again."); } } // Process translation updates function processTranslationUpdate(data, currentImage, totalImages) { debug(`Received update: ${JSON.stringify(data)}`); if (data.status === 'error') { showError(data.message || "An error occurred during translation."); progressContainer.style.display = 'none'; return; } if (data.status === 'processing') { progressText.textContent = data.message || `Processing image ${currentImage + 1}/${totalImages}...`; return; } if (data.status === 'success' && data.image_url) { // Add the translated image to the results addImageToResults(data.image_url); } if (data.status === 'complete') { progressText.textContent = 'Translation complete!'; progressFill.style.width = '100%'; setTimeout(() => { progressContainer.style.display = 'none'; }, 1000); } } // Update progress bar function updateProgress(current, total) { const percentage = Math.min(Math.round((current / total) * 100), 100); progressFill.style.width = `${percentage}%`; progressText.textContent = `Processing page ${current}/${total}...`; } // Add an image to the results grid function addImageToResults(imageUrl) { // Create result card const resultCard = document.createElement('div'); resultCard.className = 'result-card'; // Create image const img = document.createElement('img'); img.className = 'result-image'; img.src = imageUrl; img.alt = 'Translated Image'; img.loading = 'lazy'; // Create actions div const actionsDiv = document.createElement('div'); actionsDiv.className = 'result-actions'; // Create download link const downloadLink = document.createElement('a'); downloadLink.href = imageUrl; downloadLink.download = 'translated-' + imageUrl.split('/').pop(); downloadLink.className = 'btn'; downloadLink.innerHTML = ' Download'; // Create view link const viewLink = document.createElement('a'); viewLink.href = imageUrl; viewLink.target = '_blank'; viewLink.className = 'btn'; viewLink.innerHTML = ' View'; // Append elements actionsDiv.appendChild(downloadLink); actionsDiv.appendChild(viewLink); resultCard.appendChild(img); resultCard.appendChild(actionsDiv); resultsGrid.appendChild(resultCard); } // Show error message function showError(message) { resultsGrid.innerHTML = `

${message}

`; } // Create placeholder image on page load for visual preview function createPlaceholderImage() { const placeholderUrl = '/static/ui/placeholder.png'; debug('Creating placeholder UI example'); // Only add placeholder if no results yet if (resultsGrid.children.length === 0) { addImageToResults(placeholderUrl); addImageToResults(placeholderUrl); } } // Optional: Add placeholder images for demo purposes // Uncomment to enable placeholders on page load // createPlaceholderImage(); });