b0sh.net

Proudly debugging the system since 1981

Strata: coding locale con una RTX 3060

Un modello da circa 180 miliardi di parametri, sul mio PC, con una RTX 3060 da 12 GB. È questa la promessa che mi ha incuriosito e mi ha spinto a provare Strata: dopo una prima sessione di coding, la sensazione è di aver fatto un passo avanti concreto rispetto ai modelli che usavo finora in locale.

Non è soltanto una questione di riuscire ad avviare un modello molto grande. Il punto è riuscire a usarlo con velocità accettabili, un contesto ampio e una qualità che lo renda interessante anche per lavorare sul codice.

Che cos’è Strata

Strata è un progetto gratuito e open source che permette di eseguire Qwen3.8-Flash-Next su hardware consumer, distribuendo il lavoro tra GPU, CPU, RAM e SSD. Offre un’interfaccia web e API locali compatibili con OpenAI e Anthropic, così da poter collegare applicazioni e coding agent senza ricorrere a un servizio di inferenza cloud.

Il modello di partenza è notevole: Qwen3.8-Flash-Next conta circa 180 miliardi di parametri complessivi, includendo le componenti n-gram e quelle dedicate alla predizione di più token. Non è però un modello denso di quelle dimensioni: adotta un’architettura Mixture of Experts, che attiva solo una parte degli esperti per ciascun token. Il contesto nativo arriva a 262.144 token.

Strata sfrutta queste caratteristiche per rendere possibile l’esecuzione su un normale PC. La GPU mantiene gli esperti usati più frequentemente, mentre RAM e CPU gestiscono il resto; una grande tabella di lookup risiede invece sull’SSD. Non serve, quindi, far entrare tutto il modello nella VRAM.

I requisiti dichiarati partono da una GPU supportata con almeno 12 GB di VRAM, 32 GB di RAM e circa 80 GB liberi su disco, preferibilmente SSD. Il progetto supporta Windows e Linux e propone diverse varianti del modello in funzione della memoria disponibile.

Il mio PC e il modello

Ho provato Strata su questa configurazione:

ComponenteHardware
CPUAMD Ryzen 5 9600X
RAM32 GB DDR5
ArchiviazioneSSD PCIe Gen4
GPUNVIDIA RTX 3060, 12 GB di VRAM
Modello selezionatoCoder

Con 32 GB di RAM ho scelto la variante Coder, che è anche quella consigliata dal progetto per questa quantità di memoria.

La versione Coder di ISTA-DASLab non è semplicemente una quantizzazione del modello completo: combina la riduzione di precisione dei pesi con il pruning, cioè la rimozione di metà degli esperti. La selezione privilegia le capacità legate al codice e all’uso agentico degli strumenti, accettando una perdita maggiore in altri ambiti.

Il dato interessante è quanto riesca a conservare nei benchmark dichiarati dagli autori: il 91,3% del punteggio del modello originale su SWE-bench Verified e il 98,7% su LiveCodeBench v6. Quindi “oltre il 90% delle capacità” va inteso in relazione a questi test di coding, non come una misura universale dell’intelligenza del modello.

Le prestazioni sul campo

Sul mio PC ho osservato circa 300 token al secondo in prefill, cioè nella lettura del prompt, e circa 30 token al secondo in generazione. Per il modello e l’hardware in gioco, considero queste prestazioni molto buone.

A fine prova, le statistiche erano queste:

MetricaRisultato
Richieste complessive75
Token di prompt elaborati284.200
Velocità media di prefill286 token/s
Token riutilizzati dalla cache4.335.358
Token generati68.865
Velocità media di generazione30,6 token/s

Sono numeri raccolti durante l’utilizzo, non un benchmark controllato. Descrivono però bene la mia esperienza: la velocità di generazione è sufficiente a rendere il modello concretamente utilizzabile, non soltanto interessante da provare.

La cache è uno degli aspetti che mi hanno colpito di più. Nel corso delle 75 richieste, oltre 4,3 milioni di token sono stati riutilizzati, contro circa 284 mila token effettivamente elaborati in prefill.

Dal punto di vista del tempo di rilettura, quei token recuperati dalla cache sono stati praticamente “gratis”. Nella mia sessione questo ha fatto una differenza importante: il contesto poteva crescere senza dover pagare ogni volta il costo di elaborarlo nuovamente per intero.

Coding con OpenCode

Per andare oltre la semplice chat, ho fatto una breve sessione di coding usando OpenCode come harness.

