feat(01-03): API routers (calendar, generate, export, settings) e wiring main.py

- schemas/settings.py: Settings pydantic model con api_key, llm_model, nicchie_attive, tono
- routers/calendar.py: POST /api/calendar/generate, GET /api/calendar/formats
- routers/generate.py: POST /api/generate/bulk (202 + job_id), GET /job/{job_id}/status (polling), GET /job/{job_id}, POST /single
- routers/export.py: GET /api/export/{job_id}/csv (originale), POST /api/export/{job_id}/csv (modifiche inline)
- routers/settings.py: GET /api/settings/status (api_key_configured), GET /api/settings, PUT /api/settings
- main.py: include_router x4 PRIMA di SPAStaticFiles, copia prompt default al primo avvio
This commit is contained in:
Michele
2026-03-08 02:14:17 +01:00
parent 083621afd3
commit e06edde4ef
6 changed files with 694 additions and 1 deletions

View File

@@ -0,0 +1,59 @@
"""Router per la gestione del calendario editoriale.
Endpoint:
- POST /api/calendar/generate — genera un calendario di 13 slot
- GET /api/calendar/formats — ritorna il mapping formati disponibili
"""
from __future__ import annotations
from fastapi import APIRouter
from backend.schemas.calendar import CalendarRequest, CalendarResponse
from backend.services.calendar_service import CalendarService
from backend.services.format_selector import FormatSelector
router = APIRouter(prefix="/api/calendar", tags=["calendar"])
# Istanze dei servizi (create una volta alla startup del router)
_format_selector = FormatSelector()
_calendar_service = CalendarService(format_selector=_format_selector)
@router.post("/generate", response_model=CalendarResponse)
async def generate_calendar(request: CalendarRequest) -> CalendarResponse:
"""Genera un calendario editoriale di 13 slot.
Produce un piano di pubblicazione con:
- Distribuzione PN (valore, storytelling, news, riprova_sociale, coinvolgimento, promozione)
- Livelli Schwartz L1-L5 corretti per ogni tipo di contenuto
- Formato narrativo selezionato automaticamente
- Date di pubblicazione suggerite
- Rotazione nicchie (50% generico, 50% verticali)
Args:
request: Parametri del calendario (obiettivo, settimane, nicchie, frequenza, data_inizio).
Returns:
CalendarResponse con 13 slot ordinati per fase funnel.
"""
return _calendar_service.generate_calendar(request)
@router.get("/formats")
async def get_formats() -> dict:
"""Ritorna il mapping completo dei formati narrativi disponibili.
Utile per il frontend per visualizzare quale formato viene usato
per ogni combinazione tipo_contenuto x livello_schwartz.
Returns:
Dict con le 30 combinazioni tipo x livello -> formato narrativo.
"""
return {
"mapping": _format_selector.get_mapping(),
"formati_disponibili": list(
set(_format_selector.get_mapping().values())
),
}