Ogni articolo di questo blog, prima di oggi, aveva un problema estetico: nessuna copertina. PaperMod le mostra in home, nelle liste e in cima al post singolo — senza immagine, l’impaginato perde metà del suo impatto. Disegnarle a mano ogni volta, però, era il modo più rapido per non pubblicare niente.

Così ho aggiunto al mio CMS .NET + Angular una funzione che genera le copertine da sola, usando un modello di generazione immagini che gira già sul mio GX10: ComfyUI con Qwen Image 2512.

Il flusso, in breve

Dal pannello di amministrazione, ogni post ha ora un pulsante Genera copertina. Succede questo:

  1. L’API (una CoversSlice in ASP.NET Core) riceve POST /api/covers/{slug} e risponde subito 202 Accepted.
  2. In background costruisce il workflow JSON per ComfyUI e lo sottomette alla porta 8188.
  3. La UI fa polling su GET /api/covers/{slug}/status finché non vede done.
  4. L’immagine viene salvata in static/images/cover-{slug}.webp (WebP, ~10x più piccolo del PNG; il maestro lossless senza testo resta in covers-master/) e il front matter del post viene aggiornato con cover.image (per PaperMod) e images (per i tag og:image quando il post viene condiviso).
  5. Scatta la rebuild di Hugo, e la copertina appare sul sito.

Il workflow: GGUF quantizzato + LoRA Turbo

Il workflow riprende la configurazione che uso già per generare immagini in locale sul GX10 (128 GB di RAM unified aiutano, ma non sono infinita):

  • UnetLoaderGGUF con qwen-image-2512-Q5_K_M.gguf — il modello di diffusione in quantizzazione Q5, carico in VRAM/RAM in pochi secondi;
  • LoRA Turbo a 2–4 step con CFG 1: invece dei 30+ step classici, la generazione si chiude in una manciata di secondi;
  • CLIP qwen_2.5_vl_7b_fp8_scaled come encoder di testo e la VAE dedicata a Qwen Image.

Le dimensioni sono 1200×672: un 16:9 multiplo di 16 (vincolo architetturale di Qwen Image) molto vicino al 1200×630 raccomandato per le og:image.

Il vincolo di RAM che ha disegnato l’architettura

La scelta di design più interessante è figlia di un limite: sul GX10 llama-server che esegue Qwen text e Qwen Image non possono stare comodamente insieme nella RAM unified. Guadagnare trenta secondi di prompt arricchito con l’LLM sarebbe costato il rischio di swap lunghi minuti durante la generazione.

Quindi l’endpoint non chiama mai la LLM per scrivere il prompt: il default è un template derivato da titolo, descrizione, tag e categorie del post. Dall’interfaccia, però, il prompt si può sempre sovrascrivere a mano — ed è la strada che preferisco, perché le immagini migliori vengono da prompt scritti (o almeno ritoccati) da me.

Un container che chiama l’host

Ultimo dettaglio da sistemare: l’API gira in un container Docker, ComfyUI gira sull’host come servizio systemd utente. Soluzione classica: COMFY_URL=http://host.docker.internal:8188 + extra_hosts: host-gateway nel compose. In sviluppo locale (Aspire, senza container) la stessa variabile punta a localhost:8188 e il codice non cambia.

Questo post è la prova

La copertina che stai guardando in cima a questo articolo non l’ho disegnata io, e non l’ho nemmeno scritta a mano nel prompt: l’ha generata il flusso descritto qui sopra con il template automatico, in circa trenta secondi, mentre scrivevo l’ultimo paragrafo. È ufficialmente un post che si è fatto la foto da solo. 📸