La compressione un po’ si percepisce. Non ho avuto la sensazione di usare il modello originale senza compromessi, e sarebbe prematuro trarre conclusioni definitive da una prova così breve. Detto questo, nella mia esperienza è andato meglio di qualsiasi altro modello locale che abbia usato finora.

Il riferimento precedente era Qwen 3.6 31B, insieme ai relativi fine-tuning e alle diverse quantizzazioni. Rispetto a quella base, Strata con il modello Coder mi è sembrato un netto passo avanti.

Anche il contesto merita attenzione: nella mia configurazione avevo a disposizione 256K token e durante la prova sono arrivato a usarne circa 100K. Non ho quindi verificato il comportamento al limite massimo, ma non ho dovuto ridurre drasticamente la finestra di contesto per rendere il modello utilizzabile sul mio hardware.

Come riferimento cloud uso molto, ultimamente, DeepSeek 4.1 Flash. È il livello di qualità che avevo in mente avvicinandomi a questa prova, ma non ho svolto un confronto diretto e controllato: non considero quindi questa sessione una dimostrazione di equivalenza tra i due.

Un passo avanti concreto

La parte più interessante di questa esperienza è l’insieme: qualità del codice, circa 30 token al secondo in generazione, un contesto ampio e una cache che nella pratica funziona molto bene.

La compressione comporta dei compromessi, e la mia resta una prima prova. Ma il risultato non è più soltanto “un modello enorme che in qualche modo gira sul PC”: è un modello che ho potuto usare dentro un coding agent, con prestazioni convincenti, su una macchina con 32 GB di RAM e una RTX 3060 da 12 GB.

Per il mio utilizzo, Strata rappresenta un salto concreto rispetto a Qwen 3.6 31B e alle varianti che usavo prima. Non significa che abbia già sostituito i modelli cloud nel mio flusso di lavoro; significa però che il coding locale è diventato un’alternativa molto più credibile.

Audio To Text: rilascio ufficiale su Google Play

Audio To Text è ora disponibile in produzione su Google Play: chiunque può scaricare l’app, provarla e inviare feedback direttamente dalla scheda dello store.

👉 Pagina dello store:
https://play.google.com/store/apps/details?id=net.b0sh.audiotext

Da questa fase in poi non è più necessario alcun gruppo o canale separato per i tester: l’open test è aperto a tutti direttamente dallo store.


Cos’è Audio To Text

Audio To Text è un’utilità Android per trascrivere file audio in testo direttamente dal menu Condividi:

  1. Apri un file audio (MP3, M4A, WAV, ecc.) da qualsiasi app (Gestore file, Registratore, WhatsApp, ecc.).
  2. Premi Condividi.
  3. Scegli Audio To Text.
  4. L’app decodifica l’audio e lo trascrive interamente in locale, usando modelli on-device (sherpa-onnx).
  5. Il testo risultante è visibile a schermo e pronto per essere copiato o condiviso a tua volta.

Nessun audio lascia il tuo dispositivo: la trascrizione avviene offline, sul telefono. L’unica attività di rete è il download dei modelli dall’interno dell’app.

Il progetto, nato come fork di phone-whisper, è stato progressivamente riprogettato per focalizzarsi sulla trascrizione di file audio condivisi, con un’architettura, un’interfaccia e un flusso d’uso ormai molto diversi rispetto alle origini. Il repository rimane il riferimento principale per dettagli tecnici e storico del progetto.


Cosa c’è di nuovo (v1.0.3)

L’open test parte con la release v1.0.3 (19 settembre 2026), che consolida il lavoro delle versioni 0.9.x e 1.0.x. Le novità più rilevanti rispetto alle prime build di testing:

Trascrizione: ultime parole non più perse

  • Tail padding a 2.0s per il modello streaming (Kroko Zipformer2): test empirici hanno mostrato che 1.0s e 1.5s potevano ancora far perdere le ultime parole; con 2.0s la trascrizione finale è sempre completa. Si tratta di silenzio aggiunto dopo i campioni reali, quindi non può corrompere l’output, solo garantire il flush finale.
  • Decoder MediaCodec: drain completo fino a EOS in output: il ciclo di decodifica in AudioDecoder prosegue finché il decoder non segnala EOS sull’output, svuotando anche gli ultimi chunk in coda, invece di fermarsi all’EOS in input e chiamare subito stop() (che in alcuni casi scartava la fine dell’audio).

UI e informazioni versione

  • Schermata “More info”: versione installata: in fondo alla schermata compare “Installed version: <versionName>”, letta a runtime da PackageManager, evitando duplicazioni manuali della versione nel codice.
  • Version bump: 1.0.2 → 1.0.3 (versionCode 26).

