MORSATIPIK / error_tree.py
RDS777's picture
Upload error_tree.py
bf9f28b verified
Raw
History Blame Contribute Delete
3.02 kB
# core/error_tree.py
"""
Harbor — Arbre d'erreurs sémantique.
Mémorise les échecs, leurs causes, leçons et correctifs.
"""
import hashlib
import time
import json
import logging
from pathlib import Path
from typing import Dict, List
log = logging.getLogger("vortex.harbor")
class ErrorTree:
def __init__(self, storage_path: str = "data/error_tree.json"):
self.storage_path = Path(storage_path)
self.nodes: Dict[str, Dict] = {}
self.load()
def add_error(self, error_msg: str, context: str) -> str:
node_id = hashlib.sha256(f"{error_msg}{time.time()}".encode()).hexdigest()[:8]
self.nodes[node_id] = {
"error": error_msg,
"context": context[:500],
"lesson": None,
"fix": None,
"timestamp": time.time()
}
self.save()
log.info(f"[Harbor] Erreur enregistrée : {node_id}{error_msg[:50]}")
return node_id
def add_lesson(self, node_id: str, lesson: str, fix: str):
if node_id in self.nodes:
self.nodes[node_id]["lesson"] = lesson
self.nodes[node_id]["fix"] = fix
self.save()
log.info(f"[Harbor] Leçon ajoutée à {node_id}")
def search_similar(self, query: str) -> List[Dict]:
results = []
query_words = set(query.lower().split())
for nid, data in self.nodes.items():
error_words = set(data["error"].lower().split())
overlap = len(query_words & error_words)
if overlap > 0:
sim = overlap / max(len(query_words), 1)
results.append({
"id": nid,
"error": data["error"],
"lesson": data.get("lesson") or "Aucune leçon",
"fix": data.get("fix") or "Aucun correctif",
"similarity": round(sim, 3)
})
results.sort(key=lambda x: x["similarity"], reverse=True)
return results[:5]
def stats(self) -> Dict:
with_lessons = sum(1 for n in self.nodes.values() if n.get("lesson"))
return {
"total_errors": len(self.nodes),
"with_lessons": with_lessons
}
def save(self):
try:
self.storage_path.parent.mkdir(parents=True, exist_ok=True)
with open(self.storage_path, "w", encoding="utf-8") as f:
json.dump(self.nodes, f, indent=2, default=str, ensure_ascii=False)
except Exception as e:
log.error(f"[Harbor] Échec sauvegarde: {e}")
def load(self):
if self.storage_path.exists():
try:
with open(self.storage_path, "r", encoding="utf-8") as f:
self.nodes = json.load(f)
log.info(f"[Harbor] Chargé {len(self.nodes)} erreurs")
except Exception as e:
log.error(f"[Harbor] Échec chargement: {e}")
self.nodes = {}
else:
self.nodes = {}