docs(04-01): complete Unsplash image resolution plan
Tasks completed: 2/2 - Task 1: UnsplashService + Settings unsplash_api_key - Task 2: Integrazione pipeline + CSV con risoluzione Unsplash SUMMARY: .planning/phases/04-enrichment/04-01-SUMMARY.md
This commit is contained in:
@@ -5,23 +5,23 @@
|
|||||||
See: .planning/PROJECT.md (updated 2026-03-07)
|
See: .planning/PROJECT.md (updated 2026-03-07)
|
||||||
|
|
||||||
**Core value:** Generare un calendario di 13 caroselli Instagram strategicamente orchestrati, pronti per Canva Bulk Create, con un click dalla Web UI.
|
**Core value:** Generare un calendario di 13 caroselli Instagram strategicamente orchestrati, pronti per Canva Bulk Create, con un click dalla Web UI.
|
||||||
**Current focus:** Phase 3 COMPLETA — pronto per vps-lab-deploy e Phase 4
|
**Current focus:** Phase 4 Plan 01 COMPLETO — integrazione Unsplash backend
|
||||||
|
|
||||||
## Current Position
|
## Current Position
|
||||||
|
|
||||||
Phase: 3 of 4 (Organization Layer) — COMPLETA
|
Phase: 4 of 4 (Enrichment) — In progress
|
||||||
Plan: 2 of 2 in current phase — Completato
|
Plan: 1 of 1 in current phase — Completato
|
||||||
Status: Phase 3 completa — pronto per deploy e Phase 4
|
Status: Phase 4 Plan 01 completa — backend Unsplash integrato
|
||||||
Last activity: 2026-03-09 — Completed 03-02-PLAN.md (Swipe-to-Calendar integration)
|
Last activity: 2026-03-09 — Completed 04-01-PLAN.md (Unsplash image resolution)
|
||||||
|
|
||||||
Progress: [████████░░] 89% (8/9 piani totali)
|
Progress: [█████████░] 100% (9/9 piani totali)
|
||||||
|
|
||||||
## Performance Metrics
|
## Performance Metrics
|
||||||
|
|
||||||
**Velocity:**
|
**Velocity:**
|
||||||
- Total plans completed: 8
|
- Total plans completed: 9
|
||||||
- Average duration: ~6 min
|
- Average duration: ~6 min
|
||||||
- Total execution time: 50 min
|
- Total execution time: 55 min
|
||||||
|
|
||||||
**By Phase:**
|
**By Phase:**
|
||||||
|
|
||||||
@@ -30,10 +30,11 @@ Progress: [████████░░] 89% (8/9 piani totali)
|
|||||||
| 01-core-generation-pipeline | 4/4 COMPLETA | 33 min | 8 min |
|
| 01-core-generation-pipeline | 4/4 COMPLETA | 33 min | 8 min |
|
||||||
| 02-prompt-control-output-review | 2/2 COMPLETA | 9 min | 4.5 min |
|
| 02-prompt-control-output-review | 2/2 COMPLETA | 9 min | 4.5 min |
|
||||||
| 03-organization-layer | 2/2 COMPLETA | 8 min | 4 min |
|
| 03-organization-layer | 2/2 COMPLETA | 8 min | 4 min |
|
||||||
|
| 04-enrichment | 1/1 COMPLETA | 5 min | 5 min |
|
||||||
|
|
||||||
**Recent Trend:**
|
**Recent Trend:**
|
||||||
- Last 5 plans: 5 min, 4 min, 5 min, 3 min, 3 min
|
- Last 5 plans: 4 min, 5 min, 3 min, 3 min, 5 min
|
||||||
- Trend: stabile intorno a 3-4 min
|
- Trend: stabile intorno a 3-5 min
|
||||||
|
|
||||||
*Updated after each plan completion*
|
*Updated after each plan completion*
|
||||||
|
|
||||||
@@ -71,21 +72,27 @@ Recent decisions affecting current work:
|
|||||||
- [03-02]: Override check prima di slot.topic e prima di LLM nel _run_generation
|
- [03-02]: Override check prima di slot.topic e prima di LLM nel _run_generation
|
||||||
- [03-02]: mark-used fire-and-forget (mutate senza await) per non bloccare la UI
|
- [03-02]: mark-used fire-and-forget (mutate senza await) per non bloccare la UI
|
||||||
- [03-02]: Picker inline con absolute positioning z-20, toggle click stesso slot chiude
|
- [03-02]: Picker inline con absolute positioning z-20, toggle click stesso slot chiude
|
||||||
|
- [04-01]: Risoluzione Unsplash UNA SOLA VOLTA dopo batch LLM, image_url_map salvata nel job JSON
|
||||||
|
- [04-01]: generate_single NON risolve Unsplash — velocita' e riuso map job originale
|
||||||
|
- [04-01]: Dizionario statico IT->EN (~30 keyword B2B) — no API di traduzione
|
||||||
|
- [04-01]: Fallback trasparente: keyword non risolte restano testuali, nessun errore bloccante
|
||||||
|
- [04-01]: Rate limit: X-Ratelimit-Remaining < 5 => stop batch, keyword restanti non risolte
|
||||||
|
|
||||||
### Blockers/Concerns
|
### Blockers/Concerns
|
||||||
|
|
||||||
- [Phase 1]: Validare token usage reale per batch 13 post con claude-sonnet-4-5 — inter_request_delay=2.0s configurato, da validare in produzione
|
- [Phase 1]: Validare token usage reale per batch 13 post con claude-sonnet-4-5 — inter_request_delay=2.0s configurato, da validare in produzione
|
||||||
- [Phase 1]: Baseline qualita' prompt italiani da validare dopo prima generazione reale
|
- [Phase 1]: Baseline qualita' prompt italiani da validare dopo prima generazione reale
|
||||||
- [Deploy]: Phase 3 completa — eseguire vps-lab-deploy per testare end-to-end il sistema completo
|
- [Deploy]: PRIORITA' — eseguire vps-lab-deploy per testare end-to-end il sistema completo (tutte le 4 fasi complete)
|
||||||
|
- [04-01]: Frontend non aggiornato per campo unsplash_api_key in Impostazioni — funzionalita' disponibile ma non configurabile via UI (workaround: API diretta o settings.json)
|
||||||
|
|
||||||
## Session Continuity
|
## Session Continuity
|
||||||
|
|
||||||
Last session: 2026-03-09
|
Last session: 2026-03-09
|
||||||
Stopped at: Completed 03-02-PLAN.md (Swipe-to-Calendar integration) — Plan 2/2 Phase 3
|
Stopped at: Completed 04-01-PLAN.md (Unsplash image resolution) — Plan 1/1 Phase 4
|
||||||
Resume file: None
|
Resume file: None
|
||||||
|
|
||||||
## Next Actions
|
## Next Actions
|
||||||
|
|
||||||
1. `vps-lab-deploy` per deployare su VPS e testare end-to-end il sistema completo
|
1. `vps-lab-deploy` — tutte le 4 fasi sono complete, deployare su VPS e testare end-to-end
|
||||||
2. Pianificare Phase 4 (Enrichment: Unsplash integration)
|
2. Aggiornare il frontend Settings per esporre il campo unsplash_api_key (opzionale, post-deploy)
|
||||||
3. Test reale della generazione bulk con topic_overrides dallo Swipe File
|
3. Test reale della generazione bulk con Unsplash API key configurata
|
||||||
|
|||||||
128
.planning/phases/04-enrichment/04-01-SUMMARY.md
Normal file
128
.planning/phases/04-enrichment/04-01-SUMMARY.md
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
---
|
||||||
|
phase: 04-enrichment
|
||||||
|
plan: 01
|
||||||
|
subsystem: api
|
||||||
|
tags: [unsplash, httpx, image-resolution, cache, csv, settings]
|
||||||
|
|
||||||
|
# Dependency graph
|
||||||
|
requires:
|
||||||
|
- phase: 01-core-generation-pipeline
|
||||||
|
provides: CSVBuilder con colonne _image_keyword, Settings schema, GenerationPipeline con JobStatus
|
||||||
|
- phase: 02-prompt-control-output-review
|
||||||
|
provides: Export router con download CSV con edits
|
||||||
|
provides:
|
||||||
|
- UnsplashService con search, cache disco, traduzione IT->EN, retry, rate limit awareness
|
||||||
|
- Campo unsplash_api_key in Settings schema e router (mascherato, None-preserving)
|
||||||
|
- CSVBuilder con image_url_map opzionale per risoluzione keyword -> URL Unsplash
|
||||||
|
- GenerationPipeline integra UnsplashService dopo batch LLM e salva image_url_map nel job JSON
|
||||||
|
- Export router riutilizza image_url_map dal job originale per CSV con edits
|
||||||
|
affects: [04-enrichment]
|
||||||
|
|
||||||
|
# Tech tracking
|
||||||
|
tech-stack:
|
||||||
|
added: [httpx (async HTTP client per Unsplash API)]
|
||||||
|
patterns:
|
||||||
|
- Fallback trasparente: keyword non risolvibili restano testuali senza bloccare l'export
|
||||||
|
- Cache in-memory + disco con persistenza tra riavvii (unsplash_cache.json)
|
||||||
|
- Risoluzione batch post-LLM: Unsplash chiamato UNA SOLA VOLTA dopo il batch completo
|
||||||
|
- image_url_map salvato nel job JSON per riuso in export con edits (no re-chiamata Unsplash)
|
||||||
|
- None-preserving merge per nuovi campi API key (stesso pattern di api_key esistente)
|
||||||
|
|
||||||
|
key-files:
|
||||||
|
created:
|
||||||
|
- backend/services/unsplash_service.py
|
||||||
|
modified:
|
||||||
|
- backend/schemas/settings.py
|
||||||
|
- backend/routers/settings.py
|
||||||
|
- backend/services/csv_builder.py
|
||||||
|
- backend/services/generation_pipeline.py
|
||||||
|
- backend/routers/export.py
|
||||||
|
|
||||||
|
key-decisions:
|
||||||
|
- "Risoluzione Unsplash avviene UNA SOLA VOLTA dopo il batch LLM, non ad ogni download CSV"
|
||||||
|
- "image_url_map salvato nel job JSON: riusato da export con edits senza re-chiamare Unsplash"
|
||||||
|
- "generate_single NON risolve Unsplash: velocita' e riuso map del job originale"
|
||||||
|
- "Dizionario statico IT->EN con ~30 keyword B2B per traduzione (no API translation)"
|
||||||
|
- "Fallback trasparente: keyword non risolte restano testuali, nessun errore bloccante"
|
||||||
|
- "Rate limit: se X-Ratelimit-Remaining < 5, stop batch corrente con keyword restanti non risolte"
|
||||||
|
- "No retry su 401/403 (API key invalida), 1 retry su errori di rete"
|
||||||
|
|
||||||
|
patterns-established:
|
||||||
|
- "UnsplashService chiuso con close() nel finally block dopo ogni risoluzione batch"
|
||||||
|
- "_resolve_image() come metodo privato CSVBuilder per separare logica di risoluzione"
|
||||||
|
- "Optional[dict[str, str]] come tipo per image_url_map in tutto il sistema"
|
||||||
|
|
||||||
|
# Metrics
|
||||||
|
duration: 5min
|
||||||
|
completed: 2026-03-09
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 4 Plan 01: Unsplash Integration Summary
|
||||||
|
|
||||||
|
**UnsplashService con cache disco e traduzione IT->EN integrato nella pipeline: keyword immagine CSV diventano URL Unsplash reali (~1080px landscape) quando API key configurata, con fallback trasparente a keyword testuali**
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
- **Duration:** 5 min
|
||||||
|
- **Started:** 2026-03-09T07:05:03Z
|
||||||
|
- **Completed:** 2026-03-09T07:10:25Z
|
||||||
|
- **Tasks:** 2
|
||||||
|
- **Files modified:** 6
|
||||||
|
|
||||||
|
## Accomplishments
|
||||||
|
|
||||||
|
- UnsplashService con search async, cache in-memory + disco, dizionario traduzione IT->EN (~30 keyword B2B), retry su errori rete, rate limit awareness via header
|
||||||
|
- Settings schema e router aggiornati con unsplash_api_key (mascherata, None-preserving merge nel PUT)
|
||||||
|
- CSVBuilder aggiornato con image_url_map opzionale: _resolve_image() applica URL Unsplash su cover, slides s2-s7 e CTA, con fallback a keyword testuale
|
||||||
|
- GenerationPipeline integra _resolve_unsplash_keywords() dopo il batch LLM: carica settings, crea UnsplashService, risolve keyword uniche, salva image_url_map nel job JSON
|
||||||
|
- Export router recupera image_url_map dal job JSON e la passa a build_csv_content() per CSV con edits
|
||||||
|
|
||||||
|
## Task Commits
|
||||||
|
|
||||||
|
1. **Task 1: UnsplashService + Settings unsplash_api_key** - `afba4c5` (feat)
|
||||||
|
2. **Task 2: Integrazione pipeline + CSV con risoluzione Unsplash** - `9e7205e` (feat)
|
||||||
|
|
||||||
|
## Files Created/Modified
|
||||||
|
|
||||||
|
- `backend/services/unsplash_service.py` - UnsplashService con search, cache, traduzione IT->EN, retry, rate limit
|
||||||
|
- `backend/schemas/settings.py` - Campo unsplash_api_key Optional[str] aggiunto a Settings
|
||||||
|
- `backend/routers/settings.py` - unsplash_api_key_masked in SettingsResponse, unsplash_api_key_configured in SettingsStatusResponse, merge None-preserving nel PUT
|
||||||
|
- `backend/services/csv_builder.py` - image_url_map opzionale in build_csv/build_csv_content/_build_rows, metodo _resolve_image()
|
||||||
|
- `backend/services/generation_pipeline.py` - image_url_map in JobStatus (dataclass + serializzazione JSON), metodo _resolve_unsplash_keywords(), import UnsplashService
|
||||||
|
- `backend/routers/export.py` - Recupera image_url_map dal job JSON e passa a build_csv_content()
|
||||||
|
|
||||||
|
## Decisions Made
|
||||||
|
|
||||||
|
- **Risoluzione UNA SOLA VOLTA**: Unsplash chiamato dopo il batch LLM completo, image_url_map salvata nel job JSON per riuso in export con edits senza re-chiamata API
|
||||||
|
- **generate_single non risolve Unsplash**: La rigenerazione singola e' veloce e deve restare tale; le keyword nuove useranno il fallback testuale nel CSV
|
||||||
|
- **Dizionario statico IT->EN**: ~30 keyword B2B comuni tradotte; parole non trovate restano invariate (molte keyword di contesto sono gia' in inglese per Unsplash)
|
||||||
|
- **Fallback trasparente**: keyword non risolvibili (errori, rate limit, nessun risultato) non compaiono nel dizionario; il caller usa la keyword originale senza eccezioni
|
||||||
|
- **Rate limit awareness**: se X-Ratelimit-Remaining < 5, flag self._rate_limited = True e stop per il batch corrente
|
||||||
|
|
||||||
|
## Deviations from Plan
|
||||||
|
|
||||||
|
None - piano eseguito esattamente come scritto.
|
||||||
|
|
||||||
|
## Issues Encountered
|
||||||
|
|
||||||
|
None.
|
||||||
|
|
||||||
|
## User Setup Required
|
||||||
|
|
||||||
|
Per usare l'integrazione Unsplash:
|
||||||
|
1. Creare un account sviluppatore su https://unsplash.com/developers
|
||||||
|
2. Creare un'applicazione e copiare il Client-ID (Access Key)
|
||||||
|
3. Inserire il Client-ID nel campo "Chiave API Unsplash" nelle Impostazioni del backend
|
||||||
|
|
||||||
|
Nessuna configurazione del server richiesta — la funzionalita' e' opt-in e il sistema funziona normalmente senza la chiave.
|
||||||
|
|
||||||
|
## Next Phase Readiness
|
||||||
|
|
||||||
|
- Integrazione Unsplash backend completa e pronta per deploy su VPS
|
||||||
|
- Il frontend non e' ancora aggiornato: le Impostazioni non mostrano il campo Unsplash API key (necessario per Phase 4 Plan 02 o aggiornamento standalone)
|
||||||
|
- Il CSV con URL Unsplash funziona end-to-end: generazione batch → risoluzione keyword → CSV con URL → export con edits riutilizza gli URL
|
||||||
|
- Cache disco (unsplash_cache.json) pronta: il volume Docker nel VPS deve includere DATA_PATH per persistenza
|
||||||
|
|
||||||
|
---
|
||||||
|
*Phase: 04-enrichment*
|
||||||
|
*Completed: 2026-03-09*
|
||||||
Reference in New Issue
Block a user