Per il dettaglio completo di tutte le modifiche dalle 0.9.x in poi (Jetpack Compose Material 3, navigation bar, download in foreground service, correzioni varie, nuovi modelli, ecc.) puoi consultare il changangelog completo nel README del progetto.


Come partecipare all’open test

  1. Apri la pagina dello store:
    https://play.google.com/store/apps/details?id=net.b0sh.audiotext
  2. Installa o aggiorna l’app dallo store.
  3. Usa l’app come di consueto: condividi file audio e trascrivi.
  4. Invia feedback e segnalazioni di anomalie tramite le GitHub Issues del progetto:
    https://github.com/b0sh-net/phone-whisper/issues

Non è richiesta alcuna configurazione particolare: basta avere un account Google e un dispositivo Android compatibile.


Prossimi passi

Con l’apertura dell’open test, l’obiettivo è:

  • Validare la stabilità della trascrizione su una gamma più ampia di dispositivi, formati audio e condizioni d’uso reali.
  • Raccogliere feedback su UX, prestazioni e consumo batteria.
  • Consolidare il comportamento dei modelli (in particolare quelli streaming) prima di eventuali release “stabili” al di fuori dei programmi di testing.

Se hai già usato le build di closed testing, l’esperienza è la stessa; la differenza è che ora il canale è aperto a tutti e il feedback può arrivare direttamente da chiunque installi l’app dallo store o apra una issue su GitHub.


Link utili

Costo Claude Code vs Deepseek

Oggi ho fatto una sessione di debug con Claude Code e alla fine gli ho chiesto le statistiche. Circa 40 milioni di token, cache hit circa al 70% costo stimato 72$.

Peccato che la configurazione in realtà puntasse su openrouter, con deepseek V4 flash come backend. E questi sono i dati reali, non stimati:

La differenza di costo direi che è notevole. Il provider è stato bloccato su Relace per evitare fluttuazioni di costo e cache miss non graditi.

Audio To Text arriva alla 1.0.0: ecco che cosa è cambiato

Dal post di fine agosto è successo parecchio. L’ultima volta vi raccontavo della versione 0.6.3 e dell’avvio del closed testing su Google Play; oggi Audio To Text (ex phone-whisper) è arrivato alla 1.0.0, una release stabile pronta per la fase di test. In questi mesi il lavoro è stato enorme, soprattutto su interfaccia e affidabilità. Vi riassumo i punti principali.

Un’interfaccia tutta nuova

La novità più visibile è la riscrittura completa dell’interfaccia con Jetpack Compose e Material 3. Fino a qualche mese fa la UI era costruita con le classiche View di Android, ora è tutta basata su Compose: tema chiaro/scuro che riusa la palette esistente, animazioni e componenti moderni.

A cambiare è anche la navigazione: al posto dei vecchi bottoni è arrivata una barra di navigazione fissa in basso con tre sezioni — Home, Catalogo e Maggiori informazioni — ognuna con la sua icona (Material Symbols Outlined). La voce attiva è in azzurro, le altre in grigio, e la barra resta sempre visibile. L’onboarding resta una schermata separata, senza barra, con il solo pulsante “Chiudi”.

Un dettaglio che in orizzontale faceva la differenza: nella schermata principale titolo e testo informativo restano fissi, mentre stato e modelli installati scorrono verticalmente. Ora anche con il telefono ruotato tutto funziona come deve.

Download che non si interrompono

Prima, se chiudevi il catalogo mentre uno scaricamento era in corso, il download si fermava. Ora i modelli si scaricano tramite un foreground service: la scaricamento continua in background anche dopo aver premuto Indietro, con una notifica che mostra il progresso. A fine installazione la lista dei modelli installati e il catalogo si aggiornano da soli. È stato anche corretto un bug che, premendo il tasto Indietro durante un download, poteva congelare l’app (ANR).

Catalogo modelli più ricco e gestibile

Il catalogo è cresciuto e ora è più pratico:

  • Nuovi modelli, tra cui Kroko Italiano, dedicato alla trascrizione dell’italiano, scaricato come file singoli direttamente da Hugging Face.
  • Rimozione dei modelli: i modelli installati si possono eliminare (con conferma) per liberare spazio; il modello attivo, se rimosso, viene riselezionato automaticamente con il primo installato rimasto.
  • Nomi più chiari: ogni modello indica la lingua di destinazione (es. “Whisper Base – English”, “Parakeet 0.6B – Multilanguage”).
  • Supporto per modelli compressi e non, e per fonti di download diverse.

Onboarding e piccoli grandi fix

