1. _jobs_table.html: remplace la liste <li>flex par un vrai <table> avec
colonnes explicites: status · preview · #id · AUV+GP · label · duree
video · frames · hors-eau · progression · temps · actions. Stitches
restent en <ul> compacte.
2. main.py _build_acquisitions: probe TCP le viser_url avec cache 8s
avant de le passer au template. Si port mort -> d[viser_url]=None ->
pas de bouton affiche. Fini les liens qui mennent a rien.
3. style.css: purge des regles flex conflictuelles, rewrite propre pour
table.jobs-table, badges, prog-bar, btn-viser direct link.
dispatcher scp frame_*.jpg (premiere apres trim head) vers
/var/lib/cosma-qc/thumbnails/job_N.jpg a la fin de do_extract.
Endpoint GET /jobs/{id}/thumbnail serve via FileResponse. Template:
<img class=thumb src=jobs/N/thumbnail> si has_thumbnail. 48x27 px,
object-fit cover.
Backfill manuel des jobs deja done (9, 12, 13, 16, 19) via scp direct.
dashboard:
- job_id, AUV GP1/GP2 (serial en tooltip), segment_label, duree reelle,
nb frames, nb hors-eau trimes
- lien viser plain <a href> (plus de POST ni popup). Affiche uniquement
si job.done ET viser_url persistee (demo.py kept alive)
- CSS minimal: flex row, separateurs, skipped en italic mute
dispatcher:
- trim head ET tail (AUV hors-eau en debut + fin de session)
- migration DB: trimmed_head, trimmed_tail, video_duration_s
- do_extract persiste total_duration_s + trimmed counts via set_status
- run_one: RuntimeError(skipped_short) preserve le status=skipped
- min_frames underwater pour skip les segments trop courts
- ram_budget 0.45 -> 0.35 (OOM rc=137 avec 8237 frames sur 62GB RAM)
live button:
- POST /jobs/{id}/live
- Probe le port natif (worker viser_port_base + job_id) via nc
- 200 + viser_url si demo.py encore alive (necessite le patch keep-alive)
- 410 + fallback message si ferme
PLY button:
- POST /jobs/{id}/view (existant)
- Lance viser_ply.py standalone sur port VIEWER_PORT_BASE+id
Permet de choisir entre viser natif (PointCloudViewer de lingbot-map avec
camera frustums, filtre confiance interactif, animation) et viewer basic
XYZ+RGB uniquement.
- dispatcher.py : ffmpeg lancé en background (setsid), polling du
nombre de frames toutes les 5s → mise à jour du champ `progress`
en DB. ffprobe estime le total avant lancement pour calculer le %.
- _jobs_table.html : barre de progression visible sur les jobs
en status extracting/running
- style.css : styles .prog-wrap/.prog-fill/.prog-text
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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)
- Table stitches (per_auv + cross_auv) avec cancel/retry API
- Dispatcher : PLY export auto (--save_ply), trigger stitch en cascade
quand tous les jobs d'un AUV sont done
- UI : section stitch live depuis DB avec statuts/durées/boutons
- Fix : <base href="/cosma-qc/"> + chemins relatifs pour Caddy subpath
- open3d 0.19.0 installé sur gpu (.87)
- SSH key .82→.87 configurée, alias gpu ajouté sur .82
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>