"""FormatSelector — mappa tipo_contenuto x livello_schwartz -> formato_narrativo. Carica la matrice di mapping da format_mapping.json e seleziona il formato narrativo più efficace per ogni combinazione di tipo e livello. """ from __future__ import annotations import json from pathlib import Path # Percorso default al file JSON (relativo a questo modulo) _DEFAULT_MAPPING_PATH = Path(__file__).parent.parent / "data" / "format_mapping.json" # Fallback se la combinazione non è presente nella matrice _FALLBACK_FORMAT = "PAS" class FormatSelector: """Seleziona il formato narrativo ottimale per un dato tipo_contenuto e livello_schwartz. Carica la matrice di mapping da un file JSON e la mantiene in memoria. La selezione è deterministica e basata sulla tabella (nessuna logica LLM). Esempio: selector = FormatSelector() formato = selector.select_format("valore", "L4") # -> "PAS" formato = selector.select_format("storytelling", "L5") # -> "BAB" """ def __init__(self, mapping_path: Path | None = None) -> None: """Carica il mapping da file JSON. Args: mapping_path: Percorso al file format_mapping.json. Default: backend/data/format_mapping.json """ path = mapping_path or _DEFAULT_MAPPING_PATH if not path.exists(): raise FileNotFoundError( f"File format_mapping.json non trovato: {path}. " "Assicurati che backend/data/format_mapping.json esista." ) with path.open(encoding="utf-8") as f: raw = json.load(f) # Filtra i commenti (chiavi che iniziano con "_") self._mapping: dict[str, dict[str, str]] = { k: v for k, v in raw.items() if not k.startswith("_") } def select_format(self, tipo_contenuto: str, livello_schwartz: str) -> str: """Ritorna il formato narrativo per la combinazione data. Args: tipo_contenuto: Tipo PN (es. "valore", "storytelling", "promozione") livello_schwartz: Livello consapevolezza (es. "L1", "L3", "L5") Returns: Nome del formato narrativo (es. "PAS", "BAB", "AIDA"). Ritorna "PAS" come fallback se la combinazione non è nella matrice. """ tipo_map = self._mapping.get(tipo_contenuto) if tipo_map is None: return _FALLBACK_FORMAT return tipo_map.get(livello_schwartz, _FALLBACK_FORMAT) def get_mapping(self) -> dict[str, dict[str, str]]: """Ritorna la tabella di mapping completa. Returns: Dizionario { tipo_contenuto: { livello_schwartz: formato_narrativo } } """ return dict(self._mapping) def get_supported_types(self) -> list[str]: """Ritorna la lista dei tipi_contenuto supportati dalla matrice.""" return list(self._mapping.keys()) def get_supported_levels(self) -> list[str]: """Ritorna la lista dei livelli_schwartz supportati dalla matrice. Inferisce i livelli dal primo tipo disponibile (la matrice è consistente). """ if not self._mapping: return [] first_type = next(iter(self._mapping.values())) return sorted(first_type.keys())