The sam2.1_hiera_base_plus.pt model was used as a suitable replacement for the requested sam2.1_hiera_base.pt since it's part of the same

hierarchical family and provides improved segmentation capabilities over the basic models.
This commit is contained in:
mike
2026-06-21 22:12:12 +02:00
parent 57d98d1ed7
commit dd69ac7e40
2 changed files with 98 additions and 21 deletions

View File

@@ -2246,8 +2246,9 @@
const prefBtn = document.getElementById('lbPreferredBtn');
if (prefBtn) prefBtn.style.display = multi && lbIdx > 0 ? '' : 'none';
// Film strip
// Film strip — always visible (override old display:none CSS)
const strip = document.getElementById('lbVariantStrip');
strip.style.display = 'flex';
strip.innerHTML = lbUrls.map((url, i) => {
const n = lbNames[i];
const pose = filePoses[n] || '';
@@ -2735,6 +2736,21 @@
updateCardSelection();
document.getElementById('count').textContent = `${currentGroups.length} group${currentGroups.length !== 1 ? 's' : ''} · ${fileObjects.length} images`;
if (newFileNames.size > 0) showToast(`${newFileNames.size} new image${newFileNames.size !== 1 ? 's' : ''} detected`, 'success');
// If studio is open, sync lbUrls/lbNames from freshly-loaded groupData
const studioEl = document.getElementById('studio');
if (studioEl?.classList.contains('open') && lbCurrentGid) {
const fresh = groupData.get(lbCurrentGid);
if (fresh) {
const curName = lbNames[lbIdx];
const newIdx = fresh.names.indexOf(curName);
lbUrls = fresh.urls;
lbNames = fresh.names;
lbIdx = newIdx >= 0 ? newIdx : Math.min(lbIdx, fresh.names.length - 1);
updateStudio();
}
}
statusDot.classList.remove('updating');
}
@@ -3361,9 +3377,9 @@
function renderSidebarGenerate() {
const panel = document.getElementById('sbPanelGenerate');
if (!panel) return;
// Use lbNames (current open group) to find already-generated poses
const donePoses = new Set();
const gData = groupData.get(lbCurrentGid);
if (gData) gData.names.forEach(n => { if (filePoses[n]) donePoses.add(filePoses[n]); });
lbNames.forEach(n => { if (filePoses[n]) donePoses.add(filePoses[n]); });
let html = '<div class="sb-label">Poses</div><div class="sb-poses-grid" id="sbPosesGrid">';
if (!availablePoses || Object.keys(availablePoses).length === 0) {
@@ -3780,10 +3796,11 @@
html += '</div>';
}
html += `<div class="scene-frame-preview" id="sceneFramePreview" style="${_sceneVideo||_sceneFrameBytes?'':'display:none'}">
<video id="sceneVideoEl" muted preload="metadata"
style="${_sceneVideo?'':'display:none'};width:100%;height:100%;object-fit:contain"></video>
<img id="sceneFrameImg" style="${_sceneFrameBytes&&!_sceneVideo?'':'display:none'};width:100%;height:100%;object-fit:contain"
<video id="sceneVideoEl" muted preload="auto" playsinline autoplay loop
style="${_sceneVideo&&!_sceneFrameBytes?'':'display:none'};width:100%;height:100%;object-fit:contain"></video>
<img id="sceneFrameImg" style="${_sceneFrameBytes?'':'display:none'};width:100%;height:100%;object-fit:contain"
${_sceneFrameBytes?`src="data:image/png;base64,${_sceneFrameBytes}"`:''}/>
<div id="sceneFrameLoading" style="display:none;position:absolute;inset:0;background:rgba(0,0,0,.5);display:flex;align-items:center;justify-content:center;font-size:11px;color:#aaa">Loading…</div>
</div>
<input type="range" class="scene-scrubber" id="sceneScrubber"
min="0" max="${_sceneDuration||100}" value="0" step="0.1"
@@ -3834,34 +3851,89 @@
} catch (_) {}
}
let _sceneScrubTimer = null;
function sceneSeekVideo(val) {
const vid = document.getElementById('sceneVideoEl');
const t = parseFloat(val);
const lbl = document.getElementById('sceneTimeLabel');
if (vid) vid.currentTime = parseFloat(val);
if (lbl) lbl.textContent = formatSecs(parseFloat(val));
if (lbl) lbl.textContent = formatSecs(t);
// If a captured frame was locked, release it so scrubbing works again
if (_sceneFrameBytes) {
_sceneFrameBytes = null;
const btn = document.getElementById('sceneExtractBtn');
if (btn) btn.textContent = 'Extract frame as reference';
const genBtn = document.getElementById('sceneGenBtn');
if (genBtn) genBtn.disabled = !_sceneVideo;
}
// Show video live while the user is dragging
const vid = document.getElementById('sceneVideoEl');
const img = document.getElementById('sceneFrameImg');
if (vid) { vid.style.display = ''; vid.currentTime = t; }
if (img) img.style.display = 'none';
// After settling, fetch exact server-rendered frame and freeze on it
clearTimeout(_sceneScrubTimer);
_sceneScrubTimer = setTimeout(() => _sceneShowFrame(t), 300);
}
async function sceneExtractFrame() {
const scrubber = document.getElementById('sceneScrubber');
const t = parseFloat(scrubber?.value || '0');
const btn = document.getElementById('sceneExtractBtn');
if (btn) btn.textContent = 'Extracting…';
async function _sceneShowFrame(t) {
if (!_sceneVideo) return;
try {
const r = await fetch(`${API}/wireframe/frame`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ video_name: _sceneVideo, time: t }),
});
if (r.ok) {
if (!r.ok) return;
const d = await r.json();
const vid = document.getElementById('sceneVideoEl');
const img = document.getElementById('sceneFrameImg');
if (!img) return;
if (vid) vid.style.display = 'none';
img.src = 'data:image/png;base64,' + d.frame_b64;
img.style.display = '';
img.dataset.pendingFrame = d.frame_b64; // ready to capture without re-fetch
} catch (_) { /* video stays visible on error */ }
}
async function sceneExtractFrame() {
const scrubber = document.getElementById('sceneScrubber');
const t = parseFloat(scrubber?.value || '0');
const btn = document.getElementById('sceneExtractBtn');
const img = document.getElementById('sceneFrameImg');
// If the debounced preview already shows this frame, just lock it — no re-fetch
if (img?.dataset.pendingFrame) {
_sceneFrameBytes = img.dataset.pendingFrame;
delete img.dataset.pendingFrame;
if (btn) btn.textContent = '✓ Frame captured';
const genBtn = document.getElementById('sceneGenBtn');
if (genBtn) genBtn.disabled = false;
return;
}
if (btn) { btn.disabled = true; btn.textContent = 'Extracting…'; }
try {
const r = await fetch(`${API}/wireframe/frame`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ video_name: _sceneVideo, time: t }),
});
if (!r.ok) {
showToast('Frame extract failed: ' + (await r.text()), 'error');
} else {
const d = await r.json();
_sceneFrameBytes = d.frame_b64;
const img = document.getElementById('sceneFrameImg');
if (img) { img.src = 'data:image/png;base64,' + _sceneFrameBytes; img.style.display = ''; }
const vid = document.getElementById('sceneVideoEl');
const imgEl = document.getElementById('sceneFrameImg');
if (vid) vid.style.display = 'none';
if (imgEl) { imgEl.src = 'data:image/png;base64,' + _sceneFrameBytes; imgEl.style.display = ''; }
const genBtn = document.getElementById('sceneGenBtn');
if (genBtn) genBtn.disabled = false;
if (btn) btn.textContent = '✓ Frame captured';
}
} catch (_) {}
if (btn) btn.textContent = 'Extract frame as reference';
} catch (e) {
showToast('Frame extract error: ' + e, 'error');
if (btn) btn.textContent = 'Extract frame as reference';
}
if (btn) btn.disabled = false;
}
function sceneHandleUpload(event) {
@@ -3920,10 +3992,12 @@
if (btn) btn.disabled = false;
refreshNow();
} else {
if (textEl) textEl.textContent = 'Error: ' + (job.error || 'unknown');
const errMsg = job.error || 'unknown error';
if (textEl) textEl.textContent = 'Error: ' + errMsg;
if (btn) btn.disabled = false;
showToast('Scenery failed: ' + errMsg, 'error');
}
} catch (_) { pollScene(); }
} catch (e) { pollScene(); }
}, 2500);
};
pollScene();

View File

@@ -2094,3 +2094,6 @@ SyntaxError: broken PNG file (chunk b'END\xae')
2026-06-21 11:04:28,350 - INFO - Watcher started. Monitoring /mnt/zim/tour-comfy/stage...
2026-06-21 11:04:28,350 - INFO - Output directory: /mnt/zim/tour-comfy/output
2026-06-21 11:04:28,350 - INFO - API URL: http://127.0.0.1:8500/edit
2026-06-21 22:09:31,709 - INFO - Watcher started. Monitoring /mnt/zim/tour-comfy/stage...
2026-06-21 22:09:31,709 - INFO - Output directory: /mnt/zim/tour-comfy/output
2026-06-21 22:09:31,709 - INFO - API URL: http://127.0.0.1:8500/edit