Spaces:
Runtime error
Runtime error
| <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% ; 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> | |