"""Pydantic schemas per il calendario editoriale. Questi modelli rappresentano il piano di pubblicazione dei 13 slot PN generato da CalendarService, prima della generazione LLM del contenuto. """ from __future__ import annotations from typing import Optional from pydantic import BaseModel, Field class CalendarSlot(BaseModel): """Un singolo slot del calendario editoriale con metadati strategici.""" indice: int = Field( ..., ge=0, lt=13, description="Indice 0-based dello slot nel ciclo di 13 post", ) tipo_contenuto: str = Field( ..., description="Tipo Persuasion Nurturing: valore, storytelling, news, " "riprova_sociale, coinvolgimento, promozione", ) livello_schwartz: str = Field( ..., description="Livello di consapevolezza del pubblico: L1-L5", ) formato_narrativo: str = Field( ..., description="Formato narrativo selezionato: PAS, AIDA, BAB, Listicle, " "Storytelling, Dato_Implicazione, Obiezione_Risposta", ) funzione: str = Field( ..., description="Funzione editoriale: Intrattenere, Educare, Persuadere, Convertire", ) fase_campagna: str = Field( ..., description="Fase del funnel: Attira, Cattura, Coinvolgi, Converti", ) target_nicchia: str = Field( ..., description="Nicchia target: es. generico, dentisti, avvocati, ecommerce", ) data_pub_suggerita: str = Field( ..., description="Data di pubblicazione suggerita in formato YYYY-MM-DD", ) topic: Optional[str] = Field( default=None, description="Topic specifico del post. None finché non generato dall'LLM " "o specificato dall'utente.", ) class CalendarRequest(BaseModel): """Richiesta per generare un calendario editoriale.""" obiettivo_campagna: str = Field( ..., min_length=10, description="Obiettivo principale della campagna (es. 'Acquisire nuovi " "clienti dentisti nel Nord Italia')", ) settimane: int = Field( default=2, ge=1, le=12, description="Durata del ciclo in settimane (default: 2 settimane per 13 post)", ) nicchie: Optional[list[str]] = Field( default=None, description="Lista di nicchie target. Se None, usa NICCHIE_DEFAULT. " "'generico' viene sempre incluso automaticamente.", ) frequenza_post: int = Field( default=3, ge=1, le=7, description="Numero di post a settimana (default: 3 — lun, mer, ven)", ) data_inizio: Optional[str] = Field( default=None, description="Data di inizio del calendario in formato YYYY-MM-DD. " "Se None, usa la data corrente.", ) class CalendarResponse(BaseModel): """Risposta con il calendario editoriale generato.""" campagna: str = Field( ..., description="Riepilogo sintetico dell'obiettivo campagna", ) slots: list[CalendarSlot] = Field( ..., description="Lista di 13 slot del calendario ordinati per sequenza campagna " "(Attira → Cattura → Coinvolgi → Converti)", ) totale_post: int = Field( ..., description="Numero totale di slot generati (sempre 13 per ciclo completo)", )