| 01-core-generation-pipeline |
03 |
api |
| python |
| fastapi |
| anthropic |
| pydantic |
| csv |
| asyncio |
| retry |
| backoff |
| rate-limit |
|
| phase |
provides |
| 01-core-generation-pipeline (plan 01) |
backend/config.py con OUTPUTS_PATH, CONFIG_PATH, PROMPTS_PATH |
|
| phase |
provides |
| 01-core-generation-pipeline (plan 02) |
CalendarService, PromptService, CANVA_FIELDS, GeneratedPost schema, TopicResult schema |
|
|
| LLMService con retry 3x, RateLimitError con lettura retry-after header, backoff esponenziale 5xx, validazione Pydantic con correzione automatica |
| CSVBuilder con encoding utf-8-sig, header CANVA_FIELDS locked, mapping GeneratedPost+CalendarSlot -> 33 colonne |
| GenerationPipeline con background task asyncio, _jobs dict real-time, per-item error isolation, persistenza JSON |
| API router calendar |
| POST /api/calendar/generate, GET /api/calendar/formats |
|
| API router generate |
| POST /api/generate/bulk (202+job_id), GET /job/{id}/status (polling), GET /job/{id}, POST /single |
|
| API router export |
| GET /api/export/{id}/csv (originale), POST /api/export/{id}/csv (modifiche inline) |
|
| API router settings |
| GET /api/settings/status, GET /api/settings, PUT /api/settings |
|
|
| 01-04 (frontend usa tutti questi endpoint API) |
| fase deploy (tutti gli endpoint da testare via HTTP) |
|
| added |
patterns |
| anthropic.Anthropic client (già in requirements.txt) |
| asyncio.create_task per background generazione |
|
| Retry pattern: RateLimitError con retry-after header esatto, 5xx con backoff esponenziale + jitter |
| Per-item isolation: try/except individuale per slot dentro il loop, non attorno al loop |
| Background task pattern: generate_bulk_async ritorna job_id, _run_generation gira in background |
| Job polling pattern: _jobs dict in-memory + file JSON su disco per resume post-restart |
| Settings masking: api_key mai inviata al frontend, solo ultimi 4 caratteri mostrati |
| CSV BOM: encoding utf-8-sig garantisce compatibilità Excel con caratteri italiani |
|
|
| created |
modified |
| backend/services/llm_service.py |
| backend/services/csv_builder.py |
| backend/services/generation_pipeline.py |
| backend/routers/calendar.py |
| backend/routers/generate.py |
| backend/routers/export.py |
| backend/routers/settings.py |
| backend/schemas/settings.py |
|
| backend/main.py (aggiunto include_router x4, copia prompt default al primo avvio) |
|
|
| LLMService._parse_retry_after() legge l'header 'retry-after' dalla response HTTP per wait esatto (non hardcoded) |
| GenerationPipeline usa asyncio.to_thread per wrap dei metodi LLM sincroni (time.sleep non blocca event loop) |
| Settings.api_key non sovrascritta con None se non inviata nel PUT body (merge con esistente) |
| POST /export/{job_id}/csv usa build_csv_content() che produce stringa, GET usa FileResponse da disco |
| Pipeline singleton in-memory in generate.py per mantenere _jobs tra request, con fallback da disco |
|
| Thin routers: nessuna logica di business nei router, solo validazione + chiamata service + return |
| API key loading: legge da settings.json con fallback a env var ANTHROPIC_API_KEY |
| Job lifecycle: running -> completed (con CSV su disco) | running -> failed (con error) |
|
8min |
2026-03-08 |