AI Pantry · AI On-Device
DevFest Milano 2026 · il talk

AI On-Device

Cooking from your fridge with Gemini Nano, MobileCLIP and Gemma

Salvatore Matrisciano · Stefano Soriano · Mobile Developers

Gemini NanoMobileCLIP-S2Gemma 4 E2B100% on-device
Scopri il talk ↓
La domanda

Cosa succede quando decidi di far girare tutta l’AI della tua app direttamente sul telefono?

Niente cloud. Niente API key. Nessuna foto della cucina dei tuoi utenti su un server.

Oggi, quando aggiungiamo una feature AI a un’app, ci viene quasi in automatico: prendo una API key, chiamo un modello nel cloud, mando la richiesta, aspetto la risposta. Ogni richiesta che mandi a un server è una cosa in più da proteggere, da giustificare, da spiegare all’utente nella privacy policy, e anche, soprattutto, da pagare.

L’APP

AI Pantry: scansiona il frigo, ottieni la cena

L’app si chiama AI Pantry: Dispensa AI, e l’idea è molto semplice: fai una foto al frigo e ottieni un’idea di ricetta per cena.

01

Fotografi il frigo, riconosce gli ingredienti

Funziona così. Prima fai una o più foto al tuo frigo, e l’app riconosce gli ingredienti che vede. Quello che sta succedendo adesso è la parte di percezione: l’app sta capendo quali ingredienti ci sono nella foto, zona per zona, e li vedete comparire appena li trova. Nel corso del talk vi spieghiamo perché questa parte, all’inizio, ci metteva minuti, e come l’abbiamo portata a pochi secondi.

02

Gli ingredienti trovati, con la confidenza

Eccoli. . Ognuno ha la sua confidenza, e quelli sotto una certa soglia vengono già scartati. Se qualcosa è sbagliato, lo tolgo con la X. E guardate questa riga: l’app vi dice quale motore ha fatto il lavoro. Su questo telefono è . Tenetelo a mente, perché è il cuore del talk.

03

Si ricorda la tua dispensa

Poi con quelle foto costruisce l’inventario della tua dispensa. Quindi l’app si ricorda cos'hai. Faccio lo stesso con la dispensa. Le due scansioni si sommano. Aggiungo tutto. E questo è l’inventario, salvato in locale sul telefono.

04

Ti propone cosa cucinare e scrive la ricetta

Qui entra in gioco un modello diverso, un LLM vero e proprio, Gemma, perché inventare una ricetta è un compito completamente diverso dal riconoscere un’anguria. Anche questo lo vedremo nel dettaglio. Ecco quattro idee per la cena, con tempo e difficoltà. Sono ordinate in base a quanto usano quello che ho davvero: quelle che richiedono di comprare qualcosa finiscono in fondo, e l’app mi dice cosa mi manca. E se non mi convincono, “Altre ricette” me ne propone altre quattro.

05

La ricetta completa, scritta sul momento

Apro questa. Quantità e passaggi non esistevano finché non l’ho aperta: li sta scrivendo adesso, qui sul telefono.

06

100% on-device: foto e prompt non escono dal telefono

E il punto centrale è che è tutto al 100% on-device. E vi ricordo: modalità aereo. Nessuna chiamata di rete. Nessun costo per chiamata. Nessuna foto di questo frigo è finita su un server.

▶ Guarda la demo
La demo

Dall'inizio alla fine, dal telefono

La registrazione dello schermo usata come piano B del talk: scansione del frigo e della dispensa, quattro ricette, il procedimento che si scrive passo dopo passo.

Circa 3 minuti e mezzo, app in italiano. Le schermate di questa pagina sono fotogrammi dello stesso video.

MOTIVAZIONE

Perché on-device?
Privacy, prima di tutto

E una foto del frigo racconta molto più di quanto si possa pensare: abitudini alimentari, allergie, magari condizioni di salute, e a volte anche un pezzo di casa sullo sfondo.

🔒

Nessun server che vede le foto

Le foto della cucina non escono dal telefono.

📝

Nessun Data Processing Agreement (DPA)

Nessun fornitore riceve le foto: niente da firmare.

🗄

Nessun problema di data retention

Se non memorizzi mai dati, la retention non è un problema.

🕳

Nessun log da far trapelare

Il dato più sicuro è quello che non hai mai raccolto.

…poi resilienza e costi

E un frigo si trova in cucina, magari in una casa vecchia, magari in una taverna o in un seminterrato, o comunque può trovarsi in posti dove internet non prende. Più l’app ha successo, più costa.

📶

Funziona anche senza internet

Senza rete, in modalità aereo, con segnale debole (anche in cucine seminterrate)

⚡

Nessun round-trip verso il server

Niente latenza di rete: il “backend” è già in tasca.

📈

Il costo del cloud cresce con l’uso

Ogni foto si paga, per ogni utente, ogni giorno.

🔄

On-device ribalta il costo

L’inferenza gira sul telefono dell’utente: bolletta cloud a zero.

Quindi: privacy, resilienza e costi.

Prima la strada sbagliata

Due strade, e nessuna delle due andava bene

PRIMA SCELTA

La scelta ovvia: Gemini Nano

✓ Già nel sistema operativo, multimodale
✓ Una dipendenza, zero megabyte nell’APK
✓ Accelerazione hardware e aggiornamenti gestiti da Google

Perfetto. Tranne che…

PRIMA SCELTA · IL PROBLEMA

Gira solo sui flagship più recenti.

Pixel 10/11, Galaxy S26 e pochi altri top di gamma:
non i telefoni che la maggior parte della gente ha davvero.

Quindi abbiamo capito subito: Gemini Nano poteva essere un bonus, ma non poteva essere la base della nostra app.

PIANO B

Un solo LLM multimodale per fare tutto

Gemma 4 E2B · Il modello open di Google: lo porti tu, gira anche dove Nano non c’è (con abbastanza RAM).

Ha funzionato. Ingredienti corretti, JSON valido, ricette vere.

Il problema
5–10 min

Ma ci metteva 5-10 minuti per scansione

Su un Pixel 7, un telefono di quattro anni fa. Nessuno aspetta 10 minuti per un’idea per cena.

Quindi avevamo due strade (Gemini Nano e Gemma) e nessuna delle due andava bene: una veloce ma solo per pochi, e una per tutti ma inutilizzabile.

QUESTA SESSIONE

Come l’abbiamo risolto, in cinque capitoli

01
Gemini Nano via ML Kit GenAIUn upgrade gratuito, mai la base
Gemini Nano
02
Un modello per domarli tutti: Gemma…e perché era così lento
Gemma 4 E2B
03
Rilevamento zero-shot con MobileCLIP-S2Un modello che confronta, non che scrive
MobileCLIP-S2
04
Dove l’LLM si guadagna il suo postoGenerazione delle ricette
Gemma · LiteRT-LM
05
La distribuzioneOgni modello viaggia in modo diverso
Play for On-device AI

Vi spoilero già il finale, così non c’è suspense: alla fine abbiamo usato tutti e 3 i modelli. Ma ognuno per un compito diverso, e il punto principale è capire perché.

CAPITOLO 1 · GEMINI NANO

Il protagonista: Gemini Nano

🧬
Il membro più piccolo della famiglia Gemini di GoogleDistillato per girare su un telefono. Stesso DNA dei fratelli cloud, ridotto finché non entra nel budget di memoria e termico di un telefono
🖼
Multimodale: foto + testo in, testo outProprio il nostro problema: "guarda questo frigo, dimmi cosa c'è dentro"
📲
Un solo modello condiviso per dispositivoAggiornato da Google Play services: nano-v3 / nano-v4 in base al dispositivo, migliora senza che tu rilasci nulla
0️⃣
Il costo per la tua app: zero megabyteSi può usare tramite Machine Learning Kit GenAI, che espone sia API già pronte, come riassunti o riscrittura del testo, sia una Prompt API in cui il prompt lo possiamo scrivere noi.
CAPITOLO 1 · GEMINI NANO

Il modello vive in AICore, non nella tua app

E c’è un vantaggio da non sottovalutare: se 10 app sullo stesso telefono usano Gemini Nano, il modello sul disco è uno solo. Non dieci copie da qualche gigabyte ciascuna

AI Pantryfoto + prompt Un’altra appstesso modello E un’altranessuna copia in più AICoreservizio di sistema Androidpesi, storage, aggiornamentiaccelerazione hardwarecheckStatus() Gemini Nanouna sola copia sul discoaggiornata da Play servicesnano-v3 · nano-v4 LE APP NON TOCCANO MAI UN FILE DEL MODELLO
⚙️

AICore è un servizio di sistema Android

Gestisce pesi, storage, aggiornamenti e accelerazione hardware, la tua app non tocca mai un file del modello.

🖼

Prompt multimodali:
foto + testo in, testo out

Gira su pesi che non devi mai distribuire, scaricare o aggiornare.

📍

Come la fotocamera o il GPS

È una capability del sistema, non una cosa da impacchettare nell’app. Ma proprio perché è una capability del sistema, può esserci o non esserci.

CAPITOLO 1 · GEMINI NANO

Una dipendenza, una regola: verifica, poi chiama

Si controlla a ogni chiamata: la disponibilità cambia a runtime.