Alla prima apertura ora compare una guida introduttiva con tre schermate scaricabili che spiegano come scaricare il modello, attendere l’installazione e trascrivere un messaggio; si può rivedere in qualsiasi momento dalla sezione “Maggiori informazioni”, dove i link GitHub e Issues sono tornati attivi e aprono correttamente il browser.

Sono stati sistemati anche il crash di Kroko al caricamento (era un modello streaming, ora caricato con il riconoscitore giusto) e il progresso di download per i modelli compressi, che prima saltava da 0% a 100% senza valori intermedi. Le icone del download e del cestino usano ora gli icon set Material Symbols, decisamente più pulite.

Piattaforma

Sotto il cofano: target SDK 36 (Android 16), supporto a tutti gli ABI (arm64, arm, x86, x86_64) per una compatibilità più ampia, e interfaccia multilingua italiano/inglese.

Changelog in breve (0.6.3 → 1.0.0)

  • v1.0.0 — Prima release stabile per il closed testing: consolida tutta la serie 0.9.x.
  • v0.9.x — Migrazione Jetpack Compose Material 3, barra di navigazione in basso, download in background (foreground service), fix ANR/auto-riselezione/link/scroll orizzontale, icone Material Symbols, fix Kroko, progresso download compressi, chiarezza catalogo, nuovi modelli (Kroko Italiano), onboarding e indicatori.
  • v0.8.x — Rimozione modelli installati, supporto a tutti gli ABI, promozioni al closed testing.
  • v0.7.0 — Promozione al closed testing.
  • v0.6.4–0.6.6 — Target SDK 36, schermata “Maggiori informazioni”, fix UI e contrasto.

Come provarla

La 1.0.0 è pronta per il closed testing su Google Play. Per partecipare basta iscriversi al gruppo dei tester (accesso libero, nessuna mail): https://groups.google.com/g/testers-community/ . Serve solo un dispositivo Android e, se trovi qualcosa che non va — crash, modelli che non si scaricano, traduzioni imprecise — segnalalo pure via Issues o nel gruppo.

La trascrizione resta completamente locale e on-device, con modelli sherpa-onnx: nessuna dipendenza dal cloud. Grazie a chi sta testando e continua a segnalare problemi: è ciò che rende l’app migliore.

Audio To Text in closed testing su Google Play

Con la versione 0.6.3 di Audio To Text (ex phone-whisper) è partita la fase di closed testing su Google Play. È il passaggio successivo dopo il rebrand e la rimozione delle funzionalità cloud raccontati nel post precedente.

Cos’è il closed testing

Google Play richiede una fase di test con un gruppo ristretto di utenti prima di poter aprire l’app al pubblico. È un passaggio utile anche a prescindere dall’obbligo: permette di verificare il funzionamento su dispositivi e versioni di Android diverse dalla mia, cosa che da solo non riesco a coprire.

L’app è visibile alla pagina Google Play di Audio To Text, ma per installarla in questa fase è necessario essere inseriti nella lista dei tester.

Come partecipare

Chi vuole provarla lo può fare iscrivendosi al gruppo dei tester su google group: https://groups.google.com/g/testers-community/ . Il gruppo è ad accesso libero e non manda nessuna mail. Non serve nessuna competenza particolare, solo un dispositivo Android e la disponibilità a segnalare eventuali problemi — crash, modelli che non si scaricano correttamente, traduzioni imprecise o altro.

Cosa trovare nell’app

La versione in test corrisponde a quella descritta nel post precedente: trascrizione locale con modelli sherpa-onnx, nessuna dipendenza cloud, interfaccia in italiano o inglese in base alla lingua del dispositivo.

Changelog

v0.6.3 (2026-08-27)

Da phone-whisper a Audio To Text: rebrand, local-only e UI più chiara

C’è stato un cambiamento importante: nasce Audio To Text

Ad aprile avevo raccontato la nascita di phone-whisper, l’app Android per trascrivere audio offline sul dispositivo usando sherpa-onnx (potete rileggere il post originale). Da allora il progetto è cresciuto, e con la versione 0.6.1 arriva un cambiamento che va oltre il semplice numero di release: l’app cambia nome e diventa Audio To Text.

Cosa cambia davvero

Il progetto nasceva già con un forte focus sulla privacy, ma manteneva un’integrazione opzionale con OpenAI per la trascrizione cloud e il post-processing del testo. Con la 0.6.0 questa parte è stata rimossa completamente: niente più chiamate cloud, niente API key da gestire, nessun dato che lascia il telefono. L’app oggi funziona esclusivamente con i modelli sherpa-onnx scaricati e installati in locale, il che significa anche una base di codice più semplice da mantenere — sono stati eliminati interi componenti come TranscriberClient, PostProcessor e WavWriter, insieme ai relativi test.

