amine_dubs
commited on
Commit
·
a583ad7
1
Parent(s):
b7f5097
- backend/main.py +15 -7
- static/script.js +104 -128
backend/main.py
CHANGED
@@ -182,14 +182,15 @@ def translate_text(text, source_lang, target_lang):
|
|
182 |
return use_fallback_translation(text, source_lang, target_lang)
|
183 |
|
184 |
try:
|
185 |
-
#
|
186 |
-
text_to_translate = text
|
|
|
187 |
|
188 |
# Use a more reliable timeout approach with concurrent.futures
|
189 |
with concurrent.futures.ThreadPoolExecutor() as executor:
|
190 |
future = executor.submit(
|
191 |
lambda: translator(
|
192 |
-
text_to_translate,
|
193 |
max_length=768
|
194 |
)[0]["translation_text"]
|
195 |
)
|
@@ -198,17 +199,17 @@ def translate_text(text, source_lang, target_lang):
|
|
198 |
# Set a reasonable timeout
|
199 |
result = future.result(timeout=10)
|
200 |
|
201 |
-
# Post-process the result for Arabic cultural adaptation
|
202 |
if target_lang == "ar":
|
203 |
result = culturally_adapt_arabic(result)
|
204 |
|
|
|
205 |
return result
|
206 |
except concurrent.futures.TimeoutError:
|
207 |
print(f"Model inference timed out after 10 seconds, falling back to online translation")
|
208 |
return use_fallback_translation(text, source_lang, target_lang)
|
209 |
except Exception as e:
|
210 |
print(f"Error during model inference: {e}")
|
211 |
-
|
212 |
# If the model failed during inference, try to re-initialize it for next time
|
213 |
# but use fallback for this request
|
214 |
initialize_model()
|
@@ -440,27 +441,34 @@ async def translate_document_endpoint(
|
|
440 |
target_lang: str = Form("ar")
|
441 |
):
|
442 |
"""Translates text extracted from an uploaded document."""
|
|
|
443 |
try:
|
444 |
# Extract text directly from the uploaded file
|
|
|
445 |
extracted_text = await extract_text_from_file(file)
|
446 |
|
447 |
if not extracted_text:
|
|
|
448 |
raise HTTPException(status_code=400, detail="Could not extract any text from the document.")
|
449 |
|
450 |
-
# Translate the extracted text
|
|
|
451 |
translated_text = translate_text(extracted_text, source_lang, target_lang)
|
452 |
|
|
|
453 |
return JSONResponse(content={
|
454 |
"original_filename": file.filename,
|
455 |
-
"detected_source_lang": source_lang,
|
456 |
"translated_text": translated_text
|
457 |
})
|
458 |
|
459 |
except HTTPException as http_exc:
|
|
|
460 |
raise http_exc
|
461 |
except Exception as e:
|
462 |
print(f"Document translation error: {e}")
|
463 |
traceback.print_exc()
|
|
|
464 |
raise HTTPException(status_code=500, detail=f"Document translation error: {str(e)}")
|
465 |
|
466 |
# --- Run the server (for local development) ---
|
|
|
182 |
return use_fallback_translation(text, source_lang, target_lang)
|
183 |
|
184 |
try:
|
185 |
+
# Ensure only the raw text is sent to the Helsinki model
|
186 |
+
text_to_translate = text
|
187 |
+
print(f"Translating text (first 50 chars): {text_to_translate[:50]}...") # Log the actual text being sent
|
188 |
|
189 |
# Use a more reliable timeout approach with concurrent.futures
|
190 |
with concurrent.futures.ThreadPoolExecutor() as executor:
|
191 |
future = executor.submit(
|
192 |
lambda: translator(
|
193 |
+
text_to_translate, # Pass only the raw text
|
194 |
max_length=768
|
195 |
)[0]["translation_text"]
|
196 |
)
|
|
|
199 |
# Set a reasonable timeout
|
200 |
result = future.result(timeout=10)
|
201 |
|
202 |
+
# Post-process the result for Arabic cultural adaptation if needed
|
203 |
if target_lang == "ar":
|
204 |
result = culturally_adapt_arabic(result)
|
205 |
|
206 |
+
print(f"Translation successful (first 50 chars): {result[:50]}...")
|
207 |
return result
|
208 |
except concurrent.futures.TimeoutError:
|
209 |
print(f"Model inference timed out after 10 seconds, falling back to online translation")
|
210 |
return use_fallback_translation(text, source_lang, target_lang)
|
211 |
except Exception as e:
|
212 |
print(f"Error during model inference: {e}")
|
|
|
213 |
# If the model failed during inference, try to re-initialize it for next time
|
214 |
# but use fallback for this request
|
215 |
initialize_model()
|
|
|
441 |
target_lang: str = Form("ar")
|
442 |
):
|
443 |
"""Translates text extracted from an uploaded document."""
|
444 |
+
print("[DEBUG] /translate/document endpoint called (Updated Code Check)") # Added log
|
445 |
try:
|
446 |
# Extract text directly from the uploaded file
|
447 |
+
print(f"[DEBUG] Processing file: {file.filename}, Source: {source_lang}, Target: {target_lang}")
|
448 |
extracted_text = await extract_text_from_file(file)
|
449 |
|
450 |
if not extracted_text:
|
451 |
+
print("[DEBUG] No text extracted from document.")
|
452 |
raise HTTPException(status_code=400, detail="Could not extract any text from the document.")
|
453 |
|
454 |
+
# Translate the extracted text using the updated translate_text function
|
455 |
+
print("[DEBUG] Calling translate_text for document content...")
|
456 |
translated_text = translate_text(extracted_text, source_lang, target_lang)
|
457 |
|
458 |
+
print(f"[DEBUG] Document translation successful. Returning result for {file.filename}")
|
459 |
return JSONResponse(content={
|
460 |
"original_filename": file.filename,
|
461 |
+
"detected_source_lang": source_lang, # Assuming source_lang is detected or provided correctly
|
462 |
"translated_text": translated_text
|
463 |
})
|
464 |
|
465 |
except HTTPException as http_exc:
|
466 |
+
# Re-raise HTTPExceptions directly
|
467 |
raise http_exc
|
468 |
except Exception as e:
|
469 |
print(f"Document translation error: {e}")
|
470 |
traceback.print_exc()
|
471 |
+
# Return a generic error response
|
472 |
raise HTTPException(status_code=500, detail=f"Document translation error: {str(e)}")
|
473 |
|
474 |
# --- Run the server (for local development) ---
|
static/script.js
CHANGED
@@ -2,142 +2,119 @@
|
|
2 |
window.onload = function() {
|
3 |
console.log('Window fully loaded, initializing translation app');
|
4 |
|
5 |
-
// Get form elements
|
6 |
const textTranslationForm = document.querySelector('#text-translation-form');
|
7 |
const docTranslationForm = document.querySelector('#doc-translation-form');
|
8 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
// Set up text translation form
|
10 |
-
|
11 |
-
|
|
|
|
|
12 |
|
13 |
-
//
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
54 |
}
|
55 |
|
56 |
-
|
57 |
-
|
58 |
-
// Debugging: Log which specific elements are missing
|
59 |
-
console.error('Missing elements:', {
|
60 |
-
textInput: textInput,
|
61 |
-
sourceLang: sourceLang,
|
62 |
-
targetLang: targetLang
|
63 |
-
});
|
64 |
-
showError('Form elements not found. Please check the HTML structure and console logs.');
|
65 |
-
return;
|
66 |
}
|
67 |
|
68 |
-
//
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
return;
|
73 |
}
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
if (
|
81 |
-
|
82 |
-
// Create payload
|
83 |
-
const payload = {
|
84 |
-
text: text,
|
85 |
-
source_lang: sourceLangValue,
|
86 |
-
target_lang: targetLangValue
|
87 |
-
};
|
88 |
-
|
89 |
-
console.log('Sending payload:', payload);
|
90 |
-
|
91 |
-
// Send API request
|
92 |
-
fetch('/translate/text', {
|
93 |
-
method: 'POST',
|
94 |
-
headers: { 'Content-Type': 'application/json' },
|
95 |
-
body: JSON.stringify(payload)
|
96 |
-
})
|
97 |
-
.then(function(response) {
|
98 |
-
if (!response.ok) throw new Error('Server error: ' + response.status);
|
99 |
-
return response.text();
|
100 |
-
})
|
101 |
-
.then(function(responseText) {
|
102 |
-
console.log('Response received:', responseText);
|
103 |
-
|
104 |
-
// Try to parse JSON
|
105 |
-
let data;
|
106 |
-
try {
|
107 |
-
data = JSON.parse(responseText);
|
108 |
-
} catch (error) {
|
109 |
-
throw new Error('Invalid response from server');
|
110 |
-
}
|
111 |
-
|
112 |
-
// Check for translation
|
113 |
-
if (!data.translated_text) {
|
114 |
-
throw new Error('No translation returned');
|
115 |
-
}
|
116 |
-
|
117 |
-
// Show result
|
118 |
-
const resultBox = document.querySelector('#text-result');
|
119 |
-
const outputElement = document.querySelector('#text-output');
|
120 |
-
|
121 |
-
if (resultBox && outputElement) {
|
122 |
-
outputElement.textContent = data.translated_text;
|
123 |
-
resultBox.style.display = 'block';
|
124 |
-
}
|
125 |
-
})
|
126 |
-
.catch(function(error) {
|
127 |
-
showError(error.message || 'Translation failed');
|
128 |
-
console.error('Error:', error);
|
129 |
-
})
|
130 |
-
.finally(function() {
|
131 |
-
if (loadingElement) loadingElement.style.display = 'none';
|
132 |
-
});
|
133 |
});
|
134 |
-
}
|
135 |
-
console.error('Text translation form not found in the document!');
|
136 |
-
}
|
137 |
|
138 |
// Document translation handler
|
139 |
if (docTranslationForm) {
|
140 |
-
console.log('Document translation form found');
|
141 |
docTranslationForm.addEventListener('submit', function(event) {
|
142 |
event.preventDefault();
|
143 |
console.log('Document translation form submitted');
|
@@ -201,16 +178,15 @@ window.onload = function() {
|
|
201 |
});
|
202 |
});
|
203 |
} else {
|
204 |
-
console.error('Document translation form not found
|
205 |
}
|
206 |
|
207 |
// Helper function to show errors
|
208 |
function showError(message) {
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
errorDiv.style.display = 'block';
|
213 |
}
|
214 |
-
console.error('Error:', message);
|
215 |
}
|
216 |
};
|
|
|
2 |
window.onload = function() {
|
3 |
console.log('Window fully loaded, initializing translation app');
|
4 |
|
5 |
+
// Get form elements ONCE after load
|
6 |
const textTranslationForm = document.querySelector('#text-translation-form');
|
7 |
const docTranslationForm = document.querySelector('#doc-translation-form');
|
8 |
|
9 |
+
// Get text form INPUT elements ONCE
|
10 |
+
const textInput = document.getElementById('text-input');
|
11 |
+
const sourceLangText = document.getElementById('source-lang-text');
|
12 |
+
const targetLangText = document.getElementById('target-lang-text');
|
13 |
+
const textLoadingElement = document.getElementById('text-loading');
|
14 |
+
const debugElement = document.getElementById('debug-info');
|
15 |
+
const errorElement = document.getElementById('error-message');
|
16 |
+
const textResultBox = document.getElementById('text-result');
|
17 |
+
const textOutputElement = document.getElementById('text-output');
|
18 |
+
|
19 |
+
// Check if essential text elements were found on load
|
20 |
+
if (!textTranslationForm || !textInput || !sourceLangText || !targetLangText) {
|
21 |
+
console.error('CRITICAL: Essential text form elements not found on window load!', {
|
22 |
+
form: !!textTranslationForm,
|
23 |
+
input: !!textInput,
|
24 |
+
source: !!sourceLangText,
|
25 |
+
target: !!targetLangText
|
26 |
+
});
|
27 |
+
if (errorElement) {
|
28 |
+
errorElement.textContent = 'Error: Could not find essential text translation form elements. Check HTML IDs.';
|
29 |
+
errorElement.style.display = 'block';
|
30 |
+
}
|
31 |
+
// Optionally disable the form if elements are missing
|
32 |
+
if (textTranslationForm) textTranslationForm.style.opacity = '0.5';
|
33 |
+
return; // Stop further initialization if critical elements missing
|
34 |
+
}
|
35 |
+
|
36 |
// Set up text translation form
|
37 |
+
console.log('Text translation form and elements found on load');
|
38 |
+
textTranslationForm.addEventListener('submit', function(event) {
|
39 |
+
event.preventDefault();
|
40 |
+
console.log('Text translation form submitted');
|
41 |
|
42 |
+
// Hide previous results/errors
|
43 |
+
if (textResultBox) textResultBox.style.display = 'none';
|
44 |
+
if (errorElement) errorElement.style.display = 'none';
|
45 |
+
if (debugElement) debugElement.style.display = 'none';
|
46 |
+
|
47 |
+
// **Crucial Check:** Verify elements still exist before use
|
48 |
+
if (!textInput || !sourceLangText || !targetLangText) {
|
49 |
+
console.error('ERROR: Text form elements became null before accessing value!');
|
50 |
+
showError('Internal error: Form elements missing unexpectedly.');
|
51 |
+
return;
|
52 |
+
}
|
53 |
+
|
54 |
+
// Get values
|
55 |
+
const text = textInput.value ? textInput.value.trim() : '';
|
56 |
+
if (!text) {
|
57 |
+
showError('Please enter text to translate');
|
58 |
+
return;
|
59 |
+
}
|
60 |
+
|
61 |
+
const sourceLangValue = sourceLangText.value;
|
62 |
+
const targetLangValue = targetLangText.value;
|
63 |
+
|
64 |
+
// Show loading indicator
|
65 |
+
if (textLoadingElement) textLoadingElement.style.display = 'block';
|
66 |
+
|
67 |
+
// Create payload
|
68 |
+
const payload = {
|
69 |
+
text: text,
|
70 |
+
source_lang: sourceLangValue,
|
71 |
+
target_lang: targetLangValue
|
72 |
+
};
|
73 |
+
|
74 |
+
console.log('Sending payload:', payload);
|
75 |
+
|
76 |
+
// Send API request
|
77 |
+
fetch('/translate/text', {
|
78 |
+
method: 'POST',
|
79 |
+
headers: { 'Content-Type': 'application/json' },
|
80 |
+
body: JSON.stringify(payload)
|
81 |
+
})
|
82 |
+
.then(response => {
|
83 |
+
if (!response.ok) throw new Error('Server error: ' + response.status);
|
84 |
+
return response.text(); // Get raw text first
|
85 |
+
})
|
86 |
+
.then(responseText => {
|
87 |
+
console.log('Response received:', responseText);
|
88 |
+
let data;
|
89 |
+
try {
|
90 |
+
data = JSON.parse(responseText);
|
91 |
+
} catch (error) {
|
92 |
+
console.error("Failed to parse JSON:", responseText);
|
93 |
+
throw new Error('Invalid response format from server');
|
94 |
}
|
95 |
|
96 |
+
if (!data.success || !data.translated_text) {
|
97 |
+
throw new Error(data.error || 'No translation returned or success flag false');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
98 |
}
|
99 |
|
100 |
+
// Show result
|
101 |
+
if (textResultBox && textOutputElement) {
|
102 |
+
textOutputElement.textContent = data.translated_text;
|
103 |
+
textResultBox.style.display = 'block';
|
|
|
104 |
}
|
105 |
+
})
|
106 |
+
.catch(error => {
|
107 |
+
showError(error.message || 'Translation failed');
|
108 |
+
console.error('Error:', error);
|
109 |
+
})
|
110 |
+
.finally(() => {
|
111 |
+
if (textLoadingElement) textLoadingElement.style.display = 'none';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
112 |
});
|
113 |
+
});
|
|
|
|
|
114 |
|
115 |
// Document translation handler
|
116 |
if (docTranslationForm) {
|
117 |
+
console.log('Document translation form found on load');
|
118 |
docTranslationForm.addEventListener('submit', function(event) {
|
119 |
event.preventDefault();
|
120 |
console.log('Document translation form submitted');
|
|
|
178 |
});
|
179 |
});
|
180 |
} else {
|
181 |
+
console.error('Document translation form not found on load!');
|
182 |
}
|
183 |
|
184 |
// Helper function to show errors
|
185 |
function showError(message) {
|
186 |
+
if (errorElement) {
|
187 |
+
errorElement.textContent = 'Error: ' + message;
|
188 |
+
errorElement.style.display = 'block';
|
|
|
189 |
}
|
190 |
+
console.error('Error displayed:', message);
|
191 |
}
|
192 |
};
|