285 lines
11 KiB
HTML
285 lines
11 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}Upload Gambar{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="row justify-content-center">
|
|
<div class="col-md-8">
|
|
<div class="card shadow">
|
|
<div class="card-header bg-success text-white">
|
|
<h4 class="mb-0"><i class="fas fa-upload me-2"></i>Upload Gambar Sapi</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
|
|
<!-- Info Panel -->
|
|
<div class="alert alert-info mb-4">
|
|
<i class="fas fa-info-circle me-2"></i>
|
|
<strong>Petunjuk:</strong> Upload gambar sapi dengan format JPG, JPEG, PNG, atau BMP.
|
|
Pastikan gambar jelas dan bagian tubuh sapi terlihat dengan baik.
|
|
</div>
|
|
|
|
<!-- Error Message -->
|
|
{% if error %}
|
|
<div class="alert alert-danger">
|
|
<i class="fas fa-exclamation-circle me-2"></i>
|
|
{{ error }}
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Upload Form -->
|
|
<form method="POST" action="{{ url_for('predict') }}" enctype="multipart/form-data" id="uploadForm">
|
|
<div class="mb-4">
|
|
<label for="file" class="form-label fw-bold">Pilih Gambar</label>
|
|
|
|
<!-- Custom File Upload -->
|
|
<div class="upload-area border border-2 border-dashed rounded p-4 text-center"
|
|
id="uploadArea">
|
|
<i class="fas fa-cloud-upload-alt fa-4x text-success mb-3"></i>
|
|
<h5>Drag & Drop atau Klik untuk Upload</h5>
|
|
<p class="text-muted mb-3">Format: JPG, JPEG, PNG, BMP (Maks. 16MB)</p>
|
|
<input type="file" class="form-control d-none" id="file" name="image"
|
|
accept=".jpg,.jpeg,.png,.bmp" required>
|
|
<button type="button" class="btn btn-success" id="browseBtn">
|
|
<i class="fas fa-folder-open me-2"></i>Pilih File
|
|
</button>
|
|
</div>
|
|
|
|
<!-- File Info -->
|
|
<div id="fileInfo" class="mt-3 d-none">
|
|
<div class="alert alert-success">
|
|
<i class="fas fa-check-circle me-2"></i>
|
|
<span id="fileName"></span>
|
|
<button type="button" class="btn-close float-end" id="removeFile"></button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Image Preview -->
|
|
<div class="mb-4 text-center" id="previewContainer" style="display: none;">
|
|
<h6 class="mb-3">Preview Gambar:</h6>
|
|
<div class="preview-wrapper">
|
|
<img id="preview" class="img-fluid rounded shadow"
|
|
style="max-height: 300px; border: 3px solid #28a745;" alt="Preview">
|
|
</div>
|
|
<p class="text-muted mt-2 small" id="imageDimensions"></p>
|
|
</div>
|
|
|
|
<!-- Submit Button -->
|
|
<button type="submit" class="btn btn-success btn-lg w-100" id="submitBtn" disabled>
|
|
<i class="fas fa-search me-2"></i>Deteksi Sekarang
|
|
</button>
|
|
</form>
|
|
|
|
<!-- Loading Indicator -->
|
|
<div id="loading" class="text-center mt-4 d-none">
|
|
<div class="spinner-border text-success" style="width: 3rem; height: 3rem;" role="status">
|
|
<span class="visually-hidden">Loading...</span>
|
|
</div>
|
|
<p class="mt-3 fw-bold">Sedang menganalisis gambar...</p>
|
|
<p class="text-muted small">Proses ini membutuhkan waktu beberapa detik</p>
|
|
</div>
|
|
|
|
<!-- Format yang Didukung -->
|
|
<div class="mt-4">
|
|
<h6 class="mb-2">Format yang Didukung:</h6>
|
|
<div class="d-flex gap-2">
|
|
<span class="badge bg-secondary">JPG</span>
|
|
<span class="badge bg-secondary">JPEG</span>
|
|
<span class="badge bg-secondary">PNG</span>
|
|
<span class="badge bg-secondary">BMP</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tips Card -->
|
|
<div class="card mt-4">
|
|
<div class="card-header bg-info text-white">
|
|
<h5 class="mb-0"><i class="fas fa-lightbulb me-2"></i>Tips Pengambilan Gambar</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<h6><i class="fas fa-check-circle text-success me-2"></i>Disarankan:</h6>
|
|
<ul class="list-unstyled">
|
|
<li><i class="fas fa-arrow-right text-success me-2"></i>Gambar dengan pencahayaan cukup</li>
|
|
<li><i class="fas fa-arrow-right text-success me-2"></i>Fokus pada bagian mulut dan kaki</li>
|
|
<li><i class="fas fa-arrow-right text-success me-2"></i>Ambil dari jarak dekat (0.5-1 meter)</li>
|
|
<li><i class="fas fa-arrow-right text-success me-2"></i>Gunakan latar belakang polos</li>
|
|
</ul>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<h6><i class="fas fa-times-circle text-danger me-2"></i>Tidak Disarankan:</h6>
|
|
<ul class="list-unstyled">
|
|
<li><i class="fas fa-times text-danger me-2"></i>Gambar buram atau blur</li>
|
|
<li><i class="fas fa-times text-danger me-2"></i>Terlalu jauh dari objek</li>
|
|
<li><i class="fas fa-times text-danger me-2"></i>Pencahayaan kurang/tidak merata</li>
|
|
<li><i class="fas fa-times text-danger me-2"></i>Banyak objek dalam satu frame</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
.upload-area {
|
|
border: 2px dashed #28a745 !important;
|
|
background-color: #f8f9fa;
|
|
transition: all 0.3s;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.upload-area:hover {
|
|
background-color: #e9ecef;
|
|
border-color: #218838 !important;
|
|
}
|
|
|
|
.upload-area.dragover {
|
|
background-color: #d4edda;
|
|
border-color: #28a745 !important;
|
|
}
|
|
|
|
.preview-wrapper {
|
|
position: relative;
|
|
display: inline-block;
|
|
}
|
|
|
|
#removeFile {
|
|
cursor: pointer;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const uploadArea = document.getElementById('uploadArea');
|
|
const fileInput = document.getElementById('file');
|
|
const browseBtn = document.getElementById('browseBtn');
|
|
const fileInfo = document.getElementById('fileInfo');
|
|
const fileName = document.getElementById('fileName');
|
|
const removeFile = document.getElementById('removeFile');
|
|
const previewContainer = document.getElementById('previewContainer');
|
|
const preview = document.getElementById('preview');
|
|
const submitBtn = document.getElementById('submitBtn');
|
|
const loading = document.getElementById('loading');
|
|
const imageDimensions = document.getElementById('imageDimensions');
|
|
const uploadForm = document.getElementById('uploadForm');
|
|
|
|
// Click on upload area
|
|
uploadArea.addEventListener('click', function() {
|
|
fileInput.click();
|
|
});
|
|
|
|
// Browse button click
|
|
browseBtn.addEventListener('click', function(e) {
|
|
e.stopPropagation();
|
|
fileInput.click();
|
|
});
|
|
|
|
// Drag and drop events
|
|
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
|
|
uploadArea.addEventListener(eventName, preventDefaults, false);
|
|
});
|
|
|
|
function preventDefaults(e) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
}
|
|
|
|
['dragenter', 'dragover'].forEach(eventName => {
|
|
uploadArea.addEventListener(eventName, highlight, false);
|
|
});
|
|
|
|
['dragleave', 'drop'].forEach(eventName => {
|
|
uploadArea.addEventListener(eventName, unhighlight, false);
|
|
});
|
|
|
|
function highlight() {
|
|
uploadArea.classList.add('dragover');
|
|
}
|
|
|
|
function unhighlight() {
|
|
uploadArea.classList.remove('dragover');
|
|
}
|
|
|
|
uploadArea.addEventListener('drop', handleDrop, false);
|
|
|
|
function handleDrop(e) {
|
|
const dt = e.dataTransfer;
|
|
const files = dt.files;
|
|
fileInput.files = files;
|
|
handleFileSelect(files[0]);
|
|
}
|
|
|
|
// File input change
|
|
fileInput.addEventListener('change', function() {
|
|
if (this.files[0]) {
|
|
handleFileSelect(this.files[0]);
|
|
}
|
|
});
|
|
|
|
// Handle file selection
|
|
function handleFileSelect(file) {
|
|
// Check file size (16MB max)
|
|
if (file.size > 16 * 1024 * 1024) {
|
|
alert('File terlalu besar. Maksimal 16MB.');
|
|
fileInput.value = '';
|
|
return;
|
|
}
|
|
|
|
// Check file type
|
|
const allowedTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/bmp'];
|
|
if (!allowedTypes.includes(file.type)) {
|
|
alert('Tipe file tidak didukung. Gunakan JPG, JPEG, PNG, atau BMP.');
|
|
fileInput.value = '';
|
|
return;
|
|
}
|
|
|
|
// Show file info
|
|
fileName.textContent = `${file.name} (${(file.size / 1024).toFixed(2)} KB)`;
|
|
fileInfo.classList.remove('d-none');
|
|
|
|
// Show preview
|
|
const reader = new FileReader();
|
|
reader.onload = function(e) {
|
|
preview.src = e.target.result;
|
|
previewContainer.style.display = 'block';
|
|
|
|
// Get image dimensions
|
|
const img = new Image();
|
|
img.onload = function() {
|
|
imageDimensions.textContent = `${this.width} x ${this.height} pixels`;
|
|
};
|
|
img.src = e.target.result;
|
|
};
|
|
reader.readAsDataURL(file);
|
|
|
|
// Enable submit button
|
|
submitBtn.disabled = false;
|
|
}
|
|
|
|
// Remove file
|
|
removeFile.addEventListener('click', function() {
|
|
fileInput.value = '';
|
|
fileInfo.classList.add('d-none');
|
|
previewContainer.style.display = 'none';
|
|
submitBtn.disabled = true;
|
|
});
|
|
|
|
// Form submit
|
|
uploadForm.addEventListener('submit', function(e) {
|
|
if (!fileInput.files[0]) {
|
|
e.preventDefault();
|
|
alert('Pilih file terlebih dahulu');
|
|
return;
|
|
}
|
|
|
|
submitBtn.disabled = true;
|
|
loading.classList.remove('d-none');
|
|
});
|
|
});
|
|
</script>
|
|
{% endblock %} |