Aller au contenu principal

Comment utiliser Gemini Nano dans une application Capacitor

Utilisez Gemini Nano dans une application Capacitor pour l'IA embarquée sur Android : appareils compatibles, vérifications AICore, streaming avec @capgo/capacitor-llm et repli sur Gemma.

Illustration des fonctionnalités IA exécutées dans une application mobile Capacitor

Pour utiliser Gemini Nano dans une application Capacitor, installez @capgo/capacitor-llm, appelez setModel({ path: 'Gemini Nano' }) sur Android, puis créez un chat et diffusez la réponse via l'événement textFromAi Le plugin communique avec Gemini Nano via le Prompt API de ML Kit GenAI de Google, qui exécute le modèle dans le service système AICore d'Android, garantissant que le texte ne quitte jamais le téléphone.

Ce guide explique le fonctionnement de Gemini Nano, les appareils compatibles, les appels précis du plugin, le streaming, les quotas et limites, un fallback Gemma pour les téléphones non compatibles, et comment le même code atteint Apple Intelligence sur iOS.

Comment Gemini Nano fonctionne sur Android

Gemini Nano est le plus petit modèle Gemini de Google, conçu pour les téléphones. Les applications ne l'embarquent pas. Le service AICore le télécharge, le met à jour et exécute l'inférence, et les applications y accèdent via les API ML Kit GenAI:

  • Prompt API : des prompts texte libres, l’API utilisé par ce plugin (com.google.mlkit:genai-prompt).
  • API de fonctionnalités : des tâches prédéfinies comme le résumé, la relecture, la réécriture et la description d'images.

Google publie le Prompt API en bêta, sans SLA ni politique de dépréciation. Anticipez donc des changements de comportement entre les releases et gardez l’intégration derrière votre propre wrapper léger.

Comme l’inférence est locale, vous bénéficiez de trois avantages qu’un modèle cloud ne peut pas offrir : il fonctionne hors ligne, il n’engendre aucun coût par token, et le texte de l’utilisateur reste sur l’appareil. En contrepartie, le modèl’est plus petit, avec un contexte et une sortie limités. Choisissez donc des tâches adaptées : réécriture, résumé d’une note, classification de message, extraction de champs, rédaction de réponses courtes.

Appareils pris en charge et prérequis

Google publie la liste des appareils pris en charge pour chaque API sur le site ML Kit GenAI, groupée par version de Gemini Nano (nano-v2, nano-v3, nano-v4). Pour le Prompt API, elle couvre le Pixel 9 et les modèles suivants, les derniers haut de gamme Samsung Galaxy S et Z, ainsi que les récents flagships de OnePlus, OPPO, Xiaomi, vivo, Honor, realme, Motorola et d’autres. Vérifiez la liste à jour avant de promettre une fonctionnalité sur un appareil précis.

Chaque appareil pris en charge doit également :

Exigence Détail
Version Android API niveau 26 ou supérieur (le plugin le vérifie)
Bootloader Verrouillé. Google ne prend pas en charge les API GenAI sur les bootloaders déverrouillés
AICore Présent et configuré. Après une configuration ou un réinitialisation de l’appareil, le processus peut prendre un certain temps.
État de l’app Votre application doit être l’application au premier plan pendant l’inférence

Différentes versions de Nano peuvent renvoyer des sorties différentes pour le même prompt. Testez vos prompts sur au moins un appareil par version qui vous intéresse.

Installer le plugin

bun add @capgo/capacitor-llm
bunx cap sync

Le plugin suit la version majeure de Capacitor : utilisez 8.x avec Capacitor 8. Aucune modification du manifest Android n’est nécessaire pour Gemini Nano. Référence complète : doc du plugin et page du plugin.

Étape 1 : Charger Gemini Nano et vérifier la disponibilité

setModel avec le chemin spécial 'Gemini Nano' demande à ML Kit l’état du modèle. La promesse est résolue lorsque l’état est disponible et rejetée sinon, avec un message incluant l’état :

État renvoyé par AICore Comportement du plugin
disponible setModel se résout, readinessChange émet ready
téléchargeable Rejette : « Gemini Nano est téléchargeable mais pas téléchargé sur cet appareil »
téléchargement Rejette avec le statut de téléchargement
indisponible Rejet : « Gemini Nano est indisponible sur cet appareil »
import { Capacitor } from '@capacitor/core';
import { CapgoLLM } from '@capgo/capacitor-llm';

export async function loadGeminiNano(): Promise<boolean> {
  if (Capacitor.getPlatform() !== 'android') return false;

  try {
    await CapgoLLM.setModel({
      path: 'Gemini Nano',
      temperature: 0.3,
      topk: 16,
    });
  } catch (error) {
    console.warn('Gemini Nano not ready:', error);
    return false;
  }

  const { readiness } = await CapgoLLM.getReadiness();
  return readiness === 'ready';
}

