feat(dashboard): session cleaner intégré + auth + nettoyage UI
- Onglet "🧹 Nettoyage" dans le dashboard (iframe vers port 5006) - Indicateur d'état + bouton de démarrage si cleaner down - Service systemd rpa-session-cleaner intégré au target rpa-vision - svc.sh et services.conf incluent session-cleaner (port 5006) P0-A — Auth dashboard Flask : - HTTP Basic obligatoire sur tous les endpoints (sauf /health, /healthz) - Credentials via DASHBOARD_USER + DASHBOARD_PASSWORD - 13 tests Nettoyage UI : - Section "Détection Visuelle" OWL retirée (modèle remplacé par pipeline VLM) - Dashboard préfère auto shot_*_blurred.png (avec ?raw=1 pour brut) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -69,6 +69,7 @@
|
||||
<div class="tab" onclick="switchTab('corrections')">🔧 Corrections</div>
|
||||
<div class="tab" onclick="switchTab('learning')">🧠 Apprentissage</div>
|
||||
<div class="tab" onclick="switchTab('config')">🔧 Configuration</div>
|
||||
<div class="tab" onclick="switchTab('cleaner')">🧹 Nettoyage</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
@@ -783,6 +784,14 @@
|
||||
<button class="btn btn-small btn-primary" onclick="testConnection('service', 'upload_api')">Test</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="config-item">
|
||||
<label>Session Cleaner (port 5006)</label>
|
||||
<div style="display:flex;gap:10px;">
|
||||
<input type="text" id="cfg_session_cleaner_host" placeholder="localhost" class="config-input" style="flex:2;">
|
||||
<input type="number" id="cfg_session_cleaner_port" placeholder="5006" class="config-input" style="flex:1;">
|
||||
<button class="btn btn-small btn-primary" onclick="testConnection('service', 'session_cleaner')">Test</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -834,37 +843,6 @@
|
||||
</div>
|
||||
|
||||
<div class="grid grid-2">
|
||||
<!-- Section Detection -->
|
||||
<div class="card">
|
||||
<h2><span class="icon">👁️</span> Detection Visuelle</h2>
|
||||
<div id="configDetection" class="config-section">
|
||||
<div class="config-item">
|
||||
<label>Modele OWL</label>
|
||||
<select id="cfg_detection_owl_model" class="config-input">
|
||||
<option value="google/owlv2-base-patch16-ensemble">OWLv2 Base Ensemble</option>
|
||||
<option value="google/owlv2-large-patch14-ensemble">OWLv2 Large Ensemble</option>
|
||||
<option value="google/owlvit-base-patch32">OWLViT Base</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="config-item">
|
||||
<label>Seuil de confiance</label>
|
||||
<input type="range" id="cfg_detection_confidence" min="0.1" max="0.9" step="0.05" value="0.3" class="config-input" oninput="document.getElementById('confValue').textContent = this.value">
|
||||
<span id="confValue" style="color:#3b82f6;margin-left:10px;">0.3</span>
|
||||
</div>
|
||||
<div class="config-item">
|
||||
<label>Seuil NMS</label>
|
||||
<input type="range" id="cfg_detection_nms" min="0.1" max="0.9" step="0.05" value="0.3" class="config-input" oninput="document.getElementById('nmsValue').textContent = this.value">
|
||||
<span id="nmsValue" style="color:#3b82f6;margin-left:10px;">0.3</span>
|
||||
</div>
|
||||
<div class="config-item">
|
||||
<label>
|
||||
<input type="checkbox" id="cfg_detection_use_gpu" checked>
|
||||
Utiliser GPU (CUDA)
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Section Base de donnees -->
|
||||
<div class="card">
|
||||
<h2><span class="icon">💾</span> Base de Donnees</h2>
|
||||
@@ -896,9 +874,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-2">
|
||||
<!-- Section Securite -->
|
||||
<div class="card">
|
||||
<h2><span class="icon">🔒</span> Securite</h2>
|
||||
@@ -963,6 +939,46 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tab: Nettoyage de sessions (iframe vers session_cleaner port 5006) -->
|
||||
<div id="tab-cleaner" class="tab-content">
|
||||
<div class="card" style="margin-bottom:20px;background:linear-gradient(135deg, #1e293b 0%, #0f172a 100%);">
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:15px;">
|
||||
<div>
|
||||
<h2 style="margin-bottom:5px;color:#e2e8f0;"><span class="icon">🧹</span> Nettoyage de sessions avant replay</h2>
|
||||
<p style="color:#64748b;font-size:13px;">Visualisez les sessions, supprimez les clics parasites et regénérez un replay propre (Session Cleaner, port 5006)</p>
|
||||
</div>
|
||||
<div style="display:flex;gap:10px;">
|
||||
<button class="btn btn-primary" onclick="refreshCleanerFrame()">🔄 Recharger</button>
|
||||
<a class="btn btn-secondary" href="http://localhost:5006" target="_blank" rel="noopener">↗ Ouvrir dans un onglet</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Message d'état (affiché si le service n'est pas démarré) -->
|
||||
<div id="cleanerOfflineNotice" class="card" style="display:none;margin-bottom:20px;border:1px solid #ef4444;">
|
||||
<div style="display:flex;align-items:center;gap:20px;flex-wrap:wrap;">
|
||||
<div style="font-size:48px;">⚠️</div>
|
||||
<div style="flex:1;min-width:250px;">
|
||||
<h3 style="color:#ef4444;margin-bottom:8px;">Session Cleaner non démarré</h3>
|
||||
<p style="color:#94a3b8;font-size:13px;">Le service sur le port 5006 ne répond pas. Démarrez-le pour accéder à l'interface de nettoyage.</p>
|
||||
</div>
|
||||
<div style="display:flex;gap:10px;">
|
||||
<button class="btn btn-success" onclick="startCleanerService()" id="btnStartCleaner">▶️ Démarrer le cleaner</button>
|
||||
<button class="btn btn-secondary" onclick="switchTab('services')">🎛️ Gérer les services</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- iframe vers le cleaner -->
|
||||
<div id="cleanerFrameContainer" class="card" style="padding:0;overflow:hidden;">
|
||||
<iframe
|
||||
id="cleanerFrame"
|
||||
src="about:blank"
|
||||
style="width:100%;height:85vh;min-height:800px;border:0;border-radius:12px;background:#0f172a;"
|
||||
title="Session Cleaner"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
@@ -1199,6 +1215,73 @@
|
||||
if (tabName === 'corrections') refreshCorrectionPacks();
|
||||
if (tabName === 'learning') refreshLearningStats();
|
||||
if (tabName === 'config') refreshConfig();
|
||||
if (tabName === 'cleaner') checkCleanerStatus();
|
||||
}
|
||||
|
||||
// === Session Cleaner (iframe vers port 5006) ===
|
||||
const CLEANER_URL = 'http://localhost:5006';
|
||||
|
||||
async function checkCleanerStatus() {
|
||||
const notice = document.getElementById('cleanerOfflineNotice');
|
||||
const frameContainer = document.getElementById('cleanerFrameContainer');
|
||||
const frame = document.getElementById('cleanerFrame');
|
||||
if (!notice || !frameContainer || !frame) return;
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/services/session_cleaner/status');
|
||||
const data = await res.json();
|
||||
const running = data && data.status === 'running';
|
||||
|
||||
if (running) {
|
||||
notice.style.display = 'none';
|
||||
frameContainer.style.display = 'block';
|
||||
// Charger l'iframe seulement si ce n'est pas déjà fait
|
||||
if (frame.src === 'about:blank' || !frame.src.startsWith(CLEANER_URL)) {
|
||||
frame.src = CLEANER_URL;
|
||||
}
|
||||
} else {
|
||||
notice.style.display = 'block';
|
||||
frameContainer.style.display = 'none';
|
||||
frame.src = 'about:blank';
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('checkCleanerStatus error:', err);
|
||||
notice.style.display = 'block';
|
||||
frameContainer.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
function refreshCleanerFrame() {
|
||||
const frame = document.getElementById('cleanerFrame');
|
||||
if (!frame) return;
|
||||
// Forcer un rechargement (cache busting)
|
||||
frame.src = CLEANER_URL + '?t=' + Date.now();
|
||||
}
|
||||
|
||||
async function startCleanerService() {
|
||||
const btn = document.getElementById('btnStartCleaner');
|
||||
if (btn) {
|
||||
btn.disabled = true;
|
||||
btn.textContent = '⏳ Démarrage...';
|
||||
}
|
||||
try {
|
||||
const res = await fetch('/api/services/session_cleaner/start', { method: 'POST' });
|
||||
const data = await res.json();
|
||||
if (!res.ok) {
|
||||
alert('Erreur : ' + (data.error || 'démarrage impossible'));
|
||||
} else {
|
||||
// Laisser le temps au service de démarrer
|
||||
await new Promise(r => setTimeout(r, 1500));
|
||||
}
|
||||
} catch (err) {
|
||||
alert('Erreur réseau : ' + err.message);
|
||||
} finally {
|
||||
if (btn) {
|
||||
btn.disabled = false;
|
||||
btn.textContent = '▶️ Démarrer le cleaner';
|
||||
}
|
||||
await checkCleanerStatus();
|
||||
}
|
||||
}
|
||||
|
||||
// Update execution UI
|
||||
@@ -2852,15 +2935,7 @@
|
||||
refreshOllamaModels();
|
||||
}
|
||||
|
||||
// Detection
|
||||
if (config.detection) {
|
||||
document.getElementById('cfg_detection_owl_model').value = config.detection.owl_model || 'google/owlv2-base-patch16-ensemble';
|
||||
document.getElementById('cfg_detection_confidence').value = config.detection.confidence_threshold || 0.3;
|
||||
document.getElementById('confValue').textContent = config.detection.confidence_threshold || 0.3;
|
||||
document.getElementById('cfg_detection_nms').value = config.detection.nms_threshold || 0.3;
|
||||
document.getElementById('nmsValue').textContent = config.detection.nms_threshold || 0.3;
|
||||
document.getElementById('cfg_detection_use_gpu').checked = config.detection.use_gpu !== false;
|
||||
}
|
||||
// Detection (OWL-v2 legacy) — section UI retiree, config preservee telle quelle
|
||||
|
||||
// Database
|
||||
if (config.database) {
|
||||
@@ -2936,12 +3011,14 @@
|
||||
model: document.getElementById('cfg_vlm_model').value,
|
||||
description: 'Modele VLM pour l\'analyse visuelle'
|
||||
},
|
||||
detection: {
|
||||
owl_model: document.getElementById('cfg_detection_owl_model').value,
|
||||
confidence_threshold: parseFloat(document.getElementById('cfg_detection_confidence').value),
|
||||
nms_threshold: parseFloat(document.getElementById('cfg_detection_nms').value),
|
||||
use_gpu: document.getElementById('cfg_detection_use_gpu').checked,
|
||||
description: 'Configuration du detecteur visuel OWL-v2'
|
||||
// Detection: section UI retiree (OWL-v2 remplace par pipeline VLM).
|
||||
// On preserve la config existante pour le fallback eventuel.
|
||||
detection: currentConfig.detection || {
|
||||
owl_model: 'google/owlv2-base-patch16-ensemble',
|
||||
confidence_threshold: 0.3,
|
||||
nms_threshold: 0.3,
|
||||
use_gpu: true,
|
||||
description: 'Configuration legacy du detecteur visuel OWL-v2 (fallback)'
|
||||
},
|
||||
embedding: currentConfig.embedding || {
|
||||
model: 'clip',
|
||||
|
||||
Reference in New Issue
Block a user