viewer on-demand — relancer viser à la demande depuis le dashboard

Le viser de demo.py était tué dès que le PLY était écrit (pour libérer la VRAM),
donc les liens dans le dashboard menaient vers ERR_CONNECTION_REFUSED.

Ajout d'un viewer standalone indépendant :
- scripts/viser_ply.py : charge un PLY via open3d + sert via viser (sans GPU),
  subsample random à 2M pts max pour rester fluide
- app/main.py : routes POST /jobs/{id}/view et /stitches/{id}/view qui scp
  le script sur le worker et lancent un viser détaché (nohup+setsid+disown via
  wrapper shell déposé sur le worker)
- templates : remplace <a href> par <button class=viewer-btn> qui POST puis
  window.open de l'URL retournée
- Dockerfile : copie scripts/ dans l'image (nécessaire pour scp-er viser_ply.py)
This commit is contained in:
Poulpe
2026-04-21 13:09:48 +00:00
parent 6ac3a382c7
commit 468f9084ec
6 changed files with 159 additions and 3 deletions

View File

@@ -19,8 +19,8 @@
</span>
<span class="label">
{{ j.auv }}/{{ j.gopro_serial }}/{{ j.segment_label }}
{% if j.status == 'done' and j.viser_url %}
<a class="ext" href="{{ j.viser_url }}" target="_blank">viser</a>
{% if j.status == 'done' and j.ply_path %}
<button class="ext viewer-btn" data-view-url="jobs/{{ j.id }}/view">viser</button>
{% endif %}
</span>
<span class="dur">{{ j._duration }}</span>
@@ -56,7 +56,7 @@
{% else %}merge final{% endif %}
{% if s._duration %}<span class="dur muted"> — {{ s._duration }}</span>{% endif %}
{% if s.status == 'done' and s.output_ply %}
<span class="ext" title="{{ s.output_ply }}">PLY</span>
<button class="ext viewer-btn" data-view-url="stitches/{{ s.id }}/view" title="{{ s.output_ply }}">viser</button>
{% endif %}
</span>
{% if s.status in ('queued','running') %}

View File

@@ -24,5 +24,24 @@
<p class="muted">Chargement…</p>
</div>
</section>
<script>
document.addEventListener('click', async (e) => {
const btn = e.target.closest('.viewer-btn');
if (!btn) return;
e.preventDefault();
const url = btn.dataset.viewUrl;
btn.textContent = '…';
btn.disabled = true;
try {
const res = await fetch(url, { method: 'POST' });
const data = await res.json();
if (res.ok && data.url) window.open(data.url, '_blank');
else alert(data.detail || 'Erreur lancement viewer');
} catch (err) { alert('Erreur réseau: ' + err); }
btn.textContent = 'viser';
btn.disabled = false;
});
</script>
</body>
</html>