Questa scelta ha richiesto anche una riscrittura della privacy policy, per rimuovere ogni riferimento alla gestione delle chiavi API e alle modalità cloud che non esistono più.

Il rebrand: da phone-whisper a Audio To Text

Il nome phone-whisper aveva senso quando il progetto era ancora legato all’idea di Whisper e a un’integrazione cloud. Ora che l’app è diventata a tutti gli effetti uno strumento locale, ho deciso di rinominarla Audio To Text, un nome più diretto e descrittivo di quello che fa realmente. Il cambiamento non è solo estetico: il package dei sorgenti è stato spostato da com.kafkasl.phonewhisper a net.b0sh.audiotext, con la cronologia Git preservata grazie a un git mv mirato invece di una semplice riscrittura dei file.

Miglioramenti all’esperienza utente

Con la 0.6.0 e la 0.6.1 ho lavorato molto anche su come l’app comunica il proprio stato all’utente:

  • Durante l’installazione di un modello, ora viene mostrato il progresso di estrazione con numero di file completati e file corrente in lavorazione, così sai esattamente a che punto è il processo.
  • È stata aggiunta una sezione informativa sullo stato del modello nella schermata principale, per capire a colpo d’occhio se un modello è installato, pronto o ancora da scaricare.
  • Con la 0.6.1 arriva il supporto multilingua dell’interfaccia: l’app segue automaticamente la lingua del dispositivo tra inglese e italiano. Nome dell’app e nomi dei modelli restano invariati, per evitare ambiguità.

Perché questo cambiamento

L’obiettivo originale di phone-whisper era offrire una trascrizione privata e locale, ma la presenza di un’opzione cloud era in qualche modo in contrasto con quella filosofia. Rimuoverla non è stata solo una semplificazione tecnica: è stata anche una scelta di coerenza. Audio To Text è oggi un’app che fa una cosa sola, la fa completamente offline, e non ha bisogno di chiedere permessi di rete o gestire credenziali di terzi.

Changelog completo

v0.6.1 (2026-08-25)

  • Interfaccia multilingua: supporto inglese e italiano, in base alla lingua del dispositivo. Nome app e nomi modelli non tradotti.
  • Aggiornamento versione: 0.6.0 → 0.6.1 (versionCode 8).

v0.6.0 (2026-08-25)

  • Rimossa l’integrazione OpenAI: eliminate trascrizione cloud e post-processing. L’app supporta ora solo la trascrizione locale con modelli sherpa-onnx scaricati.
  • Rebrand: l’app è stata rinominata Audio To Text, package spostato in net.b0sh.audiotext.
  • Aggiornamento versione: 0.5.0 → 0.6.0 (versionCode 7).

Link utili

Audio To Text resta un progetto piccolo, ma ora è coerente al 100% con la sua promessa iniziale: nessun dato lascia il tuo telefono, mai.

Il punto di svolta: quando i modelli locali hanno iniziato a fare paura al cloud

Negli ultimi mesi ho notato un cambio di passo netto nella qualità dei modelli LLM eseguibili in locale. Non è la prima volta che scrivo di questo argomento su questo blog (chi segue il tag Ollama lo sa bene), ma stavolta la sensazione è diversa: non si tratta più di rincorrere il cloud con modelli “dignitosi per essere locali”, ma di avvicinarsi seriamente a prestazioni che fino a poco tempo fa erano appannaggio esclusivo dei giganti closed source.

Qwen 3.6 31B: il primo vero salto di qualità

Il modello che per me ha segnato la svolta è Qwen 3.6 31B. Non è la potenza bruta in sé a colpire, quanto la qualità delle rielaborazioni che la community ha saputo tirarne fuori.

Due versioni GGUF mi hanno impressionato particolarmente:

Nei miei test di coding e debug, entrambe le versioni si comportano molto bene, specialmente se abbinate all’harness ufficiale Qwen Code (qwen.ai/qwencode). La combinazione modello-tooling fa davvero la differenza: non basta un buon modello, serve un ecosistema che lo sappia sfruttare.

Agent A1: quando il locale sfida (davvero) il cloud

Se Qwen 3.6 mi aveva già convinto, oggi ho provato qualcosa che alza ulteriormente l’asticella: Agent A1 di InternScience (huggingface.co/InternScience/Agents-A1). I benchmark che presenta lo pongono a un livello paragonabile a modelli closed source molto più grandi, e non è la prima volta che vedo un modello “piccolo” (in senso relativo) tenere testa a giganti da centinaia di miliardi di parametri.

