131 lines
4.7 KiB
HTML
131 lines
4.7 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}Ambil Gambar Tomat{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="container mt-5">
|
|
<div id="notif-container" class="mb-4">
|
|
{% if error %}
|
|
<div class="alert alert-danger text-center" role="alert">
|
|
{{ error }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="text-center mb-4">
|
|
<h1 class="display-6">Ambil Gambar Tomat Anda</h1>
|
|
<p class="text-muted">Pastikan kamera Anda menghadap ke tomat yang akan diprediksi atau unggah gambar tomat dari perangkat Anda!</p>
|
|
</div>
|
|
|
|
<!-- Kamera -->
|
|
<div class="card shadow-sm mb-4">
|
|
<div class="card-body text-center">
|
|
<div id="camera-container" class="border rounded mb-3 mx-auto" style="width: 100%; max-width: 480px; aspect-ratio: 4 / 3; background-color: #f8f9fa;">
|
|
<video id="camera" autoplay muted playsinline style="width: 100%; height: 100%; object-fit: cover; border-radius: 8px;"></video>
|
|
</div>
|
|
<button id="capture" class="btn btn-primary w-100">Ambil Gambar</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Form Unggah Gambar -->
|
|
<div class="card shadow-sm">
|
|
<div class="card-body">
|
|
<form action="/upload" method="post" enctype="multipart/form-data" class="text-center">
|
|
<div class="form-group mb-3">
|
|
<label for="file" class="form-label">Pilih Gambar</label>
|
|
<input type="file" class="form-control" id="file" name="file">
|
|
</div>
|
|
<button type="submit" class="btn btn-secondary w-100">Unggah Gambar</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// Akses kamera
|
|
const video = document.getElementById('camera');
|
|
const captureButton = document.getElementById('capture');
|
|
const notifContainer = document.getElementById('notif-container');
|
|
|
|
// Mulai kamera
|
|
navigator.mediaDevices.getUserMedia({
|
|
video: { facingMode: { exact: "environment" } }
|
|
})
|
|
.then((stream) => {
|
|
video.srcObject = stream;
|
|
})
|
|
.catch((error) => {
|
|
console.warn('Gagal akses kamera belakang, coba kamera default:', error);
|
|
// Fallback ke kamera default (depan atau webcam laptop)
|
|
return navigator.mediaDevices.getUserMedia({ video: true });
|
|
})
|
|
.then((stream) => {
|
|
if (stream) {
|
|
video.srcObject = stream;
|
|
}
|
|
})
|
|
.catch((error) => {
|
|
console.error("Gagal mengakses kamera:", error);
|
|
showNotif('Tidak dapat mengakses kamera. Periksa izin kamera.', 'danger');
|
|
});
|
|
|
|
|
|
// Fungsi menampilkan notifikasi
|
|
function showNotif(message, type) {
|
|
notifContainer.innerHTML = `
|
|
<div class="alert alert-${type} text-center" role="alert">
|
|
${message}
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
// Event tombol ambil gambar
|
|
captureButton.addEventListener('click', () => {
|
|
const canvas = document.createElement('canvas');
|
|
canvas.width = video.videoWidth;
|
|
canvas.height = video.videoHeight;
|
|
const context = canvas.getContext('2d');
|
|
context.drawImage(video, 0, 0, canvas.width, canvas.height);
|
|
|
|
// Convert canvas ke base64
|
|
const imageData = canvas.toDataURL('image/png');
|
|
|
|
// Tampilkan loading
|
|
showNotif('Sedang memproses gambar...', 'info');
|
|
captureButton.innerText = 'Sedang memproses...';
|
|
captureButton.disabled = true;
|
|
|
|
// Kirim data ke server menggunakan AJAX
|
|
fetch('/predict', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({ image: imageData }),
|
|
})
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
return response.json().then(data => {
|
|
throw new Error(data.error || 'Prediksi gagal.');
|
|
});
|
|
}
|
|
return response.json();
|
|
})
|
|
.then(data => {
|
|
if (data.success) {
|
|
showNotif(`Prediksi: ${data.predicted_class} dengan akurasi ${data.confidence}%`, 'success');
|
|
} else {
|
|
showNotif(data.error || 'Prediksi gagal. Silakan coba lagi.', 'danger');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error:', error.message);
|
|
showNotif(error.message || 'Terjadi kesalahan saat memproses gambar.', 'danger');
|
|
})
|
|
.finally(() => {
|
|
captureButton.innerText = 'Ambil Gambar';
|
|
captureButton.disabled = false;
|
|
});
|
|
});
|
|
</script>
|
|
{% endblock %}
|