From 82d7b38cff89c74e8f880fa435bdfdf39223e4ca Mon Sep 17 00:00:00 2001 From: Dom Date: Mon, 20 Apr 2026 17:41:23 +0200 Subject: [PATCH] =?UTF-8?q?feat(dashboard):=20page=20Base=20de=20connaissa?= =?UTF-8?q?nces=20=E2=80=94=20m=C3=A9triques=20FAISS,=20sessions,=20patter?= =?UTF-8?q?ns?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nouvelle page /knowledge-base avec : - Mémoire visuelle : 331 vecteurs FAISS / 13666 embeddings (alerte consolidation) - Sessions observées : 56 sessions, 6.66 Go, 3 machines - Réflexes natifs : 16 patterns UI en 6 catégories - Workflows appris : 29 Onglet 📚 Connaissances ajouté dans toute la navigation. Tout en français, dark theme, zéro jargon. Co-Authored-By: Claude Opus 4.6 (1M context) --- web_dashboard/app.py | 164 +++++++++++ web_dashboard/templates/audit.html | 1 + web_dashboard/templates/index.html | 1 + web_dashboard/templates/knowledge_base.html | 294 ++++++++++++++++++++ web_dashboard/templates/process_mining.html | 1 + 5 files changed, 461 insertions(+) create mode 100644 web_dashboard/templates/knowledge_base.html diff --git a/web_dashboard/app.py b/web_dashboard/app.py index 30fd50606..ed738a54c 100644 --- a/web_dashboard/app.py +++ b/web_dashboard/app.py @@ -2445,6 +2445,170 @@ def proxy_audit(endpoint): return jsonify({'error': str(e)}), 500 +# ============================================================================= +# Base de connaissances — État mémoire et apprentissages +# ============================================================================= + +@app.route('/knowledge-base') +def knowledge_base_page(): + """Page Base de connaissances.""" + return render_template('knowledge_base.html') + + +@app.route('/api/knowledge-base/stats') +def knowledge_base_stats(): + """Retourne toutes les métriques de la base de connaissances en JSON.""" + import glob as glob_module + + result = { + 'faiss': _kb_faiss_stats(), + 'sessions': _kb_sessions_stats(), + 'patterns': _kb_patterns_stats(), + 'workflows': _kb_workflows_stats(), + } + return jsonify(result) + + +def _kb_faiss_stats() -> dict: + """Statistiques de l'index FAISS.""" + faiss_index_path = DATA_PATH / "faiss_index" / "main.index" + embeddings_dir = LIVE_SESSIONS_PATH / "embeddings" + + vectors_indexed = 0 + index_size_mb = "0 Mo" + available = False + + if faiss_index_path.exists(): + # Taille fichier + size_bytes = faiss_index_path.stat().st_size + index_size_mb = f"{size_bytes / (1024 * 1024):.1f} Mo" + + # Nombre de vecteurs via faiss + try: + import faiss + index = faiss.read_index(str(faiss_index_path)) + vectors_indexed = index.ntotal + available = True + except ImportError: + # FAISS non installé — lire le metadata si dispo + metadata_path = DATA_PATH / "faiss_index" / "main.metadata" + if metadata_path.exists(): + try: + meta = json.loads(metadata_path.read_text()) + vectors_indexed = meta.get('ntotal', 0) + available = True + except Exception: + pass + except Exception: + pass + else: + available = False + + # Compter les embeddings (.npy) + embeddings_computed = 0 + if embeddings_dir.exists(): + embeddings_computed = len(list(embeddings_dir.glob("*.npy"))) + + return { + 'vectors_indexed': vectors_indexed, + 'embeddings_computed': embeddings_computed, + 'index_size_mb': index_size_mb, + 'available': available, + } + + +def _kb_sessions_stats() -> dict: + """Statistiques des sessions shadow.""" + machines = [] + total_sessions = 0 + total_bytes = 0 + + if LIVE_SESSIONS_PATH.exists(): + for d in sorted(LIVE_SESSIONS_PATH.iterdir()): + if not d.is_dir(): + continue + # Ignorer le dossier embeddings + if d.name == 'embeddings': + continue + + # Dossiers machines (contiennent des sess_*) + if d.name.startswith('sess_'): + # Session orpheline à la racine + total_sessions += 1 + total_bytes += _dir_size(d) + else: + # Dossier machine + sess_dirs = [s for s in d.iterdir() if s.is_dir() and s.name.startswith('sess_')] + count = len(sess_dirs) + total_sessions += count + + # Dernière activité + last_activity = None + if sess_dirs: + latest = max(sess_dirs, key=lambda s: s.stat().st_mtime) + last_activity = datetime.fromtimestamp(latest.stat().st_mtime).strftime('%Y-%m-%d %H:%M') + + machine_bytes = _dir_size(d) + total_bytes += machine_bytes + + if count > 0: + machines.append({ + 'machine_id': d.name, + 'session_count': count, + 'last_activity': last_activity, + }) + + # Volume total + if total_bytes >= 1024 * 1024 * 1024: + total_volume = f"{total_bytes / (1024**3):.2f} Go" + elif total_bytes >= 1024 * 1024: + total_volume = f"{total_bytes / (1024**2):.1f} Mo" + else: + total_volume = f"{total_bytes / 1024:.0f} Ko" + + return { + 'total_sessions': total_sessions, + 'total_volume': total_volume, + 'machines': machines, + } + + +def _kb_patterns_stats() -> dict: + """Statistiques des patterns UI natifs.""" + try: + from core.knowledge.ui_patterns import UIPatternLibrary + lib = UIPatternLibrary() + stats = lib.stats + return { + 'total': stats.get('total', 0), + 'by_category': stats.get('by_category', {}), + } + except Exception: + return {'total': 0, 'by_category': {}} + + +def _kb_workflows_stats() -> dict: + """Statistiques des workflows appris.""" + total = 0 + workflows_path = DATA_PATH / "workflows" + if workflows_path.exists(): + # Compter récursivement les .json + total = len(list(workflows_path.rglob("*.json"))) + return {'total': total} + + +def _dir_size(path: Path) -> int: + """Calcule la taille totale d'un dossier (non récursif profond pour la perf).""" + total = 0 + try: + for f in path.rglob('*'): + if f.is_file(): + total += f.stat().st_size + except (PermissionError, OSError): + pass + return total + + # ============================================================================= # Main # ============================================================================= diff --git a/web_dashboard/templates/audit.html b/web_dashboard/templates/audit.html index 3a35734f8..d4ec8c9f8 100644 --- a/web_dashboard/templates/audit.html +++ b/web_dashboard/templates/audit.html @@ -175,6 +175,7 @@ 🎛️ Dashboard ⚖️ Audit 🗺️ Cartographie + 📚 Connaissances diff --git a/web_dashboard/templates/index.html b/web_dashboard/templates/index.html index b2326f615..304e6d0f6 100644 --- a/web_dashboard/templates/index.html +++ b/web_dashboard/templates/index.html @@ -65,6 +65,7 @@
🔧 Configuration
🧹 Nettoyage
🗺️ Cartographie + 📚 Connaissances
diff --git a/web_dashboard/templates/knowledge_base.html b/web_dashboard/templates/knowledge_base.html new file mode 100644 index 000000000..5abeadfe5 --- /dev/null +++ b/web_dashboard/templates/knowledge_base.html @@ -0,0 +1,294 @@ + + + + + + RPA Vision V3 - Base de connaissances + + + + + +
+
+

