feat(04-01): UnsplashService + Settings unsplash_api_key
- Crea UnsplashService con search, cache disco, traduzione IT->EN - ~30 keyword B2B italiane tradotte in dizionario statico - Cache in-memory + persistenza su disco (unsplash_cache.json) - Retry automatico su errori di rete, no-retry su 401/403 - Rate limiting awareness via X-Ratelimit-Remaining header - Aggiunge campo unsplash_api_key a Settings schema - Router settings espone unsplash_api_key_masked + configured - Merge None-preserving per unsplash_api_key nel PUT
This commit is contained in:
@@ -35,6 +35,7 @@ class SettingsStatusResponse(BaseModel):
|
||||
"""Risposta per GET /status — usata dal frontend per abilitare/disabilitare il pulsante genera."""
|
||||
api_key_configured: bool
|
||||
llm_model: str
|
||||
unsplash_api_key_configured: bool
|
||||
|
||||
|
||||
class SettingsResponse(BaseModel):
|
||||
@@ -46,6 +47,7 @@ class SettingsResponse(BaseModel):
|
||||
frequenza_post: int
|
||||
brand_name: Optional[str]
|
||||
tono: Optional[str]
|
||||
unsplash_api_key_masked: Optional[str] # Solo ultimi 4 caratteri o None
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -103,6 +105,7 @@ async def get_settings_status() -> SettingsStatusResponse:
|
||||
return SettingsStatusResponse(
|
||||
api_key_configured=bool(settings.api_key),
|
||||
llm_model=settings.llm_model,
|
||||
unsplash_api_key_configured=bool(settings.unsplash_api_key),
|
||||
)
|
||||
|
||||
|
||||
@@ -125,6 +128,7 @@ async def get_settings() -> SettingsResponse:
|
||||
frequenza_post=settings.frequenza_post,
|
||||
brand_name=settings.brand_name,
|
||||
tono=settings.tono,
|
||||
unsplash_api_key_masked=_mask_api_key(settings.unsplash_api_key),
|
||||
)
|
||||
|
||||
|
||||
@@ -149,8 +153,12 @@ async def update_settings(new_settings: Settings) -> SettingsResponse:
|
||||
if new_settings.api_key is None:
|
||||
new_settings = new_settings.model_copy(update={"api_key": existing.api_key})
|
||||
|
||||
# Se la nuova unsplash_api_key è None, mantieni quella esistente (stessa logica)
|
||||
if new_settings.unsplash_api_key is None:
|
||||
new_settings = new_settings.model_copy(update={"unsplash_api_key": existing.unsplash_api_key})
|
||||
|
||||
_save_settings(new_settings)
|
||||
logger.info("Settings aggiornate | model=%s | brand=%s", new_settings.llm_model, new_settings.brand_name)
|
||||
logger.info("Settings aggiornate | model=%s | brand=%s | unsplash=%s", new_settings.llm_model, new_settings.brand_name, bool(new_settings.unsplash_api_key))
|
||||
|
||||
return SettingsResponse(
|
||||
api_key_masked=_mask_api_key(new_settings.api_key),
|
||||
@@ -160,4 +168,5 @@ async def update_settings(new_settings: Settings) -> SettingsResponse:
|
||||
frequenza_post=new_settings.frequenza_post,
|
||||
brand_name=new_settings.brand_name,
|
||||
tono=new_settings.tono,
|
||||
unsplash_api_key_masked=_mask_api_key(new_settings.unsplash_api_key),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user