È il tipo di risultato che ti fa fermare un attimo e chiederti: dove sta andando davvero questo settore?

La domanda da un milione (di dollari, letteralmente)

Questo mi porta alla domanda che mi frulla in testa da settimane: chi vincerà, alla fine, tra cloud e inferenza locale?

Da una parte, il cloud closed source vive ancora una fase “dorata” grazie ai capitali enormi investiti da attori come OpenAI, Anthropic e compagnia. Questo ha reso possibile offrire inferenza a prezzi vantaggiosi, spesso sussidiati, pur di conquistare quote di mercato. È un classico schema da economia digitale: brucia cassa oggi, guadagna posizione domani.

Dall’altra parte, l’inferenza locale sta crescendo a una velocità sorprendente, ma per motivi completamente diversi: non capitali enormi, bensì ottimizzazione pura. Quantizzazione, tecniche come MTP, architetture MoE sempre più efficienti: tutto questo sta permettendo a hardware consumer di fare cose impensabili solo un paio di anni fa.

Al momento, il cloud vince ancora, e probabilmente vincerà ancora per un po’. Ma la vera domanda è cosa succederà quando il mercato selezionerà un vincitore (o pochi vincitori) tra i provider closed source. In quel momento, chi resterà in piedi dovrà necessariamente far pagare l’inferenza a un prezzo che rifletta davvero i costi (e gli investimenti da recuperare). È lì che si aprirà la vera partita.

Se a quel punto l’hardware consumer sarà abbastanza potente, e i modelli open abbastanza ottimizzati, avremo finalmente un’alternativa concreta e sostenibile al cloud a pagamento. Non lo so con certezza, ma spero che il ritmo di miglioramento dei modelli open continui così: non tanto per “battere” il cloud, quanto per garantire che un’alternativa esista sempre. Perché in un mercato senza alternative, alla fine, a pagare il conto siamo sempre noi.

BookmarkFox: resuscitare Delicious con Firefox e un po’ di AI-assisted coding

C’è un momento, per chi naviga il web da abbastanza tempo, in cui capisci che un servizio chiuso non è mai stato davvero sostituito. Per me quel servizio era Delicious.

Chi se lo ricorda sa di cosa parlo: un modo semplice per salvare i segnalibri, taggarli, e condividerli con altri. Quando Delicious ha chiuso i battenti, ho passato anni a provare alternative — estensioni, servizi cloud, note app riadattate — senza trovare niente che replicasse quel flusso naturale: trovo un sito interessante, lo salvo con un click, lo condivido con chi mi segue. Alla fine ho deciso di risolvere il problema alla vecchia maniera: scrivendomi l’alternativa da solo.

È nato così BookmarkFox, un’estensione per Firefox che comunica con un backend web per pubblicare i segnalibri. Niente di rivoluzionario nell’idea, ma è esattamente quello che mi serviva — e visto che non esisteva, l’ho costruito.

Il problema: nessuna vera alternativa a Delicious

Le opzioni moderne per gestire segnalibri condivisibili sono o troppo pesanti (servizi enterprise di bookmarking/knowledge management) o troppo chiuse in un ecosistema (salvataggi legati a un singolo social o browser). Mancava qualcosa di leggero, personale, e soprattutto self-hosted: un’estensione che facesse una cosa sola, bene, e che mi lasciasse controllo pieno sui dati.

BookmarkFox nasce da questa esigenza precisa: un’estensione Firefox minimale che pubblica i segnalibri su un backend che gestisco io, raggiungibile su bookmarkfox.b0sh.net.

Come ho lavorato: SpecKit invece del solito “vibe coding”

La parte che mi interessa raccontare di più, però, non è il “cosa” ma il “come”. Negli ultimi tempi ho sviluppato diversi progettini con l’aiuto di modelli AI locali o via API, e il pattern tipico è quello del prompt libero seguito da iterazioni a ruota libera. Funziona, ma con progetti che superano una certa complessità il modello perde il filo, e tu perdi tempo a rispiegare il contesto ogni volta.

Per BookmarkFox ho voluto provare un approccio più strutturato, usando GitHub SpecKit insieme a OpenCode. L’idea di SpecKit è semplice ma efficace:

  • Si parte da un prompt utente ad alto livello (l’idea del progetto).
  • SpecKit guida una fase di analisi dettagliata, trasformando l’idea grezza in una specifica vera e propria.
  • C’è una fase di clarification: il sistema pone domande specifiche per chiarire ambiguità prima di scrivere codice, invece di assumere e sbagliare.
  • Solo dopo la specifica viene suddivisa in task ben definiti, ognuno con un perimetro chiaro.

