import logging import traceback import sys from enum import Enum # ── Logging setup ───────────────────────────────────────────────────────────── LOG_FORMAT = "[%(asctime)s] %(levelname)-8s %(name)s — %(message)s" DATE_FORMAT = "%H:%M:%S" logging.basicConfig( level=logging.DEBUG, format=LOG_FORMAT, datefmt=DATE_FORMAT, handlers=[ logging.StreamHandler(sys.stdout), logging.FileHandler("generai.log", encoding="utf-8"), ], ) def get_logger(name: str) -> logging.Logger: return logging.getLogger(name) # ── Error categories ─────────────────────────────────────────────────────────── class ErrorCode(Enum): # DB / Knowledge Base KB_INIT_FAILED = "KB-001" KB_SEARCH_FAILED = "KB-002" KB_WRITE_FAILED = "KB-003" KB_REINFORCE_FAILED = "KB-004" KB_SEED_FAILED = "KB-005" # Scraper / Web WEB_SEARCH_FAILED = "WEB-001" WEB_FETCH_FAILED = "WEB-002" WEB_EXTRACT_FAILED = "WEB-003" WEB_NO_RESULTS = "WEB-004" # Brain BRAIN_ASK_FAILED = "BRN-001" BRAIN_ASYNC_FAILED = "BRN-002" # UI UI_INPUT_EMPTY = "UI-001" UI_HANDLER_FAILED = "UI-002" class GenerAIError(Exception): """Base exception with error code and user-friendly message.""" def __init__(self, code: ErrorCode, detail: str, cause: Exception | None = None): self.code = code self.detail = detail self.cause = cause super().__init__(f"[{code.value}] {detail}") def user_message(self) -> str: cause_str = f"\n> Causa: `{type(self.cause).__name__}: {self.cause}`" if self.cause else "" return f"⚠️ **Errore {self.code.value}** — {self.detail}{cause_str}" def log(self, logger: logging.Logger): logger.error("[%s] %s", self.code.value, self.detail) if self.cause: logger.debug("Traceback originale:\n%s", "".join(traceback.format_exception(type(self.cause), self.cause, self.cause.__traceback__))) def fmt_exc(e: Exception) -> str: """One-line summary of an exception for log messages.""" return f"{type(e).__name__}: {e}"