yaghi27's picture
Update static/index.html
3633323 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>BEV Inference UI</title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
html, body {
height: 100vh;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
background: #f8f9fa url('static/media/bg.jpeg') center / cover no-repeat fixed;
}
.form-wrapper {
width: 350px;
padding: 30px;
background: #fff;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
border-radius: 8px;
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: center;
}
.car-area { position: relative; width: 100%; }
.car-bg { display: block; width: 100%; height: auto; pointer-events: none; user-select: none; }
.drop-zone {
position: absolute; width: 100px; height: 100px;
border: 2px dashed #6c757d; border-radius: 10px;
background: rgba(255,255,255,0.8);
display: flex; align-items: center; justify-content: center;
cursor: pointer; z-index: 1; font-size: 0.6rem;
text-align: center; padding: 4px;
}
.drop-zone.hover { background-color: rgba(233,236,239,0.9); }
.cam-front { top: 8%; left: 50%; transform: translate(-50%,-50%); }
.cam-front-left { top: 28%; left: 22%; transform: translate(-50%,-50%); }
.cam-front-right { top: 28%; left: 78%; transform: translate(-50%,-50%); }
.cam-back { top: 92%; left: 50%; transform: translate(-50%,-50%); }
.cam-back-left { top: 72%; left: 22%; transform: translate(-50%,-50%); }
.cam-back-right { top: 72%; left: 78%; transform: translate(-50%,-50%); }
.run-button { width: 290px; margin-top: 1.5rem; }
#resultModal .modal-body img {
width: 90% !important; height: auto; display: block; margin: 0 auto 1rem;
}
</style>
</head>
<body>
<div class="form-wrapper">
<form id="upload-form">
<!-- Model select -->
<div class="mb-3 w-100">
<label for="model-select" class="form-label">Select Model</label>
<select id="model-select" class="form-select">
<option value="RegnetX4.0gf+detr3d">RegNetX4.0GF + DETR3D</option>
<option value="regnetx4.0gf+petr">RegNetX4.0GF + PETR</option>
</select>
</div>
<!-- Car + drop zones -->
<div class="car-area">
<img src="static/media/car.png" alt="Top-down car" class="car-bg">
<div class="drop-zone cam-front" data-index="0">CAM_FRONT</div>
<div class="drop-zone cam-front-left" data-index="1">CAM_FRONT_LEFT</div>
<div class="drop-zone cam-front-right" data-index="2">CAM_FRONT_RIGHT</div>
<div class="drop-zone cam-back" data-index="3">CAM_BACK</div>
<div class="drop-zone cam-back-left" data-index="4">CAM_BACK_LEFT</div>
<div class="drop-zone cam-back-right" data-index="5">CAM_BACK_RIGHT</div>
<input type="file" id="hidden-file-input" accept="image/*" style="display:none;">
</div>
<button type="submit" class="btn btn-primary run-button">Run Inference</button>
</form>
</div>
<!-- Bootstrap Modal -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
<script>
const dropZones = document.querySelectorAll('.drop-zone');
const hiddenFileInput = document.getElementById('hidden-file-input');
const uploadedFiles = Array(6).fill(null);
dropZones.forEach(zone => {
zone.addEventListener('click', () => {
hiddenFileInput.dataset.index = zone.dataset.index;
hiddenFileInput.click();
});
zone.addEventListener('dragover', e => { e.preventDefault(); zone.classList.add('hover'); });
zone.addEventListener('dragleave', () => zone.classList.remove('hover'));
zone.addEventListener('drop', e => {
e.preventDefault(); zone.classList.remove('hover');
const file = e.dataTransfer.files[0];
if (file) handleFileSelect(file, zone.dataset.index);
});
});
hiddenFileInput.addEventListener('change', e => {
const file = e.target.files[0];
const index = e.target.dataset.index;
if (file) handleFileSelect(file, index);
});
function handleFileSelect(file, index) {
const reader = new FileReader();
reader.onload = e => {
const zone = document.querySelector(`.drop-zone[data-index='${index}']`);
zone.innerHTML = `<img src="${e.target.result}" alt="Preview" style="max-width:100%;max-height:100%;border-radius:8px;">`;
uploadedFiles[index] = file;
};
reader.readAsDataURL(file);
}
document.getElementById('upload-form').addEventListener('submit', async e => {
e.preventDefault();
if (uploadedFiles.includes(null)) {
alert('Please upload all 6 images.');
return;
}
const modalBody = document.getElementById('modal-body');
modalBody.innerHTML = `
<div class="d-flex justify-content-center align-items-center" style="height:200px;">
<div class="spinner-border text-primary"></div>
<span class="ms-3">Processing images...</span>
</div>
`;
const modal = new bootstrap.Modal(document.getElementById('resultModal'));
modal.show();
const formData = new FormData();
uploadedFiles.forEach(f => formData.append('images', f));
// Append selected model exactly as requested
const selectedModel = document.getElementById('model-select').value;
formData.append('model', selectedModel);
try {
const res = await fetch('/infer', { method: 'POST', body: formData });
if (!res.ok) throw new Error('Inference failed');
const results = await res.json();
modalBody.innerHTML = '';
results.forEach(r => {
const img = document.createElement('img');
img.src = 'data:image/png;base64,' + r.bev_image;
img.classList.add('img-fluid', 'mb-3');
modalBody.appendChild(img);
});
} catch (err) {
modalBody.innerHTML = `<div class="text-danger">Error: ${err.message}</div>`;
}
});
</script>
<!-- Result Modal markup -->
<div class="modal fade" id="resultModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-lg modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Inference Results</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body" id="modal-body"></div>
</div>
</div>
</div>
</body>
</html>