Le plugin ne lance pas lui-même le téléchargement du modèl’AICore. Si un appareil signale que le modèl’est téléchargeable, il arrive généralement après qu'une autre application ou le système l'a demandé. Vérifiez donc à nouveau au prochain lancement plutôt que de masquer la fonctionnalité définitivement.

Étape 2 : Créer un chat et streamer la réponse

Un chat conserve l'historique de la conversation. Sur Android, sendMessage résout dès que la génération commence, et le texte arrive via des événements. Enveloppez-le dans une promesse qui résout sur aiFinished:

import { CapgoLLM } from '@capgo/capacitor-llm';

// Android sends deltas. iOS Apple Intelligence sends the full text so far.
// This merge handles both.
function mergeChunk(current: string, chunk: string) {
  return chunk.startsWith(current) ? chunk : current + chunk;
}

export async function ask(
  chatId: string,
  message: string,
  onText: (textSoFar: string) => void,
): Promise<string> {
  let text = '';
  let finish!: (value: string) => void;
  let fail!: (error: Error) => void;
  const done = new Promise<string>((resolve, reject) => {
    finish = resolve;
    fail = reject;
  });

  const handles = await Promise.all([
    CapgoLLM.addListener('textFromAi', (event) => {
      if (event.chatId !== chatId) return;
      text = mergeChunk(text, event.text);
      onText(text);
    }),
    CapgoLLM.addListener('aiFinished', (event) => {
      if (event.chatId === chatId) finish(text);
    }),
    CapgoLLM.addListener('generationError', (event) => {
      if (!event.chatId || event.chatId === chatId) fail(new Error(event.error));
    }),
  ]);

  // If the app is backgrounded mid-answer, neither event may arrive
  const timeout = setTimeout(() => fail(new Error('Generation timed out')), 60_000);

  try {
    await CapgoLLM.sendMessage({ chatId, message });
    return await done;
  } finally {
    clearTimeout(timeout);
    await Promise.all(handles.map((h) => h.remove()));
  }
}

Utilisez-le pour une fonctionnalité réelle, par exemple pour rédiger une réponse à une critique client :

const INSTRUCTIONS =
  'You write short, polite replies to customer reviews for a small shop. ' +
  'Answer each point, stay under 60 words, never promise refunds.';

export async function draftReply(review: string, render: (t: string) => void) {
  const { id } = await CapgoLLM.createChat();
  return ask(id, `${INSTRUCTIONS}\n\nReview:\n${review}\n\nReply:`, render);
}

createChat() ne prend aucune option, placez donc les instructions au début du premier message. Créez un nouveau chat par tâche. Sur le chemin Gemini Nano, le plugin conserve l’historique en mémoire et l’envoie avec chaque message, ce qui épuise rapidement le budget d’entrée lors des conversations longues.

Limites à prendre en compte

Limite Valeur Que faire
Saisie Moins de 4 000 tokens par requête (Google) Gardez les chats courts, réduisez les documents longs
Résultat Le plugin limite les réponses de Gemini Nano à 256 tokens Demander des sorties courtes, découper les tâches longues
Premier plan Inférence uniquement lorsque votre app est au premier plan Never run it from background tasks
Quota Quotas par app, BUSY et les erreurs de quota de batterie Debounce : évitez de générer à chaque frappe
Concurrence Une génération par chat Désactivez le bouton d’envoi pendant le streaming
Vitesse Quelques secondes pour un paragraphe Streamez toujours vers l’UI

Traitez une erreur de quota comme temporaire. Affichez une option de réessai plutôt qu’une boîte de dialogue d’erreur.

Repli : Gemma 4 si Gemini Nano est absent

La plupart des téléphones Android utilisés aujourd’hui n’ont pas Gemini Nano. Le même plugin peut exécuter des modèles Gemma ouverts via LiteRT-LM, ce qui vous permet de garder un seul API. Le modèl’est volumineux, souvent plus d’un gigaoctet : ne le téléchargez qu’après le consentement de l’utilisateur, idéalement en Wi-Fi.

import { Preferences } from '@capacitor/preferences';
import { CapgoLLM } from '@capgo/capacitor-llm';

const GEMMA_URL =
  'https://huggingface.co/litert-community/gemma-4-E2B-it-litert-lm/resolve/main/gemma-4-E2B-it.litertlm?download=true';

