From 28bed0ead69bed68ce4e5b910119ca8cb6eea948 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Thu, 20 Nov 2025 12:17:08 +0000 Subject: [PATCH] Auto commit: 2025-11-20T12:17:08.078Z --- assets/js/main.js | 102 +++++++++++++++++++++++++++++++++++++--------- index.php | 34 +++++++++++++++- upload.php | 46 ++++++++++++++++++++- 3 files changed, 160 insertions(+), 22 deletions(-) diff --git a/assets/js/main.js b/assets/js/main.js index 029c066..f65f923 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -68,38 +68,100 @@ document.addEventListener('DOMContentLoaded', function () { }) .then(response => { if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); + // Try to get error message from JSON response, otherwise use status text + return response.json().then(err => { + throw new Error(err.message || response.statusText); + }).catch(() => { + throw new Error(response.statusText); + }); } return response.json(); }) .then(data => { - if(processingMessage) { - processingMessage.style.display = 'none'; - } - if(responseMessageDiv){ - const alertClass = data.status === 'success' ? 'alert-success' : 'alert-danger'; - responseMessageDiv.innerHTML = ``; + processingMessage.style.display = 'none'; + + if (data.status === 'success') { + const translatedText = data.data.translatedText; + const outputContainer = document.getElementById('translation-output-container'); + const outputElement = document.getElementById('translation-output'); + + if (outputElement && outputContainer) { + outputElement.textContent = translatedText; + outputContainer.style.display = 'block'; + } + + responseMessageDiv.innerHTML = ``; + responseMessageDiv.style.display = 'block'; + + } else { + responseMessageDiv.innerHTML = ``; responseMessageDiv.style.display = 'block'; - } - if(translateBtn) { - translateBtn.disabled = false; - translateBtn.innerHTML = 'Translate'; } }) .catch(error => { - if(processingMessage) { - processingMessage.style.display = 'none'; - } - if(responseMessageDiv){ - responseMessageDiv.innerHTML = ``; - responseMessageDiv.style.display = 'block'; - } + processingMessage.style.display = 'none'; + responseMessageDiv.innerHTML = ``; + responseMessageDiv.style.display = 'block'; + console.error('Fetch Error:', error); + }) + .finally(() => { if(translateBtn) { translateBtn.disabled = false; - translateBtn.innerHTML = 'Translate'; + translateBtn.innerHTML = ' Translate'; } - console.error('Error:', error); }); }); } + + // Handle copy and download buttons + const copyBtn = document.getElementById('copy-btn'); + const downloadBtn = document.getElementById('download-btn'); + const translationOutput = document.getElementById('translation-output'); + + if (copyBtn) { + copyBtn.addEventListener('click', () => { + if (translationOutput && navigator.clipboard) { + navigator.clipboard.writeText(translationOutput.textContent).then(() => { + const originalText = copyBtn.innerHTML; + copyBtn.innerHTML = ' Copied!'; + copyBtn.classList.add('btn-success'); + copyBtn.classList.remove('btn-secondary'); + setTimeout(() => { + copyBtn.innerHTML = originalText; + copyBtn.classList.remove('btn-success'); + copyBtn.classList.add('btn-secondary'); + }, 2000); + }).catch(err => { + console.error('Failed to copy text: ', err); + alert('Failed to copy text. Please try again.'); + }); + } + }); + } + + if (downloadBtn) { + downloadBtn.addEventListener('click', () => { + if (translationOutput && window.jspdf) { + try { + const { jsPDF } = window.jspdf; + const doc = new jsPDF(); + + // Set font that supports a wide range of characters + doc.setFont('Helvetica'); + doc.setFontSize(12); + + const text = translationOutput.textContent; + const lines = doc.splitTextToSize(text, 180); + + doc.text(lines, 15, 20); + doc.save('translation.pdf'); + } catch (error) { + console.error('Failed to generate PDF:', error); + alert('Failed to generate PDF. An error occurred.'); + } + } else if (!window.jspdf) { + alert('The PDF generation library is not loaded.'); + } + }); + } }); \ No newline at end of file diff --git a/index.php b/index.php index 52d8f2c..1f2a902 100644 --- a/index.php +++ b/index.php @@ -58,11 +58,20 @@
@@ -73,6 +82,15 @@ + + + + + + + + +
@@ -92,6 +110,19 @@ Processing your document... This may take a moment. + + @@ -104,6 +135,7 @@ + \ No newline at end of file diff --git a/upload.php b/upload.php index 26c118b..459603a 100644 --- a/upload.php +++ b/upload.php @@ -47,8 +47,52 @@ $target_path = $upload_dir . $file_name; // Move the file to the uploads directory if (move_uploaded_file($file['tmp_name'], $target_path)) { - json_response('success', 'File uploaded successfully.', ['filePath' => 'uploads/' . $file_name]); + // AI Translation Step + try { + require_once __DIR__ . '/ai/LocalAIApi.php'; + + $source_lang = $_POST['source_lang'] ?? 'auto-detect'; + $target_lang = $_POST['target_lang'] ?? 'English'; + $file_path_for_ai = 'uploads/' . $file_name; // The path relative to the project root + + $prompt = "You are an expert document translator. Please perform the following tasks:\n" + . "1. **OCR Extraction:** Analyze the document located at the following path: `{$file_path_for_ai}`. Extract all visible text from it.\n" + . "2. **Translation:** Translate the extracted text from `{$source_lang}` to `{$target_lang}`.\n" + . "3. **Output:** Return ONLY the translated text as a single block of plain text. Do not include any explanations, apologies, or introductory phrases. Just the translation."; + + $resp = LocalAIApi::createResponse( + [ + 'input' => [ + ['role' => 'system', 'content' => 'You are a document translation service.'], + ['role' => 'user', 'content' => $prompt], + ], + ] + ); + + if (!empty($resp['success'])) { + $translated_text = LocalAIApi::extractText($resp); + if ($translated_text === '') { + // Handle cases where the AI returns a non-text response or empty text + $decoded = LocalAIApi::decodeJsonFromResponse($resp); + $error_details = $decoded ? json_encode($decoded, JSON_PRETTY_PRINT) : 'AI returned an empty or invalid response.'; + json_response('error', 'AI processing failed. Details: ' . $error_details); + } else { + json_response('success', 'File translated successfully.', [ + 'filePath' => $file_path_for_ai, + 'translatedText' => $translated_text + ]); + } + } else { + $error_message = $resp['error'] ?? 'Unknown AI error.'; + json_response('error', 'Failed to get response from AI service: ' . $error_message); + } + + } catch (Exception $e) { + json_response('error', 'An exception occurred during AI processing: ' . $e->getMessage()); + } + } else { json_response('error', 'Failed to move uploaded file.'); } + ?> \ No newline at end of file