📚 Base de connaissances

+
État de la mémoire et des apprentissages de Léa
+
+ +
+ +
+ + +
🧠 Mémoire visuelle
+ +
+
+
--
+
Vecteurs indexés
+
+
+
--
+
Embeddings calculés
+
+
+
--
+
Taille de l'index
+
+
+ + + + +
👁️ Sessions observées
+ +
+
+
--
+
Sessions totales
+
+
+
--
+
Volume de données
+
+
+
--
+
Machines distinctes
+
+
+ +
+

🖥️ Répartition par machine

+
+ + + + + + + + + + + +
MachineSessionsDernière activité
Chargement...
+
+
+ + +
Réflexes natifs
+ +
+
+
--
+
Patterns connus
+
+
+ +
+

🎯 Par catégorie

+
    +
  • Chargement...
  • +
+
+ + +
🔄 Workflows
+ +
+
+
--
+
Workflows appris
+
+
+ +
+ + + + + diff --git a/web_dashboard/templates/process_mining.html b/web_dashboard/templates/process_mining.html index 9e5b24035..059b31b0c 100644 --- a/web_dashboard/templates/process_mining.html +++ b/web_dashboard/templates/process_mining.html @@ -148,6 +148,7 @@ 🎛️ Dashboard ⚖️ Audit 🗺️ Cartographie + 📚 Connaissances