| | <!DOCTYPE html> |
| | <html lang="vi"> |
| | <head> |
| | <meta charset="UTF-8"> |
| | <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| | <title>Trích xuất văn bản Đa Ngôn Ngữ</title> |
| | <style> |
| | body { |
| | font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; |
| | background-color: #f0f2f5; |
| | display: flex; |
| | justify-content: center; |
| | padding: 40px 20px; |
| | margin: 0; |
| | } |
| | .container { |
| | background: white; |
| | padding: 30px; |
| | border-radius: 12px; |
| | box-shadow: 0 4px 12px rgba(0,0,0,0.1); |
| | max-width: 500px; |
| | width: 100%; |
| | text-align: center; |
| | } |
| | h2 { color: #333; margin-bottom: 20px; } |
| | |
| | |
| | .lang-selector { |
| | margin-bottom: 20px; |
| | text-align: left; |
| | } |
| | .lang-selector label { |
| | font-weight: 600; |
| | color: #555; |
| | display: block; |
| | margin-bottom: 8px; |
| | } |
| | .lang-selector select { |
| | width: 100%; |
| | padding: 10px; |
| | border-radius: 6px; |
| | border: 1px solid #ccc; |
| | font-size: 16px; |
| | outline: none; |
| | } |
| | |
| | .upload-area { |
| | border: 2px dashed #ccc; |
| | padding: 20px; |
| | border-radius: 8px; |
| | cursor: pointer; |
| | margin-bottom: 20px; |
| | transition: 0.3s; |
| | display: block; |
| | } |
| | .upload-area:hover { border-color: #007bff; background: #f8fbff; } |
| | input[type="file"] { display: none; } |
| | .preview-img { |
| | max-width: 100%; |
| | max-height: 300px; |
| | border-radius: 8px; |
| | display: none; |
| | margin: 10px auto; |
| | } |
| | button { |
| | background-color: #007bff; |
| | color: white; |
| | border: none; |
| | padding: 12px 24px; |
| | border-radius: 6px; |
| | font-size: 16px; |
| | cursor: pointer; |
| | width: 100%; |
| | transition: 0.3s; |
| | } |
| | button:hover { background-color: #0056b3; } |
| | button:disabled { background-color: #cccccc; cursor: not-allowed; } |
| | .result-box { |
| | margin-top: 20px; |
| | padding: 15px; |
| | background: #e9ecef; |
| | border-radius: 8px; |
| | text-align: left; |
| | min-height: 80px; |
| | white-space: pre-wrap; |
| | word-wrap: break-word; |
| | display: none; |
| | border-left: 4px solid #007bff; |
| | } |
| | .loading { display: none; margin-top: 15px; color: #666; font-style: italic; } |
| | </style> |
| | </head> |
| | <body> |
| |
|
| | <div class="container"> |
| | <h2>Nhận dạng văn bản (AI OCR)</h2> |
| |
|
| | <div class="lang-selector"> |
| | <label for="langSelect">Chọn ngôn ngữ trên ảnh:</label> |
| | <select id="langSelect"> |
| | <option value="vi">🇻🇳 Tiếng Việt (+ Tiếng Anh)</option> |
| | <option value="zh">🇨🇳 Tiếng Trung Giản Thể (+ Tiếng Anh)</option> |
| | </select> |
| | </div> |
| | |
| | <label class="upload-area" for="fileInput"> |
| | <div id="uploadText">Click để chọn ảnh hoặc Kéo thả ảnh vào đây</div> |
| | <img id="imagePreview" class="preview-img" alt="Ảnh xem trước"> |
| | </label> |
| | <input type="file" id="fileInput" accept="image/*"> |
| |
|
| | <button id="submitBtn" disabled>Trích xuất văn bản</button> |
| |
|
| | <div id="loading" class="loading">Đang phân tích ảnh, vui lòng đợi...</div> |
| | <div id="resultBox" class="result-box"></div> |
| | </div> |
| |
|
| | <script> |
| | const fileInput = document.getElementById('fileInput'); |
| | const imagePreview = document.getElementById('imagePreview'); |
| | const uploadText = document.getElementById('uploadText'); |
| | const submitBtn = document.getElementById('submitBtn'); |
| | const resultBox = document.getElementById('resultBox'); |
| | const loading = document.getElementById('loading'); |
| | const langSelect = document.getElementById('langSelect'); |
| | |
| | let selectedFile = null; |
| | |
| | fileInput.addEventListener('change', function(e) { |
| | const file = e.target.files[0]; |
| | if (file) { |
| | selectedFile = file; |
| | const reader = new FileReader(); |
| | reader.onload = function(event) { |
| | imagePreview.src = event.target.result; |
| | imagePreview.style.display = 'block'; |
| | uploadText.style.display = 'none'; |
| | submitBtn.disabled = false; |
| | } |
| | reader.readAsDataURL(file); |
| | } |
| | }); |
| | |
| | submitBtn.addEventListener('click', async function() { |
| | if (!selectedFile) return; |
| | |
| | submitBtn.disabled = true; |
| | loading.style.display = 'block'; |
| | resultBox.style.display = 'none'; |
| | resultBox.innerHTML = ''; |
| | |
| | const formData = new FormData(); |
| | formData.append('file', selectedFile); |
| | formData.append('lang', langSelect.value); |
| | |
| | try { |
| | const currentUrl = window.location.href.split('?')[0].replace(/\/$/, ""); |
| | const apiUrl = currentUrl + "/predict"; |
| | |
| | const response = await fetch(apiUrl, { |
| | method: 'POST', |
| | body: formData |
| | }); |
| | |
| | if (!response.ok) { |
| | const errorData = await response.json(); |
| | throw new Error(errorData.detail || `Lỗi máy chủ (Mã: ${response.status})`); |
| | } |
| | |
| | const data = await response.json(); |
| | resultBox.innerText = data.text || "Không tìm thấy chữ trong ảnh."; |
| | resultBox.style.display = 'block'; |
| | resultBox.style.color = "#333"; |
| | |
| | } catch (error) { |
| | console.error(error); |
| | resultBox.innerText = "Đã xảy ra lỗi: " + error.message; |
| | resultBox.style.display = 'block'; |
| | resultBox.style.color = "red"; |
| | } finally { |
| | loading.style.display = 'none'; |
| | submitBtn.disabled = false; |
| | } |
| | }); |
| | </script> |
| |
|
| | </body> |
| | </html> |