feat: hook post-job cosma-nav + style dashboard + docker-compose update
This commit is contained in:
@@ -174,6 +174,8 @@ code { background: rgba(255,255,255,0.05); padding: 0 0.25rem; border-radius: 3p
|
||||
.docs-link:hover { background: #2d2f31; }
|
||||
.btn-glb, .btn-ply-dl { display: inline-block; text-decoration: none; padding: 3px 10px; border: 1px solid #8bc34a; border-radius: 3px; color: #8bc34a; font-size: 0.72rem; background: transparent; cursor: pointer; font-family: inherit; }
|
||||
.btn-glb:hover, .btn-ply-dl:hover { background: #8bc34a; color: #000; }
|
||||
.btn-qc { display: inline-block; text-decoration: none; padding: 3px 10px; border: 1px solid #29b6f6; border-radius: 3px; color: #29b6f6; font-size: 0.72rem; background: transparent; cursor: pointer; font-family: inherit; }
|
||||
.btn-qc:hover { background: #29b6f6; color: #000; }
|
||||
|
||||
/* Section évolutions */
|
||||
#evolutions { margin-top: 2rem; padding-top: 1rem; border-top: 1px solid var(--border, #333); }
|
||||
@@ -192,3 +194,7 @@ code { background: rgba(255,255,255,0.05); padding: 0 0.25rem; border-radius: 3p
|
||||
.pipeline-box ol { margin: 0; padding-left: 1.4rem; }
|
||||
.pipeline-box li { padding: 0.18rem 0; font-size: 0.78rem; color: var(--muted, #888); }
|
||||
.pipeline-box code { font-size: 0.73rem; background: rgba(255,255,255,0.07); padding: 1px 5px; border-radius: 3px; color: #cef; }
|
||||
|
||||
.viewer-btn { background: #1a3a2a; color: #4ade80; border: 1px solid #4ade80; border-radius: 3px; padding: 2px 8px; cursor: pointer; font-size: 0.8rem; }
|
||||
.viewer-btn:hover { background: #4ade80; color: #0a1a10; }
|
||||
.viewer-btn:disabled { opacity: 0.5; cursor: wait; }
|
||||
|
||||
@@ -75,16 +75,26 @@ document.addEventListener('click', async (e) => {
|
||||
const btn = e.target.closest('.viewer-btn');
|
||||
if (!btn) return;
|
||||
e.preventDefault();
|
||||
const url = btn.dataset.viewUrl;
|
||||
const liveUrl = btn.dataset.liveUrl;
|
||||
const viewUrl = 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';
|
||||
let url = null;
|
||||
if (liveUrl) {
|
||||
try {
|
||||
const res = await fetch(liveUrl, { method: 'POST' });
|
||||
if (res.ok) { const d = await res.json(); url = d.url; }
|
||||
} catch {}
|
||||
}
|
||||
if (!url && viewUrl) {
|
||||
try {
|
||||
const res = await fetch(viewUrl, { method: 'POST' });
|
||||
if (res.ok) { const d = await res.json(); url = d.url; }
|
||||
else { const d = await res.json(); alert(d.detail || 'Erreur lancement viewer'); }
|
||||
} catch (err) { alert('Erreur réseau: ' + err); }
|
||||
}
|
||||
if (url) window.open(url, '_blank');
|
||||
btn.textContent = 'viser ↗';
|
||||
btn.disabled = false;
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -6,8 +6,8 @@ services:
|
||||
ports:
|
||||
- "3849:8000"
|
||||
volumes:
|
||||
- /home/floppyrj45/cosma-qc-data:/var/lib/cosma-qc
|
||||
- /home/floppyrj45/.ssh:/ssh-in:ro
|
||||
- /home/cosma/cosma-qc-data:/var/lib/cosma-qc
|
||||
- /home/cosma/.ssh:/ssh-in:ro
|
||||
environment:
|
||||
COSMA_QC_WORKERS: |
|
||||
[
|
||||
|
||||
@@ -806,6 +806,43 @@ def run_one_stitch(stitch: sqlite3.Row):
|
||||
finished_at=_now_iso())
|
||||
|
||||
|
||||
|
||||
ML_STACK_HOST = "192.168.0.84"
|
||||
ML_STACK_ALIAS = "ml-stack"
|
||||
_PRE_DECIMATE = "/root/cosma-nav/scripts/pre_decimate.py"
|
||||
_ARCHIVE_SH = "/root/cosma-nav/scripts/archive_job.sh"
|
||||
|
||||
|
||||
def _post_job_qc_sync(job_id: int, worker: dict, frames_dir: str):
|
||||
"""Fire-and-forget: decimate PLY + archive to NAS after a successful job.
|
||||
Only runs when the worker is ml-stack (.84) where the scripts live.
|
||||
"""
|
||||
if worker["host"] != ML_STACK_HOST:
|
||||
print(f" post_job #{job_id}: worker={worker['host']} != ml-stack, skip QC sync", flush=True)
|
||||
return
|
||||
alias = ML_STACK_ALIAS
|
||||
parent = str(Path(frames_dir).parent)
|
||||
pre_cmd = (
|
||||
f"python3 {_PRE_DECIMATE} {job_id} "
|
||||
f"--frames-dir {shlex.quote(parent)} "
|
||||
f"> /tmp/pre_decimate_{job_id}.log 2>&1"
|
||||
)
|
||||
rc_pre, _, _ = ssh(alias, pre_cmd, timeout=600)
|
||||
if rc_pre == 0:
|
||||
print(f" post_job #{job_id}: pre_decimate OK", flush=True)
|
||||
else:
|
||||
tail = ssh(alias, f"tail -5 /tmp/pre_decimate_{job_id}.log")[1]
|
||||
print(f" post_job #{job_id}: pre_decimate FAIL: {tail[:300]}", flush=True)
|
||||
|
||||
arc_cmd = f"bash {_ARCHIVE_SH} {job_id} > /tmp/archive_{job_id}.log 2>&1"
|
||||
rc_arc, _, _ = ssh(alias, arc_cmd, timeout=600)
|
||||
if rc_arc == 0:
|
||||
print(f" post_job #{job_id}: archive OK", flush=True)
|
||||
else:
|
||||
tail = ssh(alias, f"tail -5 /tmp/archive_{job_id}.log")[1]
|
||||
print(f" post_job #{job_id}: archive FAIL: {tail[:300]}", flush=True)
|
||||
|
||||
|
||||
def run_one(job: sqlite3.Row) -> bool:
|
||||
"""Returns True if a worker was picked and work started."""
|
||||
job_id = job["id"]
|
||||
@@ -825,6 +862,7 @@ def run_one(job: sqlite3.Row) -> bool:
|
||||
set_status(job_id, status="done", viser_url=viser_url, ply_path=ply_path,
|
||||
progress=100, log_tail=log, finished_at=_now_iso())
|
||||
_maybe_create_per_auv_stitch(job_id)
|
||||
threading.Thread(target=_post_job_qc_sync, args=(job_id, worker, frames_dir), daemon=True).start()
|
||||
except Exception as e:
|
||||
# do_extract raises "skipped_short" after flagging status='skipped' — don't override.
|
||||
if "skipped_short" not in str(e):
|
||||
|
||||
Reference in New Issue
Block a user