diff --git a/assets/js/main.js b/assets/js/main.js
index f65f923..19c8209 100644
--- a/assets/js/main.js
+++ b/assets/js/main.js
@@ -4,8 +4,11 @@ document.addEventListener('DOMContentLoaded', function () {
const fileNameDisplay = document.getElementById('file-upload-filename');
const translateBtn = document.getElementById('translate-btn');
const processingMessage = document.getElementById('processing-message');
+ const previewContainer = document.getElementById('preview-container');
+ const imagePreview = document.getElementById('image-preview');
+ const startTranslationBtn = document.getElementById('start-translation-btn');
+ let uploadedFilePath = '';
- // Trigger file input click when the custom upload area is clicked
if(fileUploadLabel) {
fileUploadLabel.addEventListener('click', () => {
if(fileUploadInput) {
@@ -14,36 +17,56 @@ document.addEventListener('DOMContentLoaded', function () {
});
}
- // Update UI when a file is selected
if(fileUploadInput) {
fileUploadInput.addEventListener('change', () => {
if (fileUploadInput.files.length > 0) {
- const fileName = fileUploadInput.files[0].name;
+ const file = fileUploadInput.files[0];
+ const fileName = file.name;
if(fileNameDisplay) {
fileNameDisplay.textContent = `Selected file: ${fileName}`;
}
- if(translateBtn) {
- translateBtn.disabled = false;
- }
- } else {
- if(fileNameDisplay) {
- fileNameDisplay.textContent = '';
- }
- if(translateBtn) {
- translateBtn.disabled = true;
- }
+
+ const formData = new FormData();
+ formData.append('document', file);
+
+ processingMessage.style.display = 'block';
+ fileUploadLabel.style.display = 'none';
+
+ fetch('upload.php', {
+ method: 'POST',
+ body: formData
+ })
+ .then(response => response.json())
+ .then(data => {
+ processingMessage.style.display = 'none';
+ if (data.success && data.filePath) {
+ uploadedFilePath = data.filePath;
+ imagePreview.src = uploadedFilePath;
+ previewContainer.style.display = 'block';
+ document.getElementById('translation-form').style.display = 'none';
+ startTranslationBtn.style.display = 'block';
+ } else {
+ throw new Error(data.message || 'File upload failed.');
+ }
+ })
+ .catch(error => {
+ processingMessage.style.display = 'none';
+ const responseMessageDiv = document.getElementById('response-message');
+ responseMessageDiv.innerHTML = `
-
+
+
Document Preview
+

+
+
+
diff --git a/translate.php b/translate.php
new file mode 100644
index 0000000..caf5319
--- /dev/null
+++ b/translate.php
@@ -0,0 +1,92 @@
+ $status,
+ 'message' => $message,
+ 'data' => $data
+ ]);
+ exit;
+}
+
+if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
+ json_response('error', 'Invalid request method.');
+}
+
+if (!isset($_POST['file_path']) || !isset($_POST['source_lang']) || !isset($_POST['target_lang'])) {
+ json_response('error', 'Missing required parameters.');
+}
+
+$file_path = $_POST['file_path'];
+$source_lang = $_POST['source_lang'];
+$target_lang = $_POST['target_lang'];
+
+$full_path = __DIR__ . '/' . $file_path;
+
+if (!file_exists($full_path)) {
+ json_response('error', 'File not found.');
+}
+
+try {
+ $file_content = file_get_contents($full_path);
+ if ($file_content === false) {
+ json_response('error', 'Failed to read file content.');
+ }
+
+ $base64_image = base64_encode($file_content);
+
+ if (function_exists('mime_content_type')) {
+ $mime_type = mime_content_type($full_path);
+ } else {
+ $mime_type = 'application/octet-stream';
+ }
+
+ $resp = LocalAIApi::createResponse([
+ 'input' => [
+ [
+ 'role' => 'user',
+ 'content' => [
+ [
+ 'type' => 'text',
+ 'text' => "You are an expert document translator. Please perform the following tasks:\n" \
+ . "1. **OCR Extraction:** Extract all visible text from the attached image.\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."
+ ],
+ [
+ 'type' => 'image',
+ 'source' => [
+ 'type' => 'base64',
+ 'media_type' => $mime_type,
+ 'data' => $base64_image,
+ ],
+ ],
+ ],
+ ],
+ ],
+ ]);
+
+ if (!empty($resp['success'])) {
+ $translated_text = LocalAIApi::extractText($resp);
+ if ($translated_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.', ['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: ' . $e->getMessage());
+}
+?>
diff --git a/upload.php b/upload.php
index cb47189..0cf7bb5 100644
--- a/upload.php
+++ b/upload.php
@@ -1,33 +1,29 @@
$status,
- 'message' => $message,
- 'data' => $data
- ]);
+header('Content-Type: application/json');
+
+function json_response($success, $message, $filePath = null) {
+ $response = ['success' => $success, 'message' => $message];
+ if ($filePath) {
+ $response['filePath'] = $filePath;
+ }
+ echo json_encode($response);
exit;
}
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
- json_response('error', 'Invalid request method.');
+ json_response(false, 'Invalid request method.');
}
if (!isset($_FILES['document']) || $_FILES['document']['error'] == UPLOAD_ERR_NO_FILE) {
- json_response('error', 'No file was uploaded.');
+ json_response(false, 'No file was uploaded.');
}
$file = $_FILES['document'];
-// Check for upload errors
if ($file['error'] !== UPLOAD_ERR_OK) {
$upload_errors = [
UPLOAD_ERR_INI_SIZE => 'The uploaded file exceeds the upload_max_filesize directive in php.ini.',
@@ -39,90 +35,24 @@ if ($file['error'] !== UPLOAD_ERR_OK) {
UPLOAD_ERR_EXTENSION => 'A PHP extension stopped the file upload.',
];
$error_message = $upload_errors[$file['error']] ?? 'Unknown upload error.';
- json_response('error', $error_message);
+ json_response(false, $error_message);
}
$upload_dir = __DIR__ . '/uploads/';
if (!is_dir($upload_dir)) {
if (!mkdir($upload_dir, 0775, true)) {
- json_response('error', 'Failed to create upload directory.');
+ json_response(false, 'Failed to create upload directory.');
}
}
-$file_name = basename($file['name']);
+$file_extension = pathinfo($file['name'], PATHINFO_EXTENSION);
+$file_name = uniqid('doc_') . '.' . $file_extension;
$target_path = $upload_dir . $file_name;
-// Move the file to the uploads directory
if (move_uploaded_file($file['tmp_name'], $target_path)) {
- // 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;
-
- // Read the file content and base64 encode it
- $file_content = file_get_contents($target_path);
- $base64_image = base64_encode($file_content);
-
- // Check if mime_content_type function exists
- if (function_exists('mime_content_type')) {
- $mime_type = mime_content_type($target_path);
- } else {
- // Fallback to a generic MIME type if the function doesn't exist
- $mime_type = 'application/octet-stream';
- }
-
- $resp = LocalAIApi::createResponse([
- 'input' => [
- [
- 'role' => 'user',
- 'content' => [
- [
- 'type' => 'text',
- 'text' => "You are an expert document translator. Please perform the following tasks:\n" \
- . "1. **OCR Extraction:** Extract all visible text from the attached image.\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."
- ],
- [
- 'type' => 'image',
- 'source' => [
- 'type' => 'base64',
- 'media_type' => $mime_type,
- 'data' => $base64_image,
- ],
- ],
- ],
- ],
- ],
- ]);
-
- 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());
- }
-
+ $web_path = 'uploads/' . $file_name;
+ json_response(true, 'File uploaded successfully.', $web_path);
} else {
- json_response('error', 'Failed to move uploaded file.');
+ json_response(false, 'Failed to move uploaded file.');
}
-
-?>
\ No newline at end of file
+?>