Il vantaggio pratico? Un modello non enorme — nel mio caso DeepSeek V4 Flash, con 250k di contesto — riesce a lavorare bene su singole task senza dover tenere “in mente” tutta l’architettura del progetto contemporaneamente. Ogni task è autoconclusiva, con contesto sufficiente ma non eccessivo. Il risultato è un workflow più prevedibile, meno “allucinazioni” da perdita di contesto, e codice più coerente con l’architettura pensata a monte.

È un cambio di paradigma interessante: non si tratta di usare un modello più potente, ma di strutturare meglio il problema perché anche un modello più leggero possa affrontarlo con efficacia. Per chi lavora con LLM locali o con budget di context window limitati, è una lezione che vale la pena portarsi a casa.

Il risultato

BookmarkFox oggi è operativo:

  • L’estensione è scaricabile dalle release su GitHub.
  • Il backend che gestisce la pubblicazione dei segnalibri è live su bookmarkfox.b0sh.net.
  • Il codice è open source, disponibile per chiunque voglia guardare sotto il cofano, contribuire, o semplicemente farsi un’idea di come è stato strutturato il progetto con SpecKit.

Non è (ancora) Delicious 2.0, ma è già quello che mi serviva: un modo veloce per salvare e condividere i siti interessanti che trovo in giro, senza dipendere da un servizio terzo che può chiudere domani.

Cosa mi porto a casa

Al di là del progetto in sé, l’esperienza con SpecKit mi ha convinto che il futuro dell’AI-assisted coding per progetti non banali passa da qui: meno prompt-e-spera, più analisi-chiarifica-scomponi. È un investimento di tempo iniziale che si ripaga abbondantemente quando il progetto cresce oltre le due-tre funzioni.

Se usi Firefox e ti manca un modo semplice per salvare e condividere segnalibri, dai un’occhiata a BookmarkFox. E se sei curioso di provare tu stesso il workflow SpecKit + LLM locale, è un ottimo punto di partenza per progetti di dimensioni simili.

PhotoPrism AI Curator: aggiornamenti, raffinamenti e una web UI

Qualche tempo fa ho scritto di aver costruito un selezionatore AI per PhotoPrism, un piccolo strumento che usa modelli locali per scegliere le foto migliori e creare album automatici. Il post originale raccontava il primo prototipo: ranking estetico puro, clustering semantico, e una CLI minimale.

Da allora ho lavorato molto sul progetto, aggiungendo funzionalità, migliorando la stabilità e rendendo tutto più facile da usare.

Da Ollama a Ollama e LM Studio

Una delle richiesta più comuni che ho visto in giro per progetti simili è la possibilità di usare backend diversi. Nel primo post parlavo solo di Ollama come backend AI. Ora lo strumento supporta anche LM Studio, con API OpenAI-compatibili.

Che significa, in pratica? Se desideri avere più controllo e scelta di modelli, puoi usare LM Studio senza cambiare nulla nel flusso di lavoro. Nell’interfaccia web e nella CLI il passaggio è trasparente: basta cambiare il backend nei parametri e puntare all’URL del server corretto.

Deduplicazione tempo e spazio, non solo semantica

Nel post originale parlavo di clustering semantico: le foto venivano raggruppate per similarità di descrizione e poi selezionate a rotazione per evitare ripetizioni. Funzionava, ma a volte finivo comunque con foto troppo simili, scattate nello stesso istante e nella stessa posizione.

Ho aggiunto un secondo livello di deduplicazione temporale e geografica. Dopo la selezione iniziale, lo strumento rimuove automaticamente le foto che sono entro 30 secondi e 100 metri l’una dall’altra, tenendo sempre quella con il ranking estetico migliore.

Il risultato è un album più vario, con meno “serie di foto quasi identiche” e più momenti distinti.

Logging professionale con Logback

Il primo prototipo scriveva log in modo un po’ artigianale, spesso su stdout o in file senza gestione. Per un tool che può girare automaticamente su grandi archivi, serve qualcosa di più robusto.

Ora il progetto usa Logback con:

  • logging su file (logs/photoprism-ai.log)
  • rotazione giornaliera
  • retention di 7 giorni
  • nessun output su stdout, tranne barre di progresso essenziali

Nel log trovi:

  • prompt di clustering (DEBUG)
  • rimozioni per dedup temporale/spaziale (INFO)
  • nomi dei cluster finali (INFO)

