amine_dubs commited on
Commit
c49ad44
·
1 Parent(s): 3a2e47e
backend/main.py CHANGED
@@ -404,104 +404,18 @@ async def translate_text_endpoint(request: TranslationRequest):
404
 
405
  print(f"[DEBUG] Received request: source_lang={source_lang}, target_lang={target_lang}, text={text[:50]}")
406
 
407
- translation_result = ""
408
- error_message = None
409
 
410
- try:
411
- # Check if translator is initialized, if not, initialize it
412
- if translator is None:
413
- print("[DEBUG] Translator not initialized. Attempting to initialize model...")
414
- success = initialize_model()
415
- if not success:
416
- raise Exception("Failed to initialize translation model")
417
-
418
- # Format the prompt for the model
419
- src_lang_code = f"{source_lang}_Latn" if source_lang != "ar" else f"{source_lang}_Arab"
420
- tgt_lang_code = f"{target_lang}_Latn" if target_lang != "ar" else f"{target_lang}_Arab"
421
-
422
- print("[DEBUG] Calling translator model...")
423
- # Use a thread pool to execute the translation with a timeout
424
- with concurrent.futures.ThreadPoolExecutor() as executor:
425
- future = executor.submit(
426
- lambda: translator(
427
- text,
428
- src_lang=src_lang_code,
429
- tgt_lang=tgt_lang_code,
430
- max_length=512
431
- )[0]["translation_text"]
432
- )
433
-
434
- try:
435
- result = future.result(timeout=15)
436
- translation_result = result
437
- print(f"Local model translation result: {translation_result}")
438
- except concurrent.futures.TimeoutError:
439
- print("Translation timed out after 15 seconds")
440
- raise Exception("Translation timed out")
441
- except Exception as e:
442
- print(f"Error using local model: {str(e)}")
443
- raise Exception(f"Error using local model: {str(e)}")
444
-
445
- except Exception as e:
446
- error_message = str(e)
447
- print(f"Error using local model: {error_message}")
448
 
449
- # Try the fallback options
450
- try:
451
- # Try LibreTranslate providers
452
- libre_apis = [
453
- "https://translate.terraprint.co/translate",
454
- "https://libretranslate.de/translate",
455
- "https://translate.argosopentech.com/translate",
456
- "https://translate.fedilab.app/translate"
457
- ]
458
-
459
- for api_url in libre_apis:
460
- try:
461
- print(f"Attempting fallback translation using LibreTranslate: {api_url}")
462
- payload = {
463
- "q": text,
464
- "source": source_lang,
465
- "target": target_lang,
466
- "format": "text",
467
- "api_key": ""
468
- }
469
- headers = {"Content-Type": "application/json"}
470
- response = requests.post(api_url, json=payload, headers=headers, timeout=5)
471
-
472
- if response.status_code == 200:
473
- result = response.json()
474
- if "translatedText" in result:
475
- translation_result = result["translatedText"]
476
- print(f"LibreTranslate successful: {translation_result}")
477
- break
478
- except Exception as libre_error:
479
- print(f"Error with LibreTranslate {api_url}: {str(libre_error)}")
480
-
481
- # If LibreTranslate failed, try Google Translate
482
- if not translation_result:
483
- try:
484
- # First try to import it
485
- try:
486
- from googletrans import Translator
487
- google_translator = Translator()
488
- result = google_translator.translate(text, src=source_lang, dest=target_lang)
489
- translation_result = result.text
490
- print(f"Google Translate successful: {translation_result}")
491
- except ImportError:
492
- print("googletrans package not installed, attempting to install...")
493
- subprocess.call([sys.executable, "-m", "pip", "install", "googletrans==4.0.0-rc1"])
494
- # After installation, try again
495
- from googletrans import Translator
496
- google_translator = Translator()
497
- result = google_translator.translate(text, src=source_lang, dest=target_lang)
498
- translation_result = result.text
499
- except Exception as google_error:
500
- print(f"Error with Google Translate fallback: {str(google_error)}")
501
- except Exception as e:
502
- print(f"Error with fallback translation: {str(e)}")
503
- translation_result = f"[Translation failed during fallback] {text}"
504
-
505
  return {"success": True, "translated_text": translation_result}
506
 
507
  except Exception as e:
 
404
 
405
  print(f"[DEBUG] Received request: source_lang={source_lang}, target_lang={target_lang}, text={text[:50]}")
406
 
407
+ # Call our culturally-aware translate_text function
408
+ translation_result = translate_text(text, source_lang, target_lang)
409
 
410
+ # Check for empty result
411
+ if not translation_result or translation_result.strip() == "":
412
+ print("[DEBUG] Empty translation result received")
413
+ return JSONResponse(
414
+ status_code=500,
415
+ content={"success": False, "error": "Translation returned empty result"}
416
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
417
 
418
+ print(f"[DEBUG] Translation successful: {translation_result[:100]}...")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
419
  return {"success": True, "translated_text": translation_result}
420
 
421
  except Exception as e:
backend/requirements.txt CHANGED
@@ -12,3 +12,6 @@ tensorflow
12
  tf-keras
13
  hf_xet
14
  accelerate
 
 
 
 
12
  tf-keras
13
  hf_xet
14
  accelerate
15
+ docx
16
+ BytesIO
17
+ fitz
static/script.js CHANGED
@@ -9,6 +9,21 @@ document.addEventListener('DOMContentLoaded', () => {
9
  const docSourceLang = document.getElementById('doc-source-lang');
10
  const errorMessageDiv = document.getElementById('error-message');
11
  const docLoadingIndicator = document.getElementById('doc-loading');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
  // Helper function to display errors
14
  function displayError(message) {
@@ -38,6 +53,7 @@ document.addEventListener('DOMContentLoaded', () => {
38
  console.error("Error details:", message);
39
  errorMessageDiv.textContent = errorText;
40
  errorMessageDiv.style.display = 'block';
 
41
  // Hide result boxes on error
42
  textResultBox.style.display = 'none';
43
  docResultBox.style.display = 'none';
@@ -54,9 +70,11 @@ document.addEventListener('DOMContentLoaded', () => {
54
  docFilename.textContent = '';
55
  docSourceLang.textContent = '';
56
  docLoadingIndicator.style.display = 'none';
 
 
57
  }
58
 
59
- // Fix the text form submission handler to use correct field IDs
60
  if (textForm) {
61
  textForm.addEventListener('submit', async (e) => {
62
  e.preventDefault();
@@ -73,39 +91,42 @@ document.addEventListener('DOMContentLoaded', () => {
73
  }
74
 
75
  try {
76
- // Show loading state (create it if missing)
77
- let textLoading = document.getElementById('text-loading');
78
- if (!textLoading) {
79
- textLoading = document.createElement('div');
80
- textLoading.id = 'text-loading';
81
- textLoading.className = 'loading-spinner';
82
- textLoading.innerHTML = 'Translating...';
83
- textForm.appendChild(textLoading);
84
- }
85
- textLoading.style.display = 'block';
86
 
87
  // Log payload for debugging
88
- console.log('Sending payload:', { text: sourceText, source_lang: sourceLang, target_lang: targetLang });
 
 
 
 
 
89
 
90
  const response = await fetch('/translate/text', {
91
  method: 'POST',
92
  headers: {
93
  'Content-Type': 'application/json'
94
  },
95
- body: JSON.stringify({
96
- text: sourceText,
97
- source_lang: sourceLang,
98
- target_lang: targetLang
99
- })
100
  });
101
 
102
- // Hide loading state
103
- textLoading.style.display = 'none';
104
-
105
  // Log response status
106
- console.log('Response status:', response.status);
107
 
108
- const data = await response.json();
 
 
 
 
 
 
 
 
 
 
 
 
 
109
 
110
  if (!response.ok) {
111
  if (data && data.error) {
@@ -131,80 +152,85 @@ document.addEventListener('DOMContentLoaded', () => {
131
 
132
  } catch (error) {
133
  console.error('Error:', error);
134
- displayError('Network error or invalid response format');
135
 
136
- // Hide loading if it exists
137
- const textLoading = document.getElementById('text-loading');
138
- if (textLoading) textLoading.style.display = 'none';
139
  }
140
  });
 
 
141
  }
142
 
143
  // Handle Document Translation Form Submission
144
- docForm.addEventListener('submit', async (event) => {
145
- event.preventDefault();
146
- clearFeedback();
147
-
148
- const formData = new FormData(docForm);
149
- const fileInput = document.getElementById('doc-input');
150
- const button = docForm.querySelector('button');
151
 
152
- if (!fileInput.files || fileInput.files.length === 0) {
153
- displayError('Please select a document to upload.');
154
- return;
155
- }
156
 
157
- button.disabled = true;
158
- button.textContent = 'Translating...';
159
- // Show loading indicator
160
- docLoadingIndicator.style.display = 'block';
161
 
162
- try {
163
- const response = await fetch('/translate/document', {
164
- method: 'POST',
165
- body: formData // FormData handles multipart/form-data automatically
166
- });
167
 
168
- // Get response as text first for debugging
169
- const responseText = await response.text();
170
- console.log('Raw document response:', responseText);
171
-
172
- // Try to parse as JSON
173
- let result;
174
  try {
175
- result = JSON.parse(responseText);
176
- } catch (jsonError) {
177
- throw new Error(`Failed to parse server response: ${responseText}`);
178
- }
179
 
180
- if (!response.ok) {
181
- const errorMessage = result.error || result.detail || `HTTP error! status: ${response.status}`;
182
- throw new Error(errorMessage);
183
- }
184
-
185
- console.log('Document translation response:', result);
186
-
187
- // Check if result contains the expected fields
188
- if (!result.translated_text) {
189
- throw new Error('Translation response is missing translated text');
190
- }
191
-
192
- docFilename.textContent = result.original_filename || 'N/A';
193
- docSourceLang.textContent = result.detected_source_lang || 'N/A';
194
- docOutput.textContent = result.translated_text;
195
- docResultBox.style.display = 'block';
196
-
197
- // Set text direction based on target language (document always goes to Arabic)
198
- docOutput.dir = 'rtl';
199
 
200
- } catch (error) {
201
- console.error('Document translation error:', error);
202
- displayError(error.message || 'An unexpected error occurred during document translation.');
203
- } finally {
204
- button.disabled = false;
205
- button.textContent = 'Translate Document';
206
- // Hide loading indicator
207
- docLoadingIndicator.style.display = 'none';
208
- }
209
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
210
  });
 
9
  const docSourceLang = document.getElementById('doc-source-lang');
10
  const errorMessageDiv = document.getElementById('error-message');
11
  const docLoadingIndicator = document.getElementById('doc-loading');
12
+ const debugInfoDiv = document.getElementById('debug-info');
13
+ const textLoadingDiv = document.getElementById('text-loading');
14
+
15
+ // Helper function to display debug info
16
+ function showDebug(message, data = null) {
17
+ let debugText = typeof message === 'string' ? message : JSON.stringify(message);
18
+
19
+ if (data) {
20
+ debugText += '\n' + JSON.stringify(data, null, 2);
21
+ }
22
+
23
+ console.log("DEBUG:", message, data || '');
24
+ debugInfoDiv.textContent = debugText;
25
+ debugInfoDiv.style.display = 'block';
26
+ }
27
 
28
  // Helper function to display errors
29
  function displayError(message) {
 
53
  console.error("Error details:", message);
54
  errorMessageDiv.textContent = errorText;
55
  errorMessageDiv.style.display = 'block';
56
+
57
  // Hide result boxes on error
58
  textResultBox.style.display = 'none';
59
  docResultBox.style.display = 'none';
 
70
  docFilename.textContent = '';
71
  docSourceLang.textContent = '';
72
  docLoadingIndicator.style.display = 'none';
73
+ debugInfoDiv.style.display = 'none';
74
+ debugInfoDiv.textContent = '';
75
  }
76
 
77
+ // Fix the text form submission handler
78
  if (textForm) {
79
  textForm.addEventListener('submit', async (e) => {
80
  e.preventDefault();
 
91
  }
92
 
93
  try {
94
+ // Show loading state
95
+ textLoadingDiv.style.display = 'block';
 
 
 
 
 
 
 
 
96
 
97
  // Log payload for debugging
98
+ const payload = {
99
+ text: sourceText,
100
+ source_lang: sourceLang,
101
+ target_lang: targetLang
102
+ };
103
+ showDebug('Sending translation request', payload);
104
 
105
  const response = await fetch('/translate/text', {
106
  method: 'POST',
107
  headers: {
108
  'Content-Type': 'application/json'
109
  },
110
+ body: JSON.stringify(payload)
 
 
 
 
111
  });
112
 
 
 
 
113
  // Log response status
114
+ showDebug(`Response status: ${response.status}`);
115
 
116
+ // Get the raw response text first for debugging
117
+ const responseText = await response.text();
118
+ showDebug('Raw response:', responseText);
119
+
120
+ // Then parse it as JSON
121
+ let data;
122
+ try {
123
+ data = JSON.parse(responseText);
124
+ } catch (jsonError) {
125
+ throw new Error(`Invalid JSON response: ${responseText}`);
126
+ }
127
+
128
+ // Hide loading state
129
+ textLoadingDiv.style.display = 'none';
130
 
131
  if (!response.ok) {
132
  if (data && data.error) {
 
152
 
153
  } catch (error) {
154
  console.error('Error:', error);
155
+ displayError(`Network error: ${error.message}`);
156
 
157
+ // Hide loading
158
+ textLoadingDiv.style.display = 'none';
 
159
  }
160
  });
161
+ } else {
162
+ console.error("Text translation form not found in the document!");
163
  }
164
 
165
  // Handle Document Translation Form Submission
166
+ if (docForm) {
167
+ docForm.addEventListener('submit', async (event) => {
168
+ event.preventDefault();
169
+ clearFeedback();
 
 
 
170
 
171
+ const formData = new FormData(docForm);
172
+ const fileInput = document.getElementById('doc-input');
173
+ const button = docForm.querySelector('button');
 
174
 
175
+ if (!fileInput.files || fileInput.files.length === 0) {
176
+ displayError('Please select a document to upload.');
177
+ return;
178
+ }
179
 
180
+ button.disabled = true;
181
+ button.textContent = 'Translating...';
182
+ // Show loading indicator
183
+ docLoadingIndicator.style.display = 'block';
 
184
 
 
 
 
 
 
 
185
  try {
186
+ const response = await fetch('/translate/document', {
187
+ method: 'POST',
188
+ body: formData // FormData handles multipart/form-data automatically
189
+ });
190
 
191
+ // Get response as text first for debugging
192
+ const responseText = await response.text();
193
+ showDebug('Raw document response:', responseText);
194
+
195
+ // Try to parse as JSON
196
+ let result;
197
+ try {
198
+ result = JSON.parse(responseText);
199
+ } catch (jsonError) {
200
+ throw new Error(`Failed to parse server response: ${responseText}`);
201
+ }
 
 
 
 
 
 
 
 
202
 
203
+ if (!response.ok) {
204
+ const errorMessage = result.error || result.detail || `HTTP error! status: ${response.status}`;
205
+ throw new Error(errorMessage);
206
+ }
207
+
208
+ showDebug('Document translation response:', result);
209
+
210
+ // Check if result contains the expected fields
211
+ if (!result.translated_text) {
212
+ throw new Error('Translation response is missing translated text');
213
+ }
214
+
215
+ docFilename.textContent = result.original_filename || 'N/A';
216
+ docSourceLang.textContent = result.detected_source_lang || 'N/A';
217
+ docOutput.textContent = result.translated_text;
218
+ docResultBox.style.display = 'block';
219
+
220
+ // Set text direction based on target language (document always goes to Arabic)
221
+ docOutput.dir = 'rtl';
222
+
223
+ } catch (error) {
224
+ console.error('Document translation error:', error);
225
+ displayError(error.message || 'An unexpected error occurred during document translation.');
226
+ } finally {
227
+ button.disabled = false;
228
+ button.textContent = 'Translate Document';
229
+ // Hide loading indicator
230
+ docLoadingIndicator.style.display = 'none';
231
+ }
232
+ });
233
+ } else {
234
+ console.error("Document translation form not found in the document!");
235
+ }
236
  });
templates/index.html CHANGED
@@ -5,6 +5,44 @@
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>AI Translator</title>
7
  <link rel="stylesheet" href="/static/style.css">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  </head>
9
  <body>
10
  <h1>AI Translation Service</h1>
@@ -33,6 +71,7 @@
33
  </select>
34
  </div>
35
  <textarea id="text-input" name="text" placeholder="Enter text to translate..."></textarea>
 
36
  <button type="submit">Translate Text</button>
37
  </form>
38
  <div id="text-result" class="result-box" dir="rtl"> <!- Set default to RTL for Arabic output ->
@@ -41,6 +80,10 @@
41
  </div>
42
  </div>
43
 
 
 
 
 
44
  <div class="container">
45
  <h2>Document Translation</h2>
46
  <form id="doc-translation-form" enctype="multipart/form-data">
@@ -86,8 +129,6 @@
86
  </div>
87
  </div>
88
 
89
- <div id="error-message" class="error-box" style="display: none;"></div>
90
-
91
  <script src="/static/script.js"></script>
92
  </body>
93
  </html>
 
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>AI Translator</title>
7
  <link rel="stylesheet" href="/static/style.css">
8
+ <style>
9
+ /* Add some styling for better visibility of debug and error messages */
10
+ #error-message {
11
+ background-color: #ffebee;
12
+ color: #c62828;
13
+ padding: 10px;
14
+ margin: 10px 0;
15
+ border-radius: 4px;
16
+ border: 1px solid #ef9a9a;
17
+ display: none;
18
+ }
19
+ #debug-info {
20
+ background-color: #e3f2fd;
21
+ color: #1565c0;
22
+ padding: 10px;
23
+ margin: 10px 0;
24
+ border-radius: 4px;
25
+ border: 1px solid #90caf9;
26
+ font-family: monospace;
27
+ white-space: pre-wrap;
28
+ display: none;
29
+ }
30
+ .loading-spinner {
31
+ margin: 10px 0;
32
+ padding: 10px;
33
+ background-color: #e8f5e9;
34
+ border-radius: 4px;
35
+ border: 1px solid #a5d6a7;
36
+ display: none;
37
+ }
38
+ .result-box {
39
+ margin-top: 20px;
40
+ padding: 15px;
41
+ background-color: #f5f5f5;
42
+ border-radius: 4px;
43
+ display: none;
44
+ }
45
+ </style>
46
  </head>
47
  <body>
48
  <h1>AI Translation Service</h1>
 
71
  </select>
72
  </div>
73
  <textarea id="text-input" name="text" placeholder="Enter text to translate..."></textarea>
74
+ <div id="text-loading" class="loading-spinner">Translating...</div>
75
  <button type="submit">Translate Text</button>
76
  </form>
77
  <div id="text-result" class="result-box" dir="rtl"> <!- Set default to RTL for Arabic output ->
 
80
  </div>
81
  </div>
82
 
83
+ <!-- Add debug info container -->
84
+ <div id="debug-info"></div>
85
+ <div id="error-message" class="error-box"></div>
86
+
87
  <div class="container">
88
  <h2>Document Translation</h2>
89
  <form id="doc-translation-form" enctype="multipart/form-data">
 
129
  </div>
130
  </div>
131
 
 
 
132
  <script src="/static/script.js"></script>
133
  </body>
134
  </html>