export async function loadGemma(onProgress: (pct: number) => void) {
  const saved = await Preferences.get({ key: 'gemmaPath' });
  if (saved.value) {
    try {
      await CapgoLLM.setModel({ path: saved.value, modelType: 'litertlm', maxTokens: 4096 });
      return;
    } catch {
      // File missing or corrupt, download again
    }
  }

  const sub = await CapgoLLM.addListener('downloadProgress', (e) => onProgress(e.progress));
  try {
    const { path } = await CapgoLLM.downloadModel({
      url: GEMMA_URL,
      filename: 'gemma-4-E2B-it.litertlm',
    });
    await Preferences.set({ key: 'gemmaPath', value: path });
    await CapgoLLM.setModel({ path, modelType: 'litertlm', maxTokens: 4096 });
  } finally {
    await sub.remove();
  }
}

Choisissez ensuite le moteur au démarrage :

export async function initOnDeviceAI(userAcceptedDownload: boolean, onProgress: (p: number) => void) {
  if (await loadGeminiNano()) return 'gemini-nano';
  if (userAcceptedDownload) {
    await loadGemma(onProgress);
    return 'gemma';
  }
  return 'none';
}

Si aucune des deux options n’est possible, masquez la fonctionnalité ou appelez un modèle cloud. Ne bloquez pas les flux principaux sur l’IA locale.

Le même code sur iOS

Sur iOS, le plugin utilise Apple Intelligence via le framework Foundation Models. Modifiez une seule ligne :

await CapgoLLM.setModel({ path: 'Apple Intelligence' });

createChat, sendMessage, et les événements restent les mêmes, et le mergeChunk L'assistant ci-dessus gère déjà le format de streaming iOS. Les prérequis de l'appareil diffèrent (iOS 18 et un appareil compatible Apple Intelligence). Notre guide sur Apple Intelligence dans une app Capacitor traite cet aspect.

En test

  • Utilisez un vrai téléphone compatible. Les émulateurs ne fournissent pas Gemini Nano à AICore.
  • Loggez le setModel message de rejet. Il vous indique précisément le statut rapporté par AICore.
  • Sur un appareil nouvellement configuré ou réinitialisé, attendez qu'AICore termine sa configuration initiale en ligne, puis réessayez.
  • Testez vos prompts sur la version Nano la plus basse que vous supportez. Des prompts courts et explicites sont plus stables d'une version à l'autre.

Troubleshooting

« Gemini Nano est indisponible sur cet appareil ». L'appareil ne figure pas sur la liste de Google, le bootloader est déverrouillé ou AICore n'est pas encore configuré.

« Gemini Nano est téléchargeable mais non téléchargé ». L’appareil est compatible, mais le modèle n’est pas présent. Proposez le repli sur Gemma ou réessayez plus tard.

« Session de chat introuvable ». Vous avez appelé sendMessage avec un chat créé avant un nouveau setModel. Le chargement d’un modèl’efface les chats existants, créez donc un nouveau chat.

« Model not ready ». setModel a échoué ou n’a pas été appelé avant createChat.

La sortie s’interrompt en pleine phrase. Vous avez atteint la limite de sortie. Demandez une réponse plus courte ou divisez la tâche.

Erreurs lorsque l’app passe en arrière-plan. L’inférence est réservée au premier plan. Annulez l’état de l’UI en pause et laissez l’utilisateur réessayer.

Confidentialité et validation par les stores

Avec Gemini Nano, les prompts et les réponses restent sur l'appareil, ce qui simplifie votre formulaire de sécurité des données. Les conditions d'utilisation de ML Kit de Google mentionnent encore le traitement des métriques : décrivez donc l'usage de l'IA sur l'appareil dans votre politique de confidentialité. Si vous ajoutez le fallback Gemma, le modèl’est téléchargé depuis Hugging Face : mentionnez aussi cette requête réseau.

Les prompts et les textes de l'interface des fonctionnalités d'IA changent souvent. Si vous devez les ajuster après la release, les live updates Capgo vous permet de déployer de nouveaux code web sans attendre la validation des stores. Pour une vision globale de l'IA dans les apps hybrides, lisez pourquoi Capacitor convient bien aux apps mobiles d'IA.

Récapitulatif

Gemini Nano offre aux apps Capacitor une génération de texte gratuite, privée et hors ligne sur les téléphones Android compatibles. Chargez-l’avec setModel({ path: 'Gemini Nano' }), diffusez via textFromAi, gardez des prompts et des sorties courts, respectez les règles de premier plan et de quota, et prévoyez un fallback Gemma ou cloud pour les nombreux appareils qui ne l'ont pas.

Live updates pour les apps Capacitor

Lorsqu'un bug de la couche web est en ligne, déployez le correctif via Capgo au lieu d'attendre des jours l'approbation des stores. Les utilisateurs reçoivent la mise à jour en arrière-plan, tandis que les changements natifs suivent le circuit de validation habituel.

Les derniers articles du blog

Capgo vous offre les meilleures informations pour créer une application mobile vraiment professionnelle.