DetectIngredients.kt
implementation("com.google.mlkit:genai-prompt:1.0.0-beta2")val model = Generation.getClient()suspend fun detect(bitmap: Bitmap) = when (model.checkStatus()) { // runtime, non compile time FeatureStatus.AVAILABLE -> detectWithNano(bitmap) FeatureStatus.DOWNLOADABLE -> { scope.launch { model.download().collect() } // download in background clip.detect(bitmap) // fallback } else -> clip.detect(bitmap) // fallback: MobileCLIP, non un errore }suspend fun detectWithNano(bitmap: Bitmap) = model.generateContent( generateContentRequest(ImagePart(bitmap), TextPart(prompt)) { temperature = 0.2f })

La cosa più importante è che lo stesso telefono può rispondere in modo diverso nel tempo. Quindi quel check non si fa una volta all’avvio: si fa ogni volta.

CAPITOLO 2 · UN MODELLO PER DOMARLI TUTTI

Il protagonista: Gemma 4 E2B

🔓
La famiglia open-weights di GoogleIl fratello scaricabile di Gemini. I pesi sono tuoi da includere e distribuire nella tua app; nessuna fatturazione per chiamata, nessun server
📐
'4 E2B' = 4ª generazione, 2 miliardi di parametri effettiviProgettato per i telefoni. Trucchi di memoria danno qualità da grande modello con un’impronta RAM da telefono; instruction-tuned
👁
Multimodale: un vision encoder alimenta il language modelSa guardare E scrivere. Esattamente ciò che serve a uno scanner per il frigo, e può generare anche le ricette
🧩
Via LiteRT-LM su ogni AndroidUn modello, un’integrazione, entrambi i compiti: rilevamento E ricette
CAPITOLO 2 · UN MODELLO PER DOMARLI TUTTI

Chiedi all’LLM di guardare, e di scrivere

Poi mandiamo foto e prompt nella conversazione, prendiamo il testo, facciamo il parsing del JSON, e se è malformato riproviamo in silenzio. Ci torneremo, su questo. Da notare anche il limite di quindici elementi: non è casuale.

LlmVisionIngredientDetector.kt
val prompt = """ This is a photo of the inside of a $place. Identify the food ingredients you can see, at most 15. Respond with ONLY a JSON array (no markdown, no extra text): [{"name": "...", "quantity": "..."}] Only include items you actually see. Use common English ingredient names.""".trimIndent()conversation.sendMessage(Contents.of(Content.Text(prompt), Content.ImageBytes(jpeg)))// → parsing del JSON, retry silenziosi se malformato

Il rilevamento come problema di prompting: nessun dataset, nessun training. Basta chiedere. Cosa potrebbe andare storto?

CAPITOLO 2 · PERCHÉ ANDAVA A RILENTO

Il costo a due fasi degli LLM multimodali

Prima di scrivere anche solo una parola, il modello deve leggere tutto l’input. E la nostra foto non è “un’immagine”: per il modello diventa qualche centinaio di token immagine.

Fase 1prefill
Fase 2decode
[{"name":"eggs","quantity":"6"},{"name":"milk","quantity":"1 L"},{"name":"tomatoes"…
una scansione su fascia media
5–10 min
🧮

Fase 1: prefill

La foto diventa centinaia di token immagine, tutti elaborati prima che compaia qualsiasi output.

🐢

Fase 2: decode

La risposta è generata un token alla volta attraverso un modello da 2 miliardi di parametri.

⏱

Scansione di 5-10 minuti su fascia media

L’aritmetica, non la qualità del modello, decide tra secondi e minuti.

📏

Conosci questo modello di costo

Prima di promettere qualsiasi UX multimodale.

Sul telefono, con memoria condivisa, limiti termici e una batteria da non prosciugare, ogni token si sente. Prima di dire al product owner “facciamo scattare una foto e l’AI capisce tutto”, fate questo conto.

CAPITOLO 3 · RILEVAMENTO ZERO-SHOT

Il protagonista: MobileCLIP-S2

📏
Non è un LLM: non genera nulla, misuraQuanto un’immagine corrisponde a una frase. Un modello della famiglia CLIP: Contrastive Language–Image Pre-training
🍏
La versione mobile di CLIP di AppleDistillato da modelli più grandi. S2 è il giusto mix accuratezza/velocità: zero-shot accurato come modelli più grandi, a latenza da telefono
🪶
~140 MB, input 256×256, embedding a 512 dimensioniMinuscolo accanto a un LLM da 2 miliardi di parametri, e con un profilo di costo completamente diverso
📱
Pesi aperti, si esporta senza problemi in LiteRTGira su qualsiasi telefono Android. Nessun AICore richiesto, nessuna lotteria del silicio: questa può essere la base
CAPITOLO 3 · RILEVAMENTO ZERO-SHOT

Il riconoscimento non richiede un modello che scrive, ma uno che confronta

Sono stati addestrati su milioni di coppie immagine–didascalia, in modo che una foto e la frase che la descrive finiscano vicine nello stesso spazio vettoriale. La foto di un’arancia e la frase “una foto di un’arancia” diventano due vettori che puntano più o meno nella stessa direzione.

oranges milk eggs bananas ~an empty shelf 📷 cos θ massimo → oranges SPAZIO A 512 DIMENSIONI (QUI IN 2)
🔀
Modelli della famiglia CLIP: due piccoli encoderAddestrati su milioni di coppie immagine–didascalia, così le coppie corrispondenti finiscono vicine nello spazio vettoriale.
📐
"È un’arancia?" diventa una similarità del cosenoIl riconoscimento diventa geometria: un prodotto scalare, non un paragrafo generato.
🪶
Basta un encoder da ~140 MBMobileCLIP-S2 gira su LiteRT su qualsiasi telefono Android, nessun ciclo di decode richiesto.

E il bello della similarità del coseno è che è un numero: da meno uno a uno. Niente JSON da parsare, niente allucinazioni in forma di testo: al massimo un punteggio basso.

CAPITOLO 3 · IL TRUCCO

Il vocabolario l’abbiamo costruito noi, ed è un file di testo

Il “classificatore” è un file di testo: vuoi un ingrediente in più? Aggiungi una riga.

scripts/ingredient_labels.txt · prepare_clip_assets.py
# scripts/ingredient_labels.txt · 870 etichette di ingredienti curate a manoorangesstrawberriesbananas…lactose-free milk|milk match specifico | nome mostrato all’utentebottle of whole milk|milk…~an empty shelf distrattore: assorbe i ritagli vuoti# prepare_clip_assets.py · offline, sul laptop, una volta solaTEMPLATES = ["a photo of {}", "a photo of {} in a refrigerator", "a photo of {} on a pantry shelf", "a close-up photo of {}"]
🧮

Calcolati una volta, sul laptop

Per ogni etichetta usiamo quattro template, tipo “una foto di un’arancia”, e facciamo la media dei vettori, che rende il risultato più robusto. Il risultato sono circa 4,5 megabyte di vettori, inclusi nell’APK.

✂️

Sul telefono gira solo l’image encoder

Il flusso è: ritagliamo la foto in tanti crop, a due scale diverse, calcoliamo l’embedding di ogni crop, confrontiamo col coseno contro tutte le etichette, e vincono le corrispondenze migliori, sopra una soglia di confidenza.

CAPITOLO 3 · IL RISULTATO

Stesso telefono. Stessa foto del frigo.

Minuti → secondi.
Gemma 4 E2Bun LLM che guarda e scrive
5–10 min
MobileCLIP-S2un encoder che confronta
~20 s

Ed è la lezione più importante di tutto il talk: prima di ottimizzare il modello, chiedetevi se è il modello giusto per quel compito.

CAPITOLO 4 · DOVE L’LLM SI GUADAGNA IL POSTO

Il protagonista: Gemma, il ritorno

💾
Gli stessi 2,6 GB, già sul telefonoOra fa il lavoro per cui è stato costruito. L’abbiamo messo in panchina per la percezione; non l’abbiamo mai disinstallato
📝
Stavolta solo testoNiente foto, niente token immagine, niente prefill enorme. Input: una breve lista di ingredienti
✨
Generazione instruction-tuned: le ricette sono testo nuovoInventate sul momento. L’unico compito nell’app che nessun confronto, nessun vocabolario, nessun lookup potrebbe mai svolgere
🎮
Gira tramite LiteRT-LM sulla GPUE siccome le GPU dei telefoni Android sono un mondo variegato, se la GPU si blocca o dà errore, l’app se ne accorge, passa alla CPU e se lo ricorda per le volte successive.

Quindi il costo a due fasi, che prima ci aveva ucciso, adesso gioca a nostro favore: prefill minuscolo, e decode che produce proprio quello che vogliamo. Nel rilevamento la creatività era un difetto; qui diventa il prodotto.

CAPITOLO 4 · DOVE L’LLM SI GUADAGNA IL POSTO

Le ricette sono creazione, non riconoscimento

Da un inventario a idee per la cena È per questo che esistono i modelli generativi, nessun vocabolario chiuso può farlo.

🪜

Prompting a due stadi

Prima una lista economica, poi la ricetta completa su richiesta, prompt più corti, meno attesa. Prima chiediamo una lista di cinque ricette, con titolo, tempo, difficoltà e ingredienti usati, ma senza procedimento.

🛟

Parsing JSON difensivo con retry silenziosi

I modelli piccoli rompono i contratti di formato, prevedilo, non scusarti. In pratica: togliamo i blocchi markdown, estraiamo tutti gli oggetti JSON che troviamo, accettiamo anche nomi dei campi scritti in modo diverso, e se una sola ricetta è rotta scartiamo quella, non tutta la lista.

⚡

La generazione solo testo va a 15–25 tok/s

Senza foto, niente prefill dell’immagine: si aspetta solo il testo. E siccome la lista è leggera, e i passaggi li generiamo solo per la ricetta che aprite, l’attesa resta breve.

quello che scrive il modello
Certo! Ecco le ricette: ```json [{"title": "Pasta al pomodoro", "time": "25 min",}, {"titolo": "Risotto ai funghi", "time": "45 min"} ```
→
dopo il parsing difensivo
[ {"title": "Pasta al pomodoro", "time": "25 min"}, {"title": "Risotto ai funghi", "time": "45 min"} ] // markdown tolto, virgola in più ignorata, "titolo" accettato come "title"

E così si vede, sul telefono, una ricetta che arriva token dopo token (il testo è quello della demo):

Gemma, in streaming sul telefono
≈ 18 tok/s
Pasta al pomodoro e mozzarella · 25 min · Facile
 
1. Cuocere gli spaghetti in abbondante acqua salata fino a che non sono al dente.
2. Nel frattempo, tagliare i pomodori a cubetti e metterli in una padella con un filo d’olio e qualche foglia di basilico.
3. Portare i pomodori a ebollizione, poi abbassare la fiamma e lasciar sobbollire per circa 15–20 minuti.
4. Scolare gli spaghetti e trasferirli nella padella con il sugo.
5. Aggiungere la mozzarella a cubetti e farla sciogliere delicatamente nel sugo.
CAPITOLO 5 · LA DISTRIBUZIONE

Ogni modello viaggia in modo diverso

Perché avere tre modelli è bello, ma poi bisogna farli arrivare sul telefono.

AICore
Gemini Nano
0 MB
Lo gestisce AICore, l’APK contiene solo un prompt.
MobileCLIP-S2
~140 MB
Incluso nell’APK come qualsiasi asset, il rilevamento funziona subito dopo l’installazione.
AI pack 1AI pack 2AI pack 3
Gemma 4 E2B
2,6 GB
Troppo grande per qualsiasi APK, e scrivere a mano un downloader riprendibile è un progetto a sé.
📦

AI pack tramite Play for On-device AI

Google Play gestisce la consegna, la distribuzione smette di essere un tuo problema.

E potete scegliere quando consegnarlo: all’installazione, in modalità fast-follow, cioè subito dopo l’installazione, in background, oppure on demand. Noi usiamo fast-follow. E siccome Play ha un limite di dimensione per singolo pack, abbiamo diviso Gemma in tre AI pack: al primo avvio l’app li riassembla nel modello, e poi i pack vengono rimossi per non occupare spazio 2 volte.

Questo ha un vantaggio enorme: il rilevamento funziona subito dopo l’installazione, anche offline, anche al primo avvio. E c’è anche un tema di esperienza utente: non potete chiedere a qualcuno di scaricare 2,6 giga al primo avvio, magari in 4G.

IL QUADRO COMPLETO

Tre modelli, tre compiti, un’app

Tutti i motori di rilevamento implementano lo stesso contratto.

Jetpack Compose UIuna sola interfaccia:non sa chi ha rispostoMVI · Koin · Room interface IngredientDetectorAdaptiveIngredientDetectorsceglie a ogni scansioneNano se c’è, altrimenti CLIP interface RecipeGeneratorLlmRecipeGeneratordue fasi · streamingJSON difensivo · fino a 4 tentativi Gemini Nano · l’acceleratorerilevamento gratuito sui flagshipAICore · ML Kit GenAI MobileCLIP-S2 · la basezero-shot in secondi, ovunqueLiteRT · ~140 MB Gemma 4 E2B · il creatorele ricette: solo un LLM sa farloLiteRT-LM · GPU → CPU checkStatus()ALTRIMENTI
🚀

Gemini Nano: l’acceleratore

Rilevamento multimodale gratuito sui flagship, protetto da checkStatus().

🧱

MobileCLIP-S2: la base

Rilevamento zero-shot in secondi, su ogni telefono.

🧑‍🍳

Gemma: il creatore

Ricette generate on-device: il compito che solo un LLM sa fare.

🔌

Una sola interfaccia nel codice

La UI non sa mai quale motore ha risposto.

In pratica è un pattern che conosciamo benissimo: un’interfaccia, più implementazioni, e una piccola strategia che sceglie a runtime la migliore disponibile. Questo permette di aggiungere, togliere o sostituire modelli senza toccare una riga di UI.

CONCLUSIONE

Punti chiave

1
Il modello giusto prima del modello veloceRiconoscere è confrontare, scrivere è generare. A volte il classificatore è un file di testo.
2
L’AI di piattaforma è un upgrade, non la basecheckStatus() a ogni chiamata, e sotto un fallback vero.
3
Fate i conti prima di promettereToken in uscita, giga di RAM, giga da distribuire: l’aritmetica decide.

Prima di chiedervi come renderlo più veloce, chiedetevi se è il modello giusto.

Tutti questi punti non valgono solo per un’app di ricette. Il pattern è sempre lo stesso: percezione economica come base, generazione dove serve davvero, e piattaforma come upgrade.

CAPITOLO BONUS: 6 · DOPO I TITOLI DI CODA

Avevamo detto cinque…

Il protagonista: EmbeddingGemma 2

🧠
Il nuovo modello di embedding di Google DeepMindRilasciato martedì 6 ottobre e costruito su Gemma 4: piccolo, open e pensato per girare direttamente sul telefono
🧭
Non scrive: trasforma tutto in vettoriTesto, immagini, audio e video diventano 768 numeri nello stesso spazio: la foto dei pomodori finisce vicino a “pomodori”
🌍
Etichette in italiano, e un vocabolario che cresceCapisce oltre 100 lingue, e la parte testo è sul telefono: l’app potrebbe imparare da sola gli ingredienti che aggiungete a mano
📜
Pronto per un prodotto, sul motore di GemmaApache 2.0 (MobileCLIP è solo per ricerca) e gira su LiteRT-LM. L’abbiamo provato: riconosce già i nostri ingredienti

Per ora, su un Pixel 7, è più lento di MobileCLIP: circa 40 secondi foto, contro circa 20. Ma è uscito martedì: diamogli tempo.

▶ Guarda lo spezzone
Il talk

DevFest Milano 2026, in foto

Tutte le foto del talk, nell’ordine in cui sono state scattate, e uno spezzone di 35 secondi. Tocca una foto per aprirla in grande e scorrere la galleria.

Grazie

Salvatore MatriscianoMobile Developersalvatorematrisciano.com
Stefano SorianoMobile Developerlinkedin.com/in/stefanosoriano51
Codice e slide
Com’è andata?

github.com/MatriscianoSalvatore/ai-pantry

↑ Torna all’inizio
DevFest Milano 2026

AI On-Device

Cooking from your fridge with Gemini Nano, MobileCLIP and Gemma

Salvatore Matrisciano · Stefano Soriano · Mobile Developers

Gemini NanoMobileCLIP-S2Gemma 4 E2B

SALVATORE:

Ciao, ciao a tutti! Io sono Salvatore Matrisciano e sono uno sviluppatore mobile…

STEFANO:

…e io sono Stefano Soriano, anche io sviluppatore mobile. Ciao a tutti!

SALVATORE:

Allora, oggi vi raccontiamo una storia. Una storia vera.

La storia di un’app che guarda dentro il vostro frigo e vi consiglia cosa cucinare stasera.

L’abbiamo costruita con tre modelli di intelligenza artificiale diversi: Gemini Nano, Gemma e MobileCLIP.

E tutti e 3 girano direttamente sul telefono, in locale.

Non vi faremo vedere solo la versione finale, quella che funziona.

Ma vi faremo vedere anche le strade sbagliate che abbiamo preso, perché è da lì che abbiamo imparato di più.

Partiamo da una domanda.

Cosa succede quando decidi di far girare tutta l’AI della tua app direttamente sul telefono?

Niente cloud. Niente API key. Nessuna foto della cucina dei tuoi utenti su un server.

Cosa succede quando decidi di far girare tutta l’AI della tua app direttamente sul telefono?

Oggi, quando aggiungiamo una feature AI a un’app, ci viene quasi in automatico:

prendo una API key, chiamo un modello nel cloud, mando la richiesta, aspetto la risposta.

Funziona, è comodo, lo facciamo tutti.

Punto principale: chiamare un’API AI in un’app prima di tutto ha un costo.

Poi, nel nostro caso la richiesta è una foto dell’interno della cucina di qualcuno.

Del suo frigo. Di cosa mangia, di come vive.

Ci siamo quindi chiesti: e se non la mandassimo da nessuna parte?

Niente cloud. Niente API key da proteggere. Nessuna foto su nessun server.

Ogni richiesta che mandi a un server è una cosa in più da proteggere, da giustificare, da spiegare all’utente nella privacy policy, e anche, soprattutto, da pagare.

Prima di andare avanti, vi facciamo vedere l’app.

L’APP

AI Pantry: scansiona il frigo, ottieni la cena

📷
Fotografi il frigo → riconosce gli ingredienti
🧺
Si ricorda la tua dispensa
🍝
Ti propone cosa cucinare e scrive la ricetta
🔒
100% on-device: foto e prompt non escono dal telefono

L’app si chiama AI Pantry: Dispensa AI, e l’idea è molto semplice: fai una foto al frigo e ottieni un’idea di ricetta per cena.

Funziona così. Prima fai una o più foto al tuo frigo, e l’app riconosce gli ingredienti che vede.

Poi con quelle foto costruisce l’inventario della tua dispensa. Quindi l’app si ricorda cos'hai.

E poi, da quello che hai davvero in dispensa, genera idee di ricette.

Infine, se una ti piace, genera la ricetta completa, con tutti gli step per cucinarla.

E il punto centrale è che è tutto al 100% on-device.

Quindi le foto e i prompt non lasciano mai il telefono.

Andiamo a vederla:


🎬 DEMO LIVE:

[Prima del talk: telefono in mirroring, modalità aereo ATTIVA, dispensa vuota (“La tua dispensa è vuota”, eventualmente “Svuota tutto”), Gemma già pronto (niente banner “Preparazione di Gemma 4 E2B…”). Tenere in galleria una foto di frigo e una di dispensa già testate, da scegliere con il pulsante della galleria in basso a sinistra. Video di backup pronto: demo.mp4.]

[Tempi, dal video: ogni foto si analizza in 20-25 secondi, le 4 ricette arrivano in meno di un minuto, la ricetta completa in poco più di 2 minuti.]

[mostra la barra di stato]

Prima cosa: guardate qui in alto. Il telefono è in modalità aereo. Internet non serve.

[tocca “Scansiona il frigo”, “Frigo” già selezionato, scatta la foto o la sceglie dalla galleria]

Scelgo “Frigo”, inquadro il frigo e scatto.

[sullo schermo “Riconosco gli ingredienti”: sulla foto si accendono le zone che sta analizzando (“Zone analizzate”) e gli ingredienti compaiono man mano]

Quello che sta succedendo adesso è la parte di percezione: l’app sta capendo quali ingredienti ci sono nella foto, zona per zona, e li vedete comparire appena li trova. Nel corso del talk vi spieghiamo perché questa parte, all’inizio, ci metteva minuti, e come l’abbiamo portata a pochi secondi.

[si apre il foglio “N ingredienti trovati”]

Eccoli. [leggere ad alta voce 3-4 ingredienti che compaiono davvero]. Ognuno ha la sua confidenza, e quelli sotto una certa soglia vengono già scartati. Se qualcosa è sbagliato, lo tolgo con la X. [rimuove un elemento se serve]

[indica la riga in alto “MobileCLIP-S2 zero-shot · LiteRT · on device”]

E guardate questa riga: l’app vi dice quale motore ha fatto il lavoro. Su questo telefono è [leggere: MobileCLIP-S2 oppure Gemini Nano]. Tenetelo a mente, perché è il cuore del talk.

[tocca “Altra scansione”, seleziona “Dispensa”, scatta o sceglie la foto della dispensa]

Faccio lo stesso con la dispensa. Le due scansioni si sommano. [il foglio ora conta gli ingredienti di tutte e due]

[tocca “Aggiungi a frigo e dispensa (N)”, torna a “La tua cucina” con frigo e dispensa]

Aggiungo tutto. E questo è l’inventario, salvato in locale sul telefono.

[tocca “Cosa posso cucinare? (N)”]

Adesso la parte divertente. Chiedo all’app: cosa ci cucino con questa roba?

[schermata “Genero le ricette”, poi le ricette arrivano una alla volta (“Ricetta 2 di 4”…)]

Qui entra in gioco un modello diverso, un LLM vero e proprio, Gemma, perché inventare una ricetta è un compito completamente diverso dal riconoscere un’anguria. Anche questo lo vedremo nel dettaglio.

[appare la lista “Ecco cosa puoi cucinare”]

Ecco quattro idee per la cena, con tempo e difficoltà. Sono ordinate in base a quanto usano quello che ho davvero: quelle che richiedono di comprare qualcosa finiscono in fondo, e l’app mi dice cosa mi manca. [se una ricetta mostra “Mancano: …”, indicarlo] E se non mi convincono, “Altre ricette” me ne propone altre quattro.

[apre una ricetta: in basso “Genero la ricetta…”]

Apro questa. Quantità e passaggi non esistevano finché non l’ho aperta: li sta scrivendo adesso, qui sul telefono. [compaiono le quantità, poi i passaggi del “Procedimento” uno alla volta, poi le “Varianti”. Non aspettare la fine: la ricetta completa ci mette poco più di 2 minuti]

E vi ricordo: modalità aereo. Nessuna chiamata di rete. Nessun costo per chiamata. Nessuna foto di questo frigo è finita su un server.

Questa è AI Pantry. Ora vi raccontiamo come ci siamo arrivati, e perché ci abbiamo messo più tentativi del previsto. [torna alle slide]

[PIANO B: se la demo si blocca → “La demo on-device ha deciso di essere molto on-device” → far partire il video di backup (demo.mp4) e commentarlo con lo stesso script. Nel video il telefono non è in modalità aereo: saltare le frasi sulla modalità aereo. La ricetta completa occupa gli ultimi 2 minuti del video: si può mandare avanti.]

La demo

Dall'inizio alla fine

La registrazione dello schermo: il piano B del talk.

▶ Guarda la demo
⏱
20–25 s per fotoil riconoscimento, zona per zona
🍽
4 ricette in meno di un minutouna alla volta, appena sono scritte
📜
La ricetta completa in ~2 minutiquantità, passaggi e varianti in streaming

Il video di backup della demo (demo.mp4), compresso dentro questa pagina: si avvia con il pulsante.

Tempi, dal video: ogni foto si analizza in 20-25 secondi, le 4 ricette arrivano in meno di un minuto, la ricetta completa in poco più di 2 minuti. La ricetta completa occupa gli ultimi 2 minuti del video: si può mandare avanti.

MOTIVAZIONE

Perché on-device? Privacy, prima di tutto

🔒

Nessun server che vede le foto

Le foto della cucina non escono dal telefono.

📝

Nessun Data Processing Agreement (DPA)

Nessun fornitore riceve le foto: niente da firmare.

🗄

Nessun problema di data retention

Se non memorizzi mai dati, la retention non è un problema.

🕳

Nessun log da far trapelare

Il dato più sicuro è quello che non hai mai raccolto.

Ok, quindi torniamo un passo indietro.

Perché on-device? Perché complicarsi la vita, quando un’API cloud avrebbe fatto il lavoro molto più velocemente?

La prima risposta, è la privacy. Prima di tutto.

Nessun server che vede le foto.

Le foto della cucina non lasciano mai il telefono.

E una foto del frigo racconta molto più di quanto si possa pensare: abitudini alimentari, allergie, magari condizioni di salute, e a volte anche un pezzo di casa sullo sfondo.

Nessun Data Processing Agreement.

Nello sviluppare un’app, appena mandi dati utente a un fornitore terzo, parte il giro di legal, DPA, valutazioni…

Se nessun dato utente esce, non c’è nessun agreement da firmare.

Nessun problema di data retention.

Per quanto tempo tengo le foto? Dove? Chi le può cancellare?

Se non le memorizzi mai, la domanda non si pone proprio.

E infine, nessun log sul server.

Nessuna richiesta cloud significa che non c’è niente da far trapelare, e niente da violare.

Il dato più sicuro è quello che non hai mai raccolto.

Ma la privacy non è l’unico motivo.

MOTIVAZIONE

…poi resilienza e costi

📶

Funziona anche senza internet

Senza rete, in modalità aereo, con segnale debole (anche in cucine seminterrate)

⚡

Nessun round-trip verso il server

Niente latenza di rete: il “backend” è già in tasca.

📈

Il costo del cloud cresce con l’uso

Ogni foto si paga, per ogni utente, ogni giorno.

🔄

On-device ribalta il costo

L’inferenza gira sul telefono dell’utente: bolletta cloud a zero.

0 €

bolletta cloud

Anche con un milione di utenti.

Poi ci sono resilienza e costi.

Resilienza vuol dire, prima di tutto, che funziona anche senza internet.

Senza rete, in modalità aereo, come abbiamo visto, o con il segnale debole.

E un frigo si trova in cucina, magari in una casa vecchia, magari in una taverna o in un seminterrato, o comunque può trovarsi in posti dove internet non prende.

Poi, nessun round-trip verso il server. Niente latenza di rete, niente cold start.

Il “backend”, tra virgolette, è già caldo, ce l’hai in mano.

Poi c’è il tema dei costi, che per un prodotto vero è enorme: il costo del cloud cresce con l’uso.

Ogni chiamata multimodale si paga per immagine e per token.

E va moltiplicato per ogni scansione, per ogni utente attivo, ogni giorno.

Più l’app ha successo, più costa.

On-device ribalta completamente questo modello.

L’inferenza gira sull’hardware dell’utente, e la bolletta cloud resta a zero.

Anche con un milione di utenti.

Quindi: privacy, resilienza e costi.

Ora, quale modello usiamo?

PRIMA SCELTA

La scelta ovvia: Gemini Nano

📱
Già nel sistema operativo, multimodale
📦
Una dipendenza, zero megabyte nell’APK
⚙️
Accelerazione hardware e aggiornamenti gestiti da Google

Perfetto. Tranne che…

Oggi, la scelta ovvia, se sviluppi su Android, è Gemini Nano.

È il modello on-device che Google ha integrato in Android: non sta nella tua app, vive nel sistema operativo.

Ed è multimodale: quindi gli puoi dare una foto e del testo, e risponde con del testo.

Esattamente quello che serve per scansionare un frigo: “ecco la foto, dimmi cosa c’è dentro”.

Poi la parte più bella è che è una dipendenza Gradle.

Quindi zero megabyte nell’app.

Non c’è nessun modello da includere, da scaricare o da aggiornare: se ne occupa interamente la piattaforma.

In più, accelerazione hardware inclusa: quindi sfrutta gli acceleratori hardware del telefono, senza dover scrivere una riga di codice specifico per il chip.

E gli aggiornamenti sono gestiti direttamente da Google: quando esce una versione migliore del modello, arriva agli utenti senza un nuovo rilascio dell’app.

Per uno sviluppatore Android, è quasi troppo bello per essere vero.

Sulla carta era perfetto. [pausa]

Tranne che…

PRIMA SCELTA · IL PROBLEMA

Gira solo sui flagship più recenti.

Pixel 10/11, Galaxy S26 e pochi altri top di gamma:
non i telefoni che la maggior parte della gente ha davvero.

…gira solo sui flagship più recenti.

Pixel 10, Pixel 11, Galaxy S26…

Telefoni bellissimi.

Ma non sono i telefoni che la maggior parte delle persone ha davvero in tasca.

E questo per chi rilascia un’app è un problema serio.

Se costruisci la feature principale della tua app su un modello che c’è solo su una piccola fetta di dispositivi, per tutti gli altri semplicemente l’app non funziona.

E non c’è niente che si possa fare lato codice: non è una questione di permessi o di versione di Android, dipende dall’hardware e da cosa Google ha deciso di supportare.

Quindi abbiamo capito subito: Gemini Nano poteva essere un bonus, ma non poteva essere la base della nostra app.

Ci serviva un piano B che girasse su tutti i telefoni, o quasi.

PIANO B

Un solo LLM multimodale per fare tutto

🧠
Gemma 4 E2BIl modello open di Google: lo porti tu, gira anche dove Nano non c’è (con abbastanza RAM).
✅
Ha funzionato.Ingredienti corretti, JSON valido, ricette vere.
⏳
Ma ci metteva 5-10 minuti per scansioneSu un Pixel 7, un telefono di quattro anni fa. Nessuno aspetta 10 minuti per un’idea per cena.

Il piano B era semplice, almeno nella nostra testa: un solo LLM multimodale che fa tutto.

Abbiamo scelto Gemma. La versione 4 E2B. Quindi Gemma, quarta generazione, 2 miliardi di parametri effettivi.

Pesi aperti, multimodale, ovvero visione più testo, e gira su qualsiasi telefono, perché il modello lo porti tu.

L’idea sembrava elegante: un modello, due compiti.

Prima gli chiedi “cosa c’è in questa foto?”, e poi gli chiedi “Che cosa ci cucino?”.

Quindi l’abbiamo integrato, e ha funzionato.

Ingredienti corretti, JSON valido, ricette vere.

Il modello riconosceva le uova, distingueva lo yogurt dal latte, rispettava il formato che gli chiedevamo.

Dal punto di vista della qualità, sembrava perfetto.

[pausa]

Però ci metteva 5-10 minuti per una singola scansione.

Su un Pixel 7, un telefono di fascia media.

E nessuno ovviamente inquadra il frigo e aspetta dieci minuti per avere un’idea per la cena.

In dieci minuti ordini una pizza e ti arriva a casa. [pausa]

Quindi avevamo due strade (Gemini Nano e Gemma) e nessuna delle due andava bene: una veloce ma solo per pochi, e una per tutti ma inutilizzabile.

Come ne siamo usciti? Ve lo raccontiamo in cinque capitoli.

QUESTA SESSIONE

Come l’abbiamo risolto, in cinque capitoli

01
Gemini Nano via ML Kit GenAIUn upgrade gratuito, mai la base
Gemini Nano
02
Un modello per domarli tutti: Gemma…e perché era così lento
Gemma 4 E2B
03
Rilevamento zero-shot con MobileCLIP-S2Un modello che confronta, non che scrive
MobileCLIP-S2
04
Dove l’LLM si guadagna il suo postoGenerazione delle ricette
Gemma · LiteRT-LM
05
La distribuzioneOgni modello viaggia in modo diverso
Play for On-device AI

Capitolo 1: Gemini Nano, tramite Machine Learning Kit GenAI.

Come usarlo come un upgrade gratuito, ma mai come la base della nostra app.

Capitolo 2: un modello per domarli tutti (Gemma), e perché andava così lento.

Capitolo 3: rilevamento zero-shot con MobileCLIP-S2.

Il capitolo in cui siamo passati da minuti a secondi.

Capitolo 4: dove l’LLM si guadagna davvero il suo posto, cioè la generazione delle ricette.

E infine, capitolo 5: la distribuzione.

Perché ogni modello arriva sul telefono in un modo diverso, e questo conta molto più di quanto si possa pensare.

Vi spoilero già il finale, così non c’è suspense: alla fine abbiamo usato tutti e 3 i modelli.

Ma ognuno per un compito diverso, e il punto principale è capire perché.

CAPITOLO 1 · GEMINI NANO

Il protagonista: Gemini Nano

🧬
Il membro più piccolo della famiglia Gemini di GoogleDistillato per girare su un telefono. Stesso DNA dei fratelli cloud, ridotto finché non entra nel budget di memoria e termico di un telefono
🖼
Multimodale: foto + testo in, testo outProprio il nostro problema: "guarda questo frigo, dimmi cosa c'è dentro"
📲
Un solo modello condiviso per dispositivoAggiornato da Google Play services: nano-v3 / nano-v4 in base al dispositivo, migliora senza che tu rilasci nulla
0️⃣
Il costo per la tua app: zero megabyte

Capitolo uno. Il protagonista: Gemini Nano.

È il membro più piccolo della famiglia Gemini di Google.

È un modello distillato per girare su un telefono: stesso DNA dei fratelli che girano nel cloud, ma ridotto finché non entra nel budget di memoria e nel budget termico di uno smartphone.

Perché su un telefono non conta solo quanto è veloce, ma anche quanto scalda.

È multimodale: foto più testo in ingresso, testo in uscita.

Ed era proprio il problema che volevamo risolvere con la nostra app: “Guarda questo frigo, dimmi cosa c’è dentro”.

Poi c’è un dettaglio architetturale importante: c’è un solo modello, condiviso, per dispositivo. Non uno per app.

Viene aggiornato tramite Google Play services, e a seconda del dispositivo può essere nano v3 o v4.

Quindi il modello migliora nel tempo senza rilasciare nuovi aggiornamenti dell’app.

Si può usare tramite Machine Learning Kit GenAI, che espone sia API già pronte, come riassunti o riscrittura del testo, sia una Prompt API in cui il prompt lo possiamo scrivere noi.

E noi ovviamente abbiamo usato la Prompt API.

E il costo per la tua app? Zero megabyte.

Ma come fa a costare zero? Dove sta il modello?

CAPITOLO 1 · GEMINI NANO

Il modello vive in AICore, non nella tua app

AI Pantryfoto + prompt Un’altra appstesso modello E un’altranessuna copia in più AICoreservizio di sistema Androidpesi, storage, aggiornamentiaccelerazione hardwarecheckStatus() Gemini Nanouna sola copia sul discoaggiornata da Play servicesnano-v3 · nano-v4 LE APP NON TOCCANO MAI UN FILE DEL MODELLO
⚙️
AICore è un servizio di sistema AndroidGestisce pesi, storage, aggiornamenti e accelerazione hardware, la tua app non tocca mai un file del modello.
🖼
Prompt multimodali: foto + testo in, testo outGira su pesi che non devi mai distribuire, scaricare o aggiornare.
🔗
L’integrazione è una dipendenza e una regola…

Il modello vive in AICore, non nell'app.

AICore è un servizio di sistema di Android.

Gestisce lui i pesi del modello, lo storage, gli aggiornamenti e l’accelerazione hardware.

L’app non tocca mai un singolo file del modello.

Basta mandare una richiesta, ed AICore restituisce una risposta.

E le richieste possono essere multimodali: foto più testo in ingresso, testo in uscita

Tutto questo gira su pesi che non serve mai distribuire, scaricare, o aggiornare.

E c’è un vantaggio da non sottovalutare: se 10 app sullo stesso telefono usano Gemini Nano, il modello sul disco è uno solo.

Non dieci copie da qualche gigabyte ciascuna

Per l’utente è un risparmio enorme di spazio, e per chi sviluppa app è un problema in meno.

Per noi sviluppatori è quindi un modello mentale molto comodo: è come usare la fotocamera o il GPS.

È una capability del sistema, non una cosa da impacchettare nell’app.

Ma proprio perché è una capability del sistema, può esserci o non esserci.

E quindi l’integrazione si riduce a una dipendenza e a una regola.

CAPITOLO 1 · GEMINI NANO

Una dipendenza, una regola: verifica, poi chiama

DetectIngredients.kt
implementation("com.google.mlkit:genai-prompt:1.0.0-beta2")val model = Generation.getClient()suspend fun detect(bitmap: Bitmap) = when (model.checkStatus()) { // runtime, non compile time FeatureStatus.AVAILABLE -> detectWithNano(bitmap) FeatureStatus.DOWNLOADABLE -> { scope.launch { model.download().collect() } // download in background clip.detect(bitmap) // fallback } else -> clip.detect(bitmap) // fallback: MobileCLIP, non un errore }suspend fun detectWithNano(bitmap: Bitmap) = model.generateContent( generateContentRequest(ImagePart(bitmap), TextPart(prompt)) { temperature = 0.2f })

Si controlla a ogni chiamata: la disponibilità cambia a runtime.

La dipendenza è Machine Learning Kit GenAI Prompt API.

Poi si prende il client con getClient().

E ora la regola: prima di chiamare il modello, bisogna sempre chiamare checkStatus().

La disponibilità è una questione di runtime, non di compile time.

Non si può sapere finché non si builda l’app.

Gli stati che ci interessano sono tre.

AVAILABLE: il modello c’è, è pronto, si può usare Nano.

DOWNLOADABLE: il dispositivo lo supporta, ma il modello non è ancora stato scaricato. In quel caso lanciamo il download in modo opportunistico, in background, ma intanto, per questa richiesta, usiamo il fallback. Non facciamo aspettare l’utente.

E in tutti gli altri casi, cioè dispositivo non supportato, fallback, direttamente.

Poi la chiamata vera è banale: generateContent con un’ImagePart, cioè il bitmap della foto, e una TextPart con il prompt.

Temperatura bassa in questo caso, 0.2, perché qui non vogliamo creatività: vogliamo una lista di ingredienti affidabile.

E il fallback non è un messaggio di errore: è un altro motore di rilevamento.

La cosa più importante è che lo stesso telefono può rispondere in modo diverso nel tempo.

Oggi il modello non è ancora scaricato, domani sì, dopodomani il sistema lo può rimuovere per liberare spazio.

Quindi quel check non si fa una volta all’avvio: si fa ogni volta.

Bene. Nano risolve il problema sui flagship.

Ma non per tutti gli altri. Quindi torniamo al nostro piano B.

CAPITOLO 2 · UN MODELLO PER DOMARLI TUTTI

Il protagonista: Gemma 4 E2B

🔓
La famiglia open-weights di GoogleIl fratello scaricabile di Gemini. I pesi sono tuoi da includere e distribuire nella tua app; nessuna fatturazione per chiamata, nessun server
📐
'4 E2B' = 4ª generazione, 2 miliardi di parametri effettiviProgettato per i telefoni. Trucchi di memoria danno qualità da grande modello con un’impronta RAM da telefono; instruction-tuned
👁
Multimodale: un vision encoder alimenta il language modelSa guardare E scrivere. Esattamente ciò che serve a uno scanner per il frigo, e può generare anche le ricette
🧩
Via LiteRT-LM su ogni AndroidUn modello, un’integrazione, entrambi i compiti: rilevamento E ricette

STEFANO:

Capitolo due. Il protagonista: Gemma 4 E2B.

Gemma è la famiglia open-weights di Google.

Potete pensarla come il fratello scaricabile di Gemini.

I pesi sono vostri: li includete e li distribuite con la vostra app.

Nessuna fatturazione per chiamata, nessun server.

Cosa vuol dire “4 E2B”? Quarta generazione, e 2 miliardi di parametri effettivi.

Quella “E” sta per effective: è progettato apposta per i telefoni, con dei trucchi di memoria che gli danno una qualità da modello più grande, ma con un’impronta di RAM da telefono.

Ed è instruction-tuned, quindi segue bene le istruzioni.

È multimodale: c’è un vision encoder che alimenta il language model.

Quindi sa guardare e sa scrivere.

Esattamente quello che serve a uno scanner per il frigo, e in più può generare anche le ricette.

E gira tramite LiteRT-LM su qualsiasi Android.

Non dipende da quale chip ha l’utente.

Un modello, un’integrazione, due compiti: rilevamento e ricette.

Per chi non lo conosce, LiteRT è il nuovo nome di TensorFlow Lite, e LiteRT-LM è la sua estensione pensata apposta per far girare language model sul dispositivo: gestisce tokenizzazione, cache, sessioni di conversazione, e sceglie CPU o GPU.

Sembrava l’architettura perfetta.

Vediamo come l’abbiamo usato.

CAPITOLO 2 · UN MODELLO PER DOMARLI TUTTI

Chiedi all’LLM di guardare, e di scrivere

LlmVisionIngredientDetector.kt
val prompt = """ This is a photo of the inside of a $place. Identify the food ingredients you can see, at most 15. Respond with ONLY a JSON array (no markdown, no extra text): [{"name": "...", "quantity": "..."}] Only include items you actually see. Use common English ingredient names.""".trimIndent()conversation.sendMessage(Contents.of(Content.Text(prompt), Content.ImageBytes(jpeg)))// → parsing del JSON, retry silenziosi se malformato

Il rilevamento come problema di prompting: nessun dataset, nessun training. Basta chiedere.

Cosa potrebbe andare storto?

L’approccio era: chiedi all’LLM di guardare, e poi di scrivere.

Questo è, più o meno, il prompt che usavamo.

“Questa è una foto dell’interno di un frigorifero. Identifica gli ingredienti alimentari che vedi, al massimo 15.

Rispondi solo con un array JSON, niente markdown, nessun testo extra.”

E gli diamo lo schema: nome e quantità approssimativa. E infine: “includi solo gli elementi che vedi davvero”, per limitare le allucinazioni.

Poi mandiamo foto e prompt nella conversazione, prendiamo il testo, facciamo il parsing del JSON, e se è malformato riproviamo in silenzio. Ci torneremo, su questo.

Da notare anche il limite di quindici elementi: non è casuale.

Ogni ingrediente in più nella risposta sono token in più da generare, e, come vedremo tra un attimo, i token in uscita costano molto.

E la cosa affascinante è la nota in basso: il rilevamento diventa un problema di prompting.

Nessun dataset da raccogliere, nessun training, nessuna etichettatura. Basta chiedere.

[pausa]

Cosa potrebbe andare storto?

[pausa]

Beh, lo sapete già: 5-10 minuti per scansione. La domanda interessante è: perché?

CAPITOLO 2 · PERCHÉ ANDAVA A RILENTO

Il costo a due fasi degli LLM multimodali

Fase 1prefill
Fase 2decode
[{"name":"eggs","quantity":"6"},{"name":"milk","quantity":"1 L"},{"name":"tomatoes"…
una scansione su fascia media
5–10 min

Scansione di 5-10 minuti su fascia media

L’aritmetica, non la qualità del modello, decide tra secondi e minuti.

Conosci questo modello di costo

Prima di promettere qualsiasi UX multimodale.

Perché andava così lento?

Qui c’è il concetto più importante di questo capitolo: il costo a due fasi degli LLM multimodali.

Fase uno: il prefill.

Prima di scrivere anche solo una parola, il modello deve leggere tutto l’input.

E la nostra foto non è “un’immagine”: per il modello diventa qualche centinaio di token immagine.

Token che vanno elaborati tutti, prima che compaia qualsiasi output.

Su un telefono di fascia media, già questo da solo è pesante.

Fase due: il decode. La risposta viene generata un token alla volta.

E ogni singolo token passa attraverso un modello da due miliardi di parametri.

Un JSON con quindici ingredienti e quantità sono tanti token, e ognuno costa un passaggio completo del modello.

Per darvi un’idea: sul cloud, su GPU da data center, entrambe le fasi sono talmente veloci che non ci pensate nemmeno.

Sul telefono, con memoria condivisa, limiti termici e una batteria da non prosciugare, ogni token si sente.

Mettete insieme le due fasi, e su un telefono di fascia media ottenete una scansione da 5-10 minuti.

E notate: non è un problema di qualità del modello. Le risposte erano giuste. È l’aritmetica a decidere tra secondi e minuti.

Quindi, il consiglio: conoscete questo modello di costo prima di promettere qualsiasi UX multimodale.

Prima di dire al product owner “facciamo scattare una foto e l’AI capisce tutto”, fate questo conto.

E a quel punto ci siamo fatti la domanda giusta:

Ci serve davvero un modello che scrive, per riconoscere un’arancia?

CAPITOLO 3 · RILEVAMENTO ZERO-SHOT

Il protagonista: MobileCLIP-S2

📏
Non è un LLM: non genera nulla, misuraQuanto un’immagine corrisponde a una frase. Un modello della famiglia CLIP: Contrastive Language–Image Pre-training
🍏
La versione mobile di CLIP di AppleDistillato da modelli più grandi. S2 è il giusto mix accuratezza/velocità: zero-shot accurato come modelli più grandi, a latenza da telefono
🪶
~140 MB, input 256×256, embedding a 512 dimensioniMinuscolo accanto a un LLM da 2 miliardi di parametri, e con un profilo di costo completamente diverso
📱
Pesi aperti, si esporta senza problemi in LiteRTGira su qualsiasi telefono Android. Nessun AICore richiesto, nessuna lotteria del silicio: questa può essere la base

Capitolo tre. Il protagonista: MobileCLIP-S2.

Prima cosa da capire: non è un LLM.

Non genera nulla. Misura.

Misura quanto un’immagine corrisponde a una frase.

È un modello della famiglia CLIP, che sta per Contrastive Language–Image Pre-training.

MobileCLIP è la versione mobile di CLIP, realizzata da Apple.

Sì, in un talk Android a una DevFest usiamo un modello di Apple: l’open source è bello anche per questo.

È distillato da modelli più grandi, e la variante S2 è il giusto compromesso tra accuratezza e velocità: in zero-shot è accurato come modelli più grandi, ma con una latenza da telefono.

I numeri: circa 140 megabyte, input a 256 per 256 pixel, embedding a 512 dimensioni.

Minuscolo, accanto a un LLM da 2 miliardi di parametri, e soprattutto con un profilo di costo completamente diverso.

E “zero-shot” è la parola chiave: significa che il modello riconosce categorie su cui non è mai stato addestrato esplicitamente.

Non abbiamo fatto nessun fine-tuning sugli ingredienti.

Non abbiamo raccolto nemmeno una foto di frigo.

Pesi aperti, si esporta senza problemi in LiteRT, e gira su qualsiasi telefono Android.

Questo sì che può essere la base della nostra app.

CAPITOLO 3 · RILEVAMENTO ZERO-SHOT

Il riconoscimento non richiede un modello che scrive, ma uno che confronta

oranges milk eggs bananas ~an empty shelf 📷 cos θ massimo → oranges SPAZIO A 512 DIMENSIONI (QUI IN 2)
🔀
Modelli della famiglia CLIP: due piccoli encoderAddestrati su milioni di coppie immagine–didascalia, così le coppie corrispondenti finiscono vicine nello spazio vettoriale.
📐
"È un’arancia?" diventa una similarità del cosenoIl riconoscimento diventa geometria: un prodotto scalare, non un paragrafo generato.
🪶
Basta un encoder da ~140 MBMobileCLIP-S2 gira su LiteRT su qualsiasi telefono Android, nessun ciclo di decode richiesto.

L’intuizione chiave è questa: il riconoscimento non richiede un modello che scrive, ma un modello che confronta.

Come funziona CLIP?

Sono due piccoli encoder: uno per le immagini, uno per il testo.

Sono stati addestrati su milioni di coppie immagine–didascalia, in modo che una foto e la frase che la descrive finiscano vicine nello stesso spazio vettoriale.

La foto di un’arancia e la frase “una foto di un’arancia” diventano due vettori che puntano più o meno nella stessa direzione.

E quindi la domanda “è un’arancia?” diventa una similarità del coseno.

Prendo il vettore dell’immagine, prendo il vettore della frase, faccio un prodotto scalare.

Il riconoscimento diventa geometria.

Un prodotto scalare, e non un paragrafo generato.

E il bello della similarità del coseno è che è un numero: da meno uno a uno.

Possiamo mettere una soglia, ordinare i risultati, scartare quelli poco convinti.

Niente JSON da parsare, niente allucinazioni in forma di testo: al massimo un punteggio basso.

Ora ripensate alle due fasi di prima.

Qui non c’è decode: non genero nessun token.

Non c’è un prefill da centinaia di token attraverso due miliardi di parametri.

C’è solo un encoder da circa 140 mega che guarda la foto. Fine.

MobileCLIP-S2 gira su LiteRT, su qualsiasi telefono Android, senza nessun ciclo di decode.

C’è però una domanda ovvia: se il modello confronta un’immagine con delle frasi… quali frasi? Da dove arrivano?

CAPITOLO 3 · IL TRUCCO

Il vocabolario l’abbiamo costruito noi, ed è un file di testo

scripts/ingredient_labels.txt · prepare_clip_assets.py
# scripts/ingredient_labels.txt · 870 etichette di ingredienti curate a manoorangesstrawberriesbananas…lactose-free milk|milk match specifico | nome mostrato all’utentebottle of whole milk|milk…~an empty shelf distrattore: assorbe i ritagli vuoti# prepare_clip_assets.py · offline, sul laptop, una volta solaTEMPLATES = ["a photo of {}", "a photo of {} in a refrigerator", "a photo of {} on a pantry shelf", "a close-up photo of {}"]

Il “classificatore” è un file di testo: vuoi un ingrediente in più? Aggiungi una riga.

Ed ecco il trucco: il vocabolario l’abbiamo costruito noi.

Ed è un file di testo.

Si chiama ingredient_labels.txt, e contiene più di ottocento etichette di ingredienti, curate a mano.

Arancia. Fragola. Banana.

E guardate la terza riga: “latte senza lattosio, pipe, latte”. A sinistra c’è l’etichetta specifica, quella che usiamo per il match; a destra quella semplice, che mostriamo all’utente. Così il modello riconosce il cartone di latte intero, ma nella dispensa vedete solo “latte”.

Questo trucco risolve un problema molto concreto: CLIP ragiona meglio con descrizioni specifiche, ma per le ricette è meglio una dispensa pulita, non “cartone di latte intero parzialmente scremato”.

Poi: gli embedding del testo li calcoliamo offline, su un laptop, una volta sola.

Per ogni etichetta usiamo quattro template, tipo “una foto di un’arancia”, e facciamo la media dei vettori, che rende il risultato più robusto.

Il risultato sono circa 4,5 megabyte di vettori, inclusi nell’APK.

E qui c’è il punto chiave: siccome le etichette non cambiano a runtime, non ha senso far girare il text encoder sul telefono. Lo lasciamo sul laptop.

E quindi sul telefono gira solo l’image encoder.

Il flusso è: ritagliamo la foto in tanti crop, a due scale diverse, calcoliamo l’embedding di ogni crop, confrontiamo col coseno contro tutte le etichette, e vincono le corrispondenze migliori, sopra una soglia di confidenza.

E un dettaglio furbo: nel file ci sono anche alcune etichette “distrattore”, che non sono cibo.

Servono ad assorbire i crop vuoti, lo scaffale, la mensola, così non diventano un ingrediente.

E la cosa bella è questa: il “classificatore” è un file di testo modificabile.

Vuoi aggiungere un ingrediente? Aggiungi una riga, rigeneri i vettori, fatto. Nessun dataset, nessun training.

E il risultato?

CAPITOLO 3 · IL RISULTATO

Stesso telefono. Stessa foto del frigo.

Minuti → secondi.
Gemma 4 E2Bun LLM che guarda e scrive
5–10 min
MobileCLIP-S2un encoder che confronta
~20 s

Stesso telefono. Stessa foto del frigo.

[pausa]

Minuti… diventano secondi.

[pausa]

Non abbiamo cambiato telefono. Non abbiamo comprato un chip nuovo.

Non abbiamo quantizzato fino all’osso l’LLM.

Abbiamo cambiato la classe di modello.

Abbiamo smesso di chiedere a un modello generativo di fare un lavoro di confronto.

E il bello è che il vecchio approccio non l’abbiamo buttato: la qualità dell’LLM per il rilevamento era ottima, ma MobileCLIP ci dà una qualità comparabile in una frazione del tempo, su qualsiasi telefono.

Ed è la lezione più importante di tutto il talk: prima di ottimizzare il modello, chiedetevi se è il modello giusto per quel compito.

Ma a questo punto avevamo 2,6 gigabyte di Gemma sul telefono, e nessun lavoro da fargli fare.

CAPITOLO 4 · DOVE L’LLM SI GUADAGNA IL POSTO

Il protagonista: Gemma, il ritorno

💾
Gli stessi 2,6 GB, già sul telefonoOra fa il lavoro per cui è stato costruito. L’abbiamo messo in panchina per la percezione; non l’abbiamo mai disinstallato
📝
Stavolta solo testoNiente foto, niente token immagine, niente prefill enorme. Input: una breve lista di ingredienti
✨
Generazione instruction-tuned: le ricette sono testo nuovoInventate sul momento. L’unico compito nell’app che nessun confronto, nessun vocabolario, nessun lookup potrebbe mai svolgere
🎮
Gira tramite LiteRT-LM sulla GPU

Capitolo quattro. Il protagonista: Gemma, il ritorno.

Sono gli stessi 2,6 gigabyte che avevamo già sul telefono.

Ma ora fa il lavoro per cui è stato costruito.

Lo avevamo messo in panchina per la percezione, ma non l’abbiamo mai disinstallato.

La differenza è che stavolta lavora solo con il testo.

Niente foto, niente token immagine, niente prefill enorme.

L’input è una breve lista di ingredienti: “uova, zucchine, pomodori, Parmigiano”.

Quindi il costo a due fasi, che prima ci aveva ucciso, adesso gioca a nostro favore: prefill minuscolo, e decode che produce proprio quello che vogliamo.

E qui la generazione instruction-tuned ha senso, perché le ricette sono testo nuovo.

Sono inventate sul momento.

È l’unico compito nell’app che nessun confronto, nessun vocabolario, nessun lookup potrebbe mai svolgere.

Ma per cui serve necessariamente un LLM.

E c’è un altro vantaggio: per le ricette la creatività serve.

Qui possiamo alzare un po’ la temperatura, lasciare che il modello proponga abbinamenti che non ci aspettavamo.

Nel rilevamento la creatività era un difetto; qui diventa il prodotto.

Gira tramite LiteRT-LM, con la GPU come prima scelta.

E siccome le GPU dei telefoni Android sono un mondo variegato, se la GPU si blocca o dà errore, l’app se ne accorge, passa alla CPU e se lo ricorda per le volte successive.

E LiteRT-LM supporta anche lo streaming della risposta, token per token.

Lato UX, questo cambia tutto.

CAPITOLO 4 · DOVE L’LLM SI GUADAGNA IL POSTO

Le ricette sono creazione, non riconoscimento

🍽
Da un inventario a idee per la cenaÈ per questo che esistono i modelli generativi, nessun vocabolario chiuso può farlo.
🪜
Prompting a due stadiPrima una lista economica, poi la ricetta completa su richiesta, prompt più corti, meno attesa.
🛟
Parsing JSON difensivo con retry silenziosiI modelli piccoli rompono i contratti di formato, prevedilo, non scusarti.
⚡
La generazione solo testo va a 15–25 tok/sSenza foto, niente prefill dell’immagine: si aspetta solo il testo.
Gemma, in streaming sul telefono
≈ 18 tok/s
Pasta al pomodoro e mozzarella · 25 min · Facile
 
1. Cuocere gli spaghetti in abbondante acqua salata fino a che non sono al dente.
2. Nel frattempo, tagliare i pomodori a cubetti e metterli in una padella con un filo d’olio e qualche foglia di basilico.
3. Portare i pomodori a ebollizione, poi abbassare la fiamma e lasciar sobbollire per circa 15–20 minuti.
4. Scolare gli spaghetti e trasferirli nella padella con il sugo.
5. Aggiungere la mozzarella a cubetti e farla sciogliere delicatamente nel sugo.

Le ricette sono creazione, non riconoscimento.

Passare da un inventario a delle idee per la cena è esattamente il motivo per cui esistono i modelli generativi.

Nessun vocabolario chiuso può farlo.

Tre accorgimenti che ci hanno salvato.

Primo: prompting a due stadi.

Prima chiediamo una lista di cinque ricette, con titolo, tempo, difficoltà e ingredienti usati, ma senza procedimento.

Poi, solo quando l’utente ne apre una, generiamo passaggi e varianti.

Prompt più corti, output più corti, meno attesa.

Secondo: parsing JSON difensivo con retry silenziosi.

È facile che i modelli piccoli rompano i contratti di formato: una virgola di troppo, un blocco markdown attorno al JSON, una frase di cortesia prima della risposta.

Non è un bug raro: è il comportamento normale.

Quindi prevedetelo, non scusatevi con l’utente.

In pratica: togliamo i blocchi markdown, estraiamo tutti gli oggetti JSON che troviamo, accettiamo anche nomi dei campi scritti in modo diverso, e se una sola ricetta è rotta scartiamo quella, non tutta la lista.

E se proprio non c’è niente di valido, riproviamo, fino a quattro volte, prima di mostrare un errore all’utente.

Terzo: senza foto, la generazione solo testo va a 15–25 token al secondo.

E siccome la lista è leggera, e i passaggi li generiamo solo per la ricetta che aprite, l’attesa resta breve.

CAPITOLO 5 · LA DISTRIBUZIONE

Ogni modello viaggia in modo diverso

AICore
Gemini Nano
0 MB
Lo gestisce AICore, l’APK contiene solo un prompt.
MobileCLIP-S2
~140 MB
Incluso nell’APK come qualsiasi asset, il rilevamento funziona subito dopo l’installazione.
AI pack 1AI pack 2AI pack 3
Gemma 4 E2B
2,6 GB
Troppo grande per qualsiasi APK, e scrivere a mano un downloader riprendibile è un progetto a sé.
📦

AI pack tramite Play for On-device AI

Google Play gestisce la consegna, la distribuzione smette di essere un tuo problema.

Capitolo cinque: la distribuzione.

Perché avere tre modelli è bello, ma poi bisogna farli arrivare sul telefono.

E ogni modello viaggia in modo diverso.

Gemini Nano: zero megabyte. Lo gestisce AICore. Nel nostro APK c’è solo un prompt.

MobileCLIP-S2: circa 140 megabyte.

Lo includiamo nell’APK come qualsiasi altro asset.

Questo ha un vantaggio enorme: il rilevamento funziona subito dopo l’installazione, anche offline, anche al primo avvio.

Gemma: 2,6 gigabyte di pesi.

Troppo grande per qualsiasi APK da pubblicare sul Play Store.

E l’alternativa, scrivere a mano un downloader riprendibile, che gestisca rete che cade, spazio che finisce, integrità dei file, aggiornamenti, è un progetto a sé.

E noi non volevamo che la nostra app non scaricasse niente da internet.

E c’è anche un tema di esperienza utente: non potete chiedere a qualcuno di scaricare 2,6 giga al primo avvio, magari in 4G.

Ecco perché il rilevamento deve funzionare subito, e le ricette possono arrivare un po’ dopo.

La soluzione sono gli AI pack tramite Play for On-device AI.

Impacchettate il modello come un AI pack, e Google Play si occupa della consegna, esattamente come fa con l’app.

La distribuzione smette di essere un problema vostro.

E potete scegliere quando consegnarlo: all’installazione, in modalità fast-follow, cioè subito dopo l’installazione, in background, oppure on demand.

Noi usiamo fast-follow.

E siccome Play ha un limite di dimensione per singolo pack, abbiamo diviso Gemma in tre AI pack: al primo avvio l’app li riassembla nel modello, e poi i pack vengono rimossi per non occupare spazio 2 volte.

E ora, rimettiamo insieme i pezzi.

IL QUADRO COMPLETO

Tre modelli, tre compiti, un’app

Jetpack Compose UIuna sola interfaccia:non sa chi ha rispostoMVI · Koin · Room interface IngredientDetectorAdaptiveIngredientDetectorsceglie a ogni scansioneNano se c’è, altrimenti CLIP interface RecipeGeneratorLlmRecipeGeneratordue fasi · streamingJSON difensivo · fino a 4 tentativi Gemini Nano · l’acceleratorerilevamento gratuito sui flagshipAICore · ML Kit GenAI MobileCLIP-S2 · la basezero-shot in secondi, ovunqueLiteRT · ~140 MB Gemma 4 E2B · il creatorele ricette: solo un LLM sa farloLiteRT-LM · GPU → CPU checkStatus()ALTRIMENTI

Una sola interfaccia nel codice · La UI non sa mai quale motore ha risposto.

Ecco il quadro completo: 3 modelli, 3 compiti, un’app.

Gemini Nano è l’acceleratore.

Rilevamento multimodale gratuito sui flagship, sempre protetto da checkStatus().

Se c’è, lo usiamo. Se non c’è, nessun problema.

MobileCLIP-S2 è la base.

Rilevamento zero-shot in pochi secondi, su ogni telefono.

È la base sotto cui l’esperienza non scende mai.

Gemma è il creatore.

Ricette generate on-device: l’unico compito che solo un LLM sa fare.

E il quarto elemento, che è forse il più importante lato architettura: una sola interfaccia nel codice.

Tutti i motori di rilevamento implementano lo stesso contratto.

La UI non sa mai quale motore ha risposto. Non le interessa.

Oggi risponde Nano, domani MobileCLIP, e l’utente vede sempre la stessa esperienza.

In pratica è un pattern che conosciamo benissimo: un’interfaccia, più implementazioni, e una piccola strategia che sceglie a runtime la migliore disponibile.

Prima provo Nano; se checkStatus() dice di no, uso MobileCLIP.

Niente di magico: buona architettura Android, applicata all’AI.

Questo permette di aggiungere, togliere o sostituire modelli senza toccare una riga di UI.

Chiudiamo con quello che vorremmo vi portaste a casa.

CONCLUSIONE

Punti chiave

1
Il modello giusto prima del modello veloceRiconoscere è confrontare, scrivere è generare. A volte il classificatore è un file di testo.
2
L’AI di piattaforma è un upgrade, non la basecheckStatus() a ogni chiamata, e sotto un fallback vero.
3
Fate i conti prima di promettereToken in uscita, giga di RAM, giga da distribuire: l’aritmetica decide.

Prima di chiedervi come renderlo più veloce, chiedetevi se è il modello giusto.

3 punti chiave.

1: il modello giusto prima del modello veloce.

Riconoscere è confrontare, scrivere è generare.

Scegliere quello giusto è la differenza tra secondi e minuti.

E a volte il classificatore più economico di sempre è un file di testo: embedding delle etichette calcolati offline, zero training, zero infrastruttura.

2: l’AI di piattaforma è un upgrade, non la base.

Controllate checkStatus() a ogni chiamata, perché la disponibilità di Nano cambia a runtime.

E sotto tenete sempre un fallback vero: un altro motore, non un messaggio di errore.

3: fate i conti prima di promettere.

Token in uscita, giga di RAM, giga da distribuire.

È quell’aritmetica che decide se la vostra feature ci mette secondi o minuti.

Tutti questi punti non valgono solo per un’app di ricette.

Valgono per qualsiasi feature AI on-device: scansione di documenti, riconoscimento di prodotti, assistenti nelle app.

Il pattern è sempre lo stesso: percezione economica come base, generazione dove serve davvero, e piattaforma come upgrade.

E se proprio dovete ricordarvi una sola cosa: prima di chiedervi come rendere un modello più veloce, chiedetevi se è il modello giusto.

CAPITOLO BONUS: 6 · DOPO I TITOLI DI CODA

Avevamo detto cinque… Il protagonista: EmbeddingGemma 2

🧠
Il nuovo modello di embedding di Google DeepMindRilasciato martedì 6 ottobre e costruito su Gemma 4: piccolo, open e pensato per girare direttamente sul telefono
🧭
Non scrive: trasforma tutto in vettoriTesto, immagini, audio e video diventano 768 numeri nello stesso spazio: la foto dei pomodori finisce vicino a “pomodori”
🌍
Etichette in italiano, e un vocabolario che cresceCapisce oltre 100 lingue, e la parte testo è sul telefono: l’app potrebbe imparare da sola gli ingredienti che aggiungete a mano
📜
Pronto per un prodotto, sul motore di GemmaApache 2.0 (MobileCLIP è solo per ricerca) e gira su LiteRT-LM. L’abbiamo provato: riconosce già i nostri ingredienti

Aspettate, non è finita.

Avevamo detto cinque capitoli… ma martedì 6 ottobre (4 giorni fa) Google DeepMind ha rilasciato EmbeddingGemma 2, e non potevamo non parlarne.

Quindi: capitolo bonus, il sesto, la scena dopo i titoli di coda.

EmbeddingGemma 2 è il nuovo modello di embedding open di Google, costruito su Gemma 4 e pensato per girare sul telefono.

Come MobileCLIP, non è un LLM: non scrive niente.

Trasforma testo, immagini, audio e video in vettori di 768 numeri, tutti nello stesso spazio.

Quindi la foto dei pomodori finisce vicino alla parola “pomodori”.

È esattamente il trucco del capitolo 3: calcoliamo una volta i vettori delle etichette, sul telefono calcoliamo solo quello della foto, e vince l’etichetta più vicina.

Cosa potrebbe dare al nostro scanner?

Primo: capisce oltre 100 lingue, quindi le etichette le possiamo scrivere direttamente in italiano. MobileCLIP le capisce solo in inglese.

Secondo: oggi il vocabolario sta dentro l’app. I vettori delle etichette li calcoliamo prima, sul computer, perché sul telefono MobileCLIP ha solo la parte che guarda le foto: per aggiungere un ingrediente serve una nuova versione dell’app.

EmbeddingGemma invece sul telefono ha anche la parte testo. Quindi l’app potrebbe calcolare da sola il vettore di un ingrediente nuovo, per esempio uno che aggiungete a mano alla dispensa, e riconoscerlo già dalla foto dopo, senza aspettare un aggiornamento.

Il vocabolario potrebbe crescere insieme alla vostra dispensa.

Terzo: la licenza. È Apache 2.0, quindi si può usare in un prodotto, mentre i pesi di MobileCLIP sono solo per la ricerca.

E gira su LiteRT-LM, lo stesso motore che usiamo già per Gemma.

L’abbiamo provato sulle foto della demo: riconosce già i nostri ingredienti.

Per ora, su un Pixel 7, è più lento di MobileCLIP: circa 40 secondi foto, contro circa 20.

Ma è uscito martedì: diamogli tempo.

Grazie

Salvatore MatriscianoMobile Developersalvatorematrisciano.com
Stefano SorianoMobile Developerlinkedin.com/in/stefanosoriano51

E questo è tutto. Grazie mille!

Il codice di AI Pantry è open source: lo trovate su GitHub, al link che vedete qui, github.com/MatriscianoSalvatore/ai-pantry.

Scaricatelo, provatelo sul vostro telefono, apriteci una issue se si rompe. Nella repo trovate anche le slide del talk.

E se volete continuare la chiacchierata, trovate i nostri contatti qui: il sito di Salvatore e il mio LinkedIn.

Oppure fermateci pure dopo, siamo qui tutto il giorno.

Grazie ancora alla DevFest Milano e a tutti voi.

Se ci sono domande, siamo qui!

FEEDBACK

Com’è andata?

Inquadrate il QR per lasciare un feedback sul talk

Prima di salutarci, un’ultima cosa.

Potete Inquadrare questo QR per lasciarci un feedback sul talk.

Ci aiuta a migliorare, e aiuta gli organizzatori dell’evento a capire cosa è piaciuto.

E ora, se ci sono domande, siamo qui!

← → avanti/indietro · N note · P relatore · O panoramica · F schermo intero · D documento
1 / 1