Tornare da un viaggio significa quasi sempre ritrovarsi con una quantità ingestibile di foto. Nel caso di Lisbona, il problema non era tanto archiviare gli scatti, quanto riuscire a estrarne una ventina davvero condivisibile: belle, sì, ma anche varie e capaci di raccontare l’esperienza nel suo insieme. PhotoPrism offriva già un’ottima base grazie a geolocalizzazione, riconoscimento facciale, label e strumenti di organizzazione, ma non aveva ancora un modo per comporre automaticamente un album con “le foto più belle” e soprattutto con sufficiente varietà.

Da qui è nata l’idea di un selezionatore AI: una piccola applicazione Java che usa PhotoPrism per recuperare le miniature delle immagini e Ollama per far lavorare due modelli AI, uno multimodale per assegnare un punteggio estetico e produrre una descrizione oggettiva, e un secondo modello testuale per raggruppare semanticamente le foto e selezionarle con più equilibrio.

Il problema vero non era la qualità

Il primo prototipo faceva una cosa molto semplice: prendere le foto da PhotoPrism, inviarle a un modello multimodale su Ollama e chiedere un voto estetico da 1 a 100 insieme a una breve descrizione. Sulla carta sembrava sufficiente, ma in pratica produceva una selezione monotona: immagini molto belle singolarmente, ma spesso troppo simili tra loro.

Era il classico caso in cui un ranking puro ottimizza la qualità locale ma non la copertura narrativa. Se cinque foto dello stesso scorcio o dello stesso momento ricevono voti alti, un algoritmo ingenuo tende a sceglierle tutte. Per costruire un album da condividere, invece, non basta premiare le immagini migliori: bisogna anche evitare la ripetizione.

Dalla classifica ai cluster

La seconda iterazione ha quindi cambiato approccio. Invece di trattare il problema come una semplice classifica, il tool ha iniziato a ragionare per gruppi: ogni foto riceve una descrizione oggettiva dal modello visivo, e queste descrizioni vengono poi analizzate da un secondo modello text-only per creare cluster di immagini semanticamente simili.

In questo modo la selezione finale non è più dominata da un unico soggetto o da una sola scena. Il sistema sceglie a rotazione le migliori foto da cluster diversi, così da conservare un livello qualitativo alto senza sacrificare la varietà. È un cambiamento piccolo da spiegare, ma sostanziale nel risultato: da “le più belle” a “le più belle che, insieme, raccontano meglio il viaggio”.

Il collo di bottiglia era la latenza

La parte più difficile non è stata immaginare la pipeline, ma farla funzionare in tempi accettabili. Creare i cluster su un numero elevato di immagini si è rivelato più costoso del previsto, soprattutto per il tempo necessario a far processare le descrizioni dal modello. Per questo la pipeline è stata spezzata in blocchi parziali, poi riunificati in una fase finale di merge, così da ridurre il costo operativo del clustering su un set grande.

Anche così, però, i timeout continuavano a essere un problema reale. La svolta è arrivata intervenendo direttamente sulle chiamate verso Ollama: per il modello dedicato al clustering è stata disabilitata la fase di thinking, usando richieste batch con think:false, così da evitare lunghi passaggi riflessivi non necessari per questo tipo di compito. È stata la scelta risolutiva, soprattutto con i modelli Qwen, che tendono ad avere una fase riflessiva di default piuttosto lunga.

Cosa fa la prima beta

La prima beta, pubblicata come PhotoPrism AI Curator, automatizza l’intero flusso: scarica le miniature delle foto da PhotoPrism, invia ciascuna miniatura a Ollama con un modello multimodale per ottenere un punteggio estetico e una descrizione, raggruppa le immagini per similarità semantica tramite un secondo modello text-only, seleziona a rotazione le migliori da ciascun gruppo e crea infine un album direttamente in PhotoPrism. Questa architettura è coerente con le capacità offerte da PhotoPrism per organizzazione, persone e label, e con il ruolo di Ollama come runtime locale per modelli diversi nello stesso workflow.

Il progetto include anche una modalità “anno intero”, che processa tutti i dodici mesi in sequenza e accumula le migliori foto mensili in un unico album annuale. È una funzione semplice da descrivere ma molto pratica per chi usa PhotoPrism come archivio personale continuo e non vuole lavorare manualmente mese per mese.

Stack e funzionamento

