feat: merged detection output + parallel model execution

- Multiple models run simultaneously on each frame via ThreadPoolExecutor
- Detections merged with IoU deduplication (same class, high overlap → keep highest conf)
- Single merged_annotated.mp4 output (not per-model videos)
- Single model still uses existing run_pipeline for backward compat
- Active jobs banner on upload page (polls every 5s)
- GPU warning when selecting 3+ models
- 62/62 tests pass
This commit is contained in:
jetson committed 2026-09-22 11:10:41 +07:00
1 parent 163280078f
commit fc20a521ee
5 files changed
+381 -40

No files matched your search

+29 -1
View File
@@ -270,7 +270,14 @@
Submit — enable/disable, loading state
------------------------------------------------ */
function initFormSubmit() {
form.addEventListener('submit', function () {
form.addEventListener('submit', function (e) {
var checked = modelGrid.querySelectorAll('.model-card-check:checked');
if (checked.length >= 3) {
if (!confirm('Running ' + checked.length + ' models simultaneously may use significant GPU memory on Jetson. Continue?')) {
e.preventDefault();
return;
}
}
if (videoPathInput.value) {
form.action = '/upload/reuse';
} else {
@@ -304,6 +311,27 @@
initModelCards();
initFormSubmit();
loadExistingVideos();
// Poll active jobs
function checkActiveJobs() {
fetch('/api/jobs/active')
.then(function(res) { return res.json(); })
.then(function(data) {
var banner = document.getElementById('active-jobs-banner');
var text = document.getElementById('active-jobs-text');
if (banner && text) {
if (data.count > 0) {
banner.style.display = '';
text.textContent = data.count + ' job' + (data.count > 1 ? 's' : '') + ' in progress';
} else {
banner.style.display = 'none';
}
}
})
.catch(function() {});
}
checkActiveJobs();
setInterval(checkActiveJobs, 5000);
})();
function formatRelativeTime(timestamp) {