Prompt emozionale e descrizioni più ricche

Uno dei problemi iniziali era che il modello multimodale produceva descrizioni troppo brevi o generiche, il che rendeva il clustering meno efficace.

Ho:

  • aumentato la descrizione a 30 parole per ogni foto
  • introdotto un prompt emozionale più ricco, per spingere il modello a valutare anche composizione, originalità e “atmosfera”, non solo要素 tecnici

Il clustering ne beneficia molto: le categorie sono più pulite e coerenti.

Batch, thread e performance

Nel primo post parlavo di timeout e latenza come principali colli di bottiglia. Ho fatto diversi affini:

  • batch da 30 richieste per il clustering
  • 3 thread per il processing parallelo
  • caching più intelligente di takenAt, titolo, coordinate e luogo
  • retry automatico 3× per le chiamate AI in caso di errore

Questi cambiamenti hanno reso il tool più stabile e veloce, soprattutto su archivi grandi.

Barra di progresso e Web UI

La CLI funziona bene, ma per molti utenti un’interfaccia visuale è più comoda. Ho quindi sviluppato una Web UI leggera con:

  • Javalin come server embedded
  • HTMX per dinamicità senza scrivere JavaScript complesso
  • una barra di progresso per il clustering, con conteggio batch in tempo reale

La Web UI permette di:

  • scegliere mese singolo o anno intero
  • specificare quante foto selezionare
  • personalizzare il prompt di valutazione
  • scegliere il nome dell’album

Il form è semplice, ma copre tutti i casi d’uso principali.

Modalità anno intero

Nel post originale parlavo solo di selezione per mese. Ora c’è anche una modalità anno intero: lo strumento processa tutti i 12 mesi in sequenza, accumulando le foto migliori di ogni mese in un unico album annuale.

È utile per creare album tipo “Best of 2025” o “Viaggi 2025” senza dover lanciare manualmente 12 selezioni separate.

Cache arricchita e pool temporaneo

La cache (ai-cache.json) ora conserva per ogni foto:

  • score estetico
  • descrizione generata dall’AI
  • cluster assegnato
  • titolo, coordinate, takenAt, placeLabel, placeCity, placeState, placeCountry

Il pool temporaneo pre-dedup viene salvato in {albumName}.json, utile per debug e analisi.

CLI più flessibile

Oltre alla Web UI, la CLI è più potente:

bash# Mese singolo
java -jar target/photoprism-ai-curator-1.0.1.jar \
  --no-web --mode month --month 1 --year 2026 \
  --count 20 --album "Mia Selezione"

# Anno intero
java -jar target/photoprism-ai-curator-1.0.1.jar \
  --no-web --mode year --year 2026 \
  --count 20 --album "Best of 2026"

# Prompt personalizzato
java -jar target/photoprism-ai-curator-1.0.1.jar \
  --no-web --mode month --month 1 --year 2026 \
  --count 20 \
  --prompt "Rate composition and originality"

Sono disponibili flag per:

  • percorso del config file
  • forzatura modalità CLI
  • modalità mese/anno
  • mese, anno, conteggio foto
  • nome album
  • prompt di valutazione

Struttura del progetto

Il progetto è ora più maturo e meglio organizzato:

  • AiBackend come interfaccia comune per rating e clustering
  • OllamaClient e LmStudioClient come implementazioni separate
  • PhotoFetcher, AISelector, AlbumManager, ImageHasher come servizi puliti
  • WebServer con Javalin + HTMX
  • JobContext per lo stato thread-safe dei job

Tutto il codice è in Java 17+, con Maven, JUnit 5 e Mockito per i test.

Perché questi aggiornamenti contano

Per me, il punto non è solo automatizzare una classifica di bellezza. Il vero valore sta nel:

  • combinare giudizio estetico, varietà narrativa e vincoli pratici
  • gestire cache, timeout e costi computazionali in modo intelligente
  • offrire un’alternativa locale e controllabile ai servizi cloud per la selezione foto

Con LM Studio, dedup tempo/spazio, Logback, Web UI e modalità anno intero, ritengo che il progetto sia oggi molto più pronto per l’uso quotidiano.


Tutti i dettagli tecnici, commit e modifiche sono disponibili su GitHub.
La commit history è qui: https://github.com/b0sh-net/photoprism-ai-curator/commits/master/.

Ho costruito un selezionatore AI per scegliere le foto migliori da PhotoPrism

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.

Continua a leggere
« Articoli meno recenti

© 2026 b0sh.net

Tema di Anders Noren — Su ↑