Dal punto di vista tecnico, il progetto richiede Java 17+, Maven, un’istanza PhotoPrism con API attiva e Ollama con almeno due modelli: uno multimodale per l’analisi visiva, come minicpm-v, llava o moondream, e uno text-only per il clustering delle descrizioni, come qwen3.5:4b o llama3.2:3b. In alternativa è possibile usare un solo modello capace di gestire sia input visivi sia generazione testuale pura, ma l’architettura pensata per la beta separa chiaramente valutazione estetica e clustering semantico.

L’applicazione si compila con Maven, legge la configurazione da config.properties e consente di impostare URL e token di PhotoPrism, endpoint Ollama, modelli da usare, prompt di valutazione, file di cache e timeout per connessione, rating e clustering. Il fatto di mantenere una cache locale delle valutazioni in ai-cache.json è importante, perché evita di ripetere inferenze costose su immagini già processate e rende molto più sopportabile l’uso iterativo durante i test.

Web UI invece di solo CLI

Un aspetto interessante della beta è che non si ferma alla linea di comando. Il progetto espone anche una piccola interfaccia web embedded, avviabile direttamente dal JAR, costruita con Javalin lato server e HTMX nel frontend, una scelta leggera ma molto sensata per questo tipo di utility locale. L’interfaccia permette di scegliere se elaborare un mese singolo o l’intero anno, indicare quante foto selezionare, personalizzare il prompt di valutazione e decidere il nome dell’album finale.

Questa parte è importante anche narrativamente, perché mostra che il progetto non è solo una prova tecnica. C’è già il tentativo di trasformare uno script nato per uso personale in uno strumento riutilizzabile, con uno stato di job thread-safe e una UX minima ma concreta.

Struttura del progetto

La struttura del repository rende abbastanza chiara l’evoluzione del tool. I client separano le API di PhotoPrism e Ollama, i service isolano fetch delle foto, logica di selezione, hashing e gestione degli album, mentre il pacchetto web contiene il server e il contesto di esecuzione dei job. È una divisione ordinata che aiuta a leggere il progetto come una pipeline composta da fasi distinte: raccolta, valutazione, raggruppamento, selezione, pubblicazione.

In breve, l’albero principale comprende App.java come entry point, una configurazione dedicata, model per foto e album, client per PhotoPrism e Ollama, service per selezione e gestione operativa, e una web UI HTMX servita da Javalin. Anche la scelta di usare JUnit 5 e Mockito per i test indica che la beta non è soltanto un esperimento estemporaneo, ma un progetto già pensato per crescere.

Perché mi interessava davvero

La cosa più interessante di questo progetto non è tanto aver fatto scegliere delle foto a un’AI. Il punto è aver trasformato un problema quotidiano e noioso — rientrare da un viaggio e dover setacciare centinaia di immagini quasi uguali — in una pipeline locale, controllabile e compatibile con strumenti self-hosted già esistenti.

PhotoPrism sa già dove sono state scattate le foto, chi compare nelle immagini e quali label possono descriverle, ma il salto verso una vera selezione richiede qualcosa in più: un giudizio estetico, una nozione minima di varietà e una serie di compromessi pratici su latenza, timeout e costo computazionale. È proprio in quel punto, tra metadata e gusto, che questo selezionatore AI prova a inserirsi.

Come provarlo

Per compilare la beta basta clonare il repository, copiare config.properties.example in config.properties, inserire i dati della propria istanza PhotoPrism e di Ollama e lanciare mvn clean package. A quel punto si può avviare il JAR in modalità web oppure usare la CLI con il file di configurazione passato esplicitamente.

bashgit clone <url-repo>
cd photoprism-ai-curator
cp config.properties.example config.properties
# modifica config.properties con i tuoi dati
mvn clean package
java -jar target/photoprism-ai-curator-1.0.0.jar

Una volta aperta l’interfaccia web su http://localhost:8080, il flusso è lineare: scegliere il periodo, indicare il numero di foto desiderate, adattare eventualmente il prompt di valutazione e lasciare che il sistema costruisca l’album finale dentro PhotoPrism.

Cosa può diventare

Questa prima beta risolve già il problema più concreto: ridurre una massa di foto a una selezione più pulita, più varia e più condivisibile. Ma lascia intravedere sviluppi interessanti, come criteri di selezione personalizzabili per tipo di viaggio, un bilanciamento più esplicito tra soggetti, luoghi e momenti, oppure un uso più intelligente dei metadata di PhotoPrism per influenzare il clustering e la rotazione finale.

Il progetto è già disponibile in una prima beta su GitHub, qui: b0sh-net/photoprism-ai-curator. Dentro al repository ci sono codice, istruzioni di compilazione, configurazione di PhotoPrism e Ollama, oltre alla piccola interfaccia web che ho costruito per rendere il flusso più comodo da usare.