sikeaditya commited on
Commit
41f3e48
·
verified ·
1 Parent(s): 33b9630

Update templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +304 -212
templates/index.html CHANGED
@@ -1,213 +1,305 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>OCR Translation - English to Hindi</title>
7
- <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css" rel="stylesheet">
8
- <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap" rel="stylesheet">
9
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
10
- <style>
11
- body {
12
- font-family: 'Poppins', sans-serif;
13
- background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
14
- }
15
- .loader {
16
- border: 3px solid #f3f3f3;
17
- border-radius: 50%;
18
- border-top: 3px solid #3498db;
19
- width: 40px;
20
- height: 40px;
21
- animation: spin 1s linear infinite;
22
- display: none;
23
- }
24
- @keyframes spin {
25
- 0% { transform: rotate(0deg); }
26
- 100% { transform: rotate(360deg); }
27
- }
28
- .drop-zone {
29
- border: 2px dashed #cbd5e0;
30
- transition: all 0.3s ease;
31
- }
32
- .drop-zone:hover {
33
- border-color: #3498db;
34
- background-color: #f8fafc;
35
- }
36
- .result-box {
37
- background: rgba(255, 255, 255, 0.9);
38
- backdrop-filter: blur(10px);
39
- transition: all 0.3s ease;
40
- }
41
- .result-box:hover {
42
- transform: translateY(-2px);
43
- box-shadow: 0 8px 20px rgba(0, 0, 0, 0.1);
44
- }
45
- .custom-file-input::-webkit-file-upload-button {
46
- visibility: hidden;
47
- width: 0;
48
- }
49
- .custom-file-input::before {
50
- content: 'Choose File';
51
- display: inline-block;
52
- background: #3498db;
53
- color: white;
54
- padding: 8px 16px;
55
- border-radius: 5px;
56
- cursor: pointer;
57
- }
58
- .translate-btn {
59
- background: linear-gradient(135deg, #3498db 0%, #2980b9 100%);
60
- transition: all 0.3s ease;
61
- }
62
- .translate-btn:hover {
63
- transform: translateY(-1px);
64
- box-shadow: 0 4px 12px rgba(52, 152, 219, 0.3);
65
- }
66
- </style>
67
- </head>
68
- <body class="min-h-screen py-12 px-4">
69
- <div class="container mx-auto max-w-4xl">
70
- <!-- Header -->
71
- <div class="text-center mb-12">
72
- <h1 class="text-4xl font-bold text-gray-800 mb-3">
73
- <i class="fas fa-language mr-2"></i>OCR Translation
74
- </h1>
75
- <p class="text-gray-600">English to Hindi Translation with Image Recognition</p>
76
- </div>
77
-
78
- <!-- Main Content -->
79
- <div class="bg-white rounded-xl shadow-lg p-8 mb-8">
80
- <!-- Upload Section -->
81
- <div class="drop-zone rounded-lg p-8 text-center mb-6">
82
- <div class="mb-4">
83
- <i class="fas fa-cloud-upload-alt text-4xl text-gray-400 mb-3"></i>
84
- <h3 class="text-lg font-semibold text-gray-700 mb-2">Upload Image</h3>
85
- <p class="text-sm text-gray-500 mb-4">Support for PNG, JPG, JPEG, GIF, BMP</p>
86
- </div>
87
-
88
- <input type="file"
89
- id="imageInput"
90
- accept="image/*"
91
- class="custom-file-input w-full mb-4 cursor-pointer">
92
-
93
- <button onclick="processImage()"
94
- class="translate-btn w-full py-3 px-6 text-white rounded-lg font-medium flex items-center justify-center">
95
- <i class="fas fa-sync-alt mr-2"></i>
96
- <span>Translate Now</span>
97
- </button>
98
-
99
- <div id="loader" class="loader mx-auto mt-4"></div>
100
- </div>
101
-
102
- <!-- Preview Section -->
103
- <div id="previewSection" class="hidden mb-6">
104
- <h3 class="text-lg font-semibold text-gray-700 mb-3">Image Preview</h3>
105
- <img id="imagePreview" class="max-w-full h-auto rounded-lg shadow" src="" alt="Preview">
106
- </div>
107
-
108
- <!-- Results Section -->
109
- <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
110
- <!-- Original Text -->
111
- <div class="result-box rounded-xl p-6">
112
- <div class="flex items-center justify-between mb-4">
113
- <h3 class="text-lg font-semibold text-gray-700">
114
- <i class="fas fa-file-alt mr-2"></i>Extracted Text
115
- </h3>
116
- <button onclick="copyText('extractedText')" class="text-blue-500 hover:text-blue-600">
117
- <i class="far fa-copy"></i>
118
- </button>
119
- </div>
120
- <div id="extractedText" class="p-4 bg-gray-50 rounded-lg min-h-[150px] text-gray-700">
121
- <!-- Extracted text will appear here -->
122
- </div>
123
- </div>
124
-
125
- <!-- Translated Text -->
126
- <div class="result-box rounded-xl p-6">
127
- <div class="flex items-center justify-between mb-4">
128
- <h3 class="text-lg font-semibold text-gray-700">
129
- <i class="fas fa-language mr-2"></i>Hindi Translation
130
- </h3>
131
- <button onclick="copyText('translatedText')" class="text-blue-500 hover:text-blue-600">
132
- <i class="far fa-copy"></i>
133
- </button>
134
- </div>
135
- <div id="translatedText" class="p-4 bg-gray-50 rounded-lg min-h-[150px] text-gray-700"
136
- style="font-family: 'Noto Sans Devanagari', sans-serif;">
137
- <!-- Translated text will appear here -->
138
- </div>
139
- </div>
140
- </div>
141
- </div>
142
- </div>
143
-
144
- <script>
145
- // Image preview functionality
146
- document.getElementById('imageInput').addEventListener('change', function(e) {
147
- const file = e.target.files[0];
148
- if (file) {
149
- const reader = new FileReader();
150
- reader.onload = function(e) {
151
- document.getElementById('imagePreview').src = e.target.result;
152
- document.getElementById('previewSection').classList.remove('hidden');
153
- }
154
- reader.readAsDataURL(file);
155
- }
156
- });
157
-
158
- // Copy text functionality
159
- function copyText(elementId) {
160
- const text = document.getElementById(elementId).textContent;
161
- navigator.clipboard.writeText(text).then(() => {
162
- // Show a brief notification
163
- const element = document.getElementById(elementId);
164
- const originalBackground = element.style.backgroundColor;
165
- element.style.backgroundColor = '#e8f5e9';
166
- setTimeout(() => {
167
- element.style.backgroundColor = originalBackground;
168
- }, 500);
169
- });
170
- }
171
-
172
- function processImage() {
173
- const fileInput = document.getElementById('imageInput');
174
- const loader = document.getElementById('loader');
175
- const extractedTextDiv = document.getElementById('extractedText');
176
- const translatedTextDiv = document.getElementById('translatedText');
177
-
178
- if (!fileInput.files[0]) {
179
- alert('Please select an image first');
180
- return;
181
- }
182
-
183
- const formData = new FormData();
184
- formData.append('file', fileInput.files[0]);
185
-
186
- // Show loader and clear previous results
187
- loader.style.display = 'block';
188
- extractedTextDiv.textContent = '';
189
- translatedTextDiv.textContent = '';
190
-
191
- fetch('/upload', {
192
- method: 'POST',
193
- body: formData
194
- })
195
- .then(response => response.json())
196
- .then(data => {
197
- if (data.error) {
198
- throw new Error(data.error);
199
- }
200
- extractedTextDiv.textContent = data.original_text;
201
- translatedTextDiv.textContent = data.translated_text;
202
- })
203
- .catch(error => {
204
- console.error('Error:', error);
205
- alert(error.message || 'An error occurred during processing');
206
- })
207
- .finally(() => {
208
- loader.style.display = 'none';
209
- });
210
- }
211
- </script>
212
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
213
  </html>
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>OCR Translation - English to Hindi</title>
7
+ <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css" rel="stylesheet">
8
+ <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap" rel="stylesheet">
9
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
10
+ <style>
11
+ body {
12
+ font-family: 'Poppins', sans-serif;
13
+ background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
14
+ }
15
+ .loader {
16
+ border: 3px solid #f3f3f3;
17
+ border-radius: 50%;
18
+ border-top: 3px solid #3498db;
19
+ width: 40px;
20
+ height: 40px;
21
+ animation: spin 1s linear infinite;
22
+ display: none;
23
+ }
24
+ @keyframes spin {
25
+ 0% { transform: rotate(0deg); }
26
+ 100% { transform: rotate(360deg); }
27
+ }
28
+ .drop-zone {
29
+ border: 2px dashed #cbd5e0;
30
+ transition: all 0.3s ease;
31
+ }
32
+ .drop-zone:hover {
33
+ border-color: #3498db;
34
+ background-color: #f8fafc;
35
+ }
36
+ .result-box {
37
+ background: rgba(255, 255, 255, 0.9);
38
+ backdrop-filter: blur(10px);
39
+ transition: all 0.3s ease;
40
+ }
41
+ .result-box:hover {
42
+ transform: translateY(-2px);
43
+ box-shadow: 0 8px 20px rgba(0, 0, 0, 0.1);
44
+ }
45
+ .custom-file-input::-webkit-file-upload-button {
46
+ visibility: hidden;
47
+ width: 0;
48
+ }
49
+ .custom-file-input::before {
50
+ content: 'Choose File';
51
+ display: inline-block;
52
+ background: #3498db;
53
+ color: white;
54
+ padding: 8px 16px;
55
+ border-radius: 5px;
56
+ cursor: pointer;
57
+ }
58
+ .translate-btn {
59
+ background: linear-gradient(135deg, #3498db 0%, #2980b9 100%);
60
+ transition: all 0.3s ease;
61
+ }
62
+ .translate-btn:hover {
63
+ transform: translateY(-1px);
64
+ box-shadow: 0 4px 12px rgba(52, 152, 219, 0.3);
65
+ }
66
+ .error-message {
67
+ background-color: #fee2e2;
68
+ border: 1px solid #ef4444;
69
+ color: #b91c1c;
70
+ padding: 10px;
71
+ border-radius: 5px;
72
+ margin-bottom: 15px;
73
+ display: none;
74
+ }
75
+ .api-status {
76
+ display: inline-flex;
77
+ align-items: center;
78
+ padding: 4px 8px;
79
+ border-radius: 4px;
80
+ font-size: 12px;
81
+ margin-left: 8px;
82
+ }
83
+ .api-status.online {
84
+ background-color: #d1fae5;
85
+ color: #065f46;
86
+ }
87
+ .api-status.offline {
88
+ background-color: #fee2e2;
89
+ color: #b91c1c;
90
+ }
91
+ </style>
92
+ </head>
93
+ <body class="min-h-screen py-12 px-4">
94
+ <div class="container mx-auto max-w-4xl">
95
+ <!-- Header -->
96
+ <div class="text-center mb-12">
97
+ <h1 class="text-4xl font-bold text-gray-800 mb-3">
98
+ <i class="fas fa-language mr-2"></i>OCR Translation
99
+ </h1>
100
+ <p class="text-gray-600">English to Hindi Translation with Image Recognition</p>
101
+ <div id="apiStatus" class="mt-2">
102
+ <span class="text-sm text-gray-500">API Status: </span>
103
+ <span id="apiStatusBadge" class="api-status offline">
104
+ <i class="fas fa-circle-notch fa-spin mr-1"></i>Checking...
105
+ </span>
106
+ </div>
107
+ </div>
108
+
109
+ <!-- Error Message Box -->
110
+ <div id="errorMessage" class="error-message mb-4">
111
+ <i class="fas fa-exclamation-circle mr-2"></i>
112
+ <span id="errorText">Error message will appear here</span>
113
+ </div>
114
+
115
+ <!-- Main Content -->
116
+ <div class="bg-white rounded-xl shadow-lg p-8 mb-8">
117
+ <!-- Upload Section -->
118
+ <div class="drop-zone rounded-lg p-8 text-center mb-6">
119
+ <div class="mb-4">
120
+ <i class="fas fa-cloud-upload-alt text-4xl text-gray-400 mb-3"></i>
121
+ <h3 class="text-lg font-semibold text-gray-700 mb-2">Upload Image</h3>
122
+ <p class="text-sm text-gray-500 mb-4">Support for PNG, JPG, JPEG, GIF, BMP</p>
123
+ </div>
124
+
125
+ <input type="file"
126
+ id="imageInput"
127
+ accept="image/*"
128
+ class="custom-file-input w-full mb-4 cursor-pointer">
129
+
130
+ <button id="translateBtn" onclick="processImage()"
131
+ class="translate-btn w-full py-3 px-6 text-white rounded-lg font-medium flex items-center justify-center">
132
+ <i class="fas fa-sync-alt mr-2"></i>
133
+ <span>Translate Now</span>
134
+ </button>
135
+
136
+ <div id="loader" class="loader mx-auto mt-4"></div>
137
+ </div>
138
+
139
+ <!-- Preview Section -->
140
+ <div id="previewSection" class="hidden mb-6">
141
+ <h3 class="text-lg font-semibold text-gray-700 mb-3">Image Preview</h3>
142
+ <img id="imagePreview" class="max-w-full h-auto rounded-lg shadow" src="" alt="Preview">
143
+ </div>
144
+
145
+ <!-- Results Section -->
146
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
147
+ <!-- Original Text -->
148
+ <div class="result-box rounded-xl p-6">
149
+ <div class="flex items-center justify-between mb-4">
150
+ <h3 class="text-lg font-semibold text-gray-700">
151
+ <i class="fas fa-file-alt mr-2"></i>Extracted Text
152
+ </h3>
153
+ <button onclick="copyText('extractedText')" class="text-blue-500 hover:text-blue-600">
154
+ <i class="far fa-copy"></i>
155
+ </button>
156
+ </div>
157
+ <div id="extractedText" class="p-4 bg-gray-50 rounded-lg min-h-[150px] text-gray-700">
158
+ <!-- Extracted text will appear here -->
159
+ </div>
160
+ </div>
161
+
162
+ <!-- Translated Text -->
163
+ <div class="result-box rounded-xl p-6">
164
+ <div class="flex items-center justify-between mb-4">
165
+ <h3 class="text-lg font-semibold text-gray-700">
166
+ <i class="fas fa-language mr-2"></i>Hindi Translation
167
+ </h3>
168
+ <button onclick="copyText('translatedText')" class="text-blue-500 hover:text-blue-600">
169
+ <i class="far fa-copy"></i>
170
+ </button>
171
+ </div>
172
+ <div id="translatedText" class="p-4 bg-gray-50 rounded-lg min-h-[150px] text-gray-700"
173
+ style="font-family: 'Noto Sans Devanagari', sans-serif;">
174
+ <!-- Translated text will appear here -->
175
+ </div>
176
+ </div>
177
+ </div>
178
+ </div>
179
+ </div>
180
+
181
+ <script>
182
+ // Check API status on page load
183
+ window.addEventListener('DOMContentLoaded', function() {
184
+ checkApiStatus();
185
+ });
186
+
187
+ function checkApiStatus() {
188
+ fetch('/api-status')
189
+ .then(response => response.json())
190
+ .then(data => {
191
+ const statusBadge = document.getElementById('apiStatusBadge');
192
+ if (data.api_working) {
193
+ statusBadge.className = 'api-status online';
194
+ statusBadge.innerHTML = '<i class="fas fa-check-circle mr-1"></i>Online';
195
+ document.getElementById('translateBtn').disabled = false;
196
+ } else {
197
+ statusBadge.className = 'api-status offline';
198
+ statusBadge.innerHTML = '<i class="fas fa-times-circle mr-1"></i>Offline';
199
+ document.getElementById('translateBtn').disabled = true;
200
+ showError('API is not working. Please check your API key or try again later.');
201
+ }
202
+ })
203
+ .catch(error => {
204
+ const statusBadge = document.getElementById('apiStatusBadge');
205
+ statusBadge.className = 'api-status offline';
206
+ statusBadge.innerHTML = '<i class="fas fa-times-circle mr-1"></i>Error';
207
+ showError('Failed to check API status: ' + error.message);
208
+ });
209
+ }
210
+
211
+ function showError(message) {
212
+ const errorDiv = document.getElementById('errorMessage');
213
+ const errorText = document.getElementById('errorText');
214
+ errorText.textContent = message;
215
+ errorDiv.style.display = 'block';
216
+ }
217
+
218
+ function hideError() {
219
+ document.getElementById('errorMessage').style.display = 'none';
220
+ }
221
+
222
+ // Image preview functionality
223
+ document.getElementById('imageInput').addEventListener('change', function(e) {
224
+ const file = e.target.files[0];
225
+ if (file) {
226
+ const reader = new FileReader();
227
+ reader.onload = function(e) {
228
+ document.getElementById('imagePreview').src = e.target.result;
229
+ document.getElementById('previewSection').classList.remove('hidden');
230
+ }
231
+ reader.readAsDataURL(file);
232
+ hideError(); // Hide any previous errors
233
+ }
234
+ });
235
+
236
+ // Copy text functionality
237
+ function copyText(elementId) {
238
+ const text = document.getElementById(elementId).textContent;
239
+ navigator.clipboard.writeText(text).then(() => {
240
+ // Show a brief notification
241
+ const element = document.getElementById(elementId);
242
+ const originalBackground = element.style.backgroundColor;
243
+ element.style.backgroundColor = '#e8f5e9';
244
+ setTimeout(() => {
245
+ element.style.backgroundColor = originalBackground;
246
+ }, 500);
247
+ });
248
+ }
249
+
250
+ function processImage() {
251
+ const fileInput = document.getElementById('imageInput');
252
+ const loader = document.getElementById('loader');
253
+ const extractedTextDiv = document.getElementById('extractedText');
254
+ const translatedTextDiv = document.getElementById('translatedText');
255
+
256
+ if (!fileInput.files[0]) {
257
+ showError('Please select an image first');
258
+ return;
259
+ }
260
+
261
+ const formData = new FormData();
262
+ formData.append('file', fileInput.files[0]);
263
+
264
+ // Hide previous errors
265
+ hideError();
266
+
267
+ // Show loader and clear previous results
268
+ loader.style.display = 'block';
269
+ extractedTextDiv.textContent = '';
270
+ translatedTextDiv.textContent = '';
271
+
272
+ fetch('/upload', {
273
+ method: 'POST',
274
+ body: formData
275
+ })
276
+ .then(response => {
277
+ if (!response.ok) {
278
+ return response.json().then(data => {
279
+ throw new Error(data.error || `Server error: ${response.status}`);
280
+ });
281
+ }
282
+ return response.json();
283
+ })
284
+ .then(data => {
285
+ extractedTextDiv.textContent = data.original_text;
286
+ translatedTextDiv.textContent = data.translated_text;
287
+
288
+ // Check if the response contains error messages
289
+ if (data.original_text && data.original_text.startsWith('Could not extract text')) {
290
+ showError(data.original_text);
291
+ }
292
+ })
293
+ .catch(error => {
294
+ console.error('Error:', error);
295
+ showError(error.message || 'An unknown error occurred');
296
+ extractedTextDiv.textContent = 'Error: Could not process image.';
297
+ translatedTextDiv.textContent = 'Translation unavailable due to processing error.';
298
+ })
299
+ .finally(() => {
300
+ loader.style.display = 'none';
301
+ });
302
+ }
303
+ </script>
304
+ </body>
305
  </html>