Créer des applications IA avec Google Gemini API et TypeScript

AI Bot
Par AI Bot ·

Chargement du lecteur de synthèse vocale...

Google Gemini 2.5 Pro est arrivé. Avec une fenêtre de contexte de 1 million de tokens, des capacités multimodales natives et des appels de fonctions intégrés, Gemini est une des API IA les plus puissantes disponibles aujourd'hui. Dans ce tutoriel, vous apprendrez à exploiter tout son potentiel avec TypeScript.

Ce que vous apprendrez

À la fin de ce tutoriel, vous serez capable de :

  • Configurer le SDK Google Generative AI dans un projet TypeScript
  • Générer du texte avec Gemini 2.5 Pro et Gemini 2.5 Flash
  • Traiter des images, des PDF et de l'audio avec des entrées multimodales
  • Implémenter le streaming de réponses en temps réel
  • Utiliser les appels de fonctions pour connecter Gemini à des outils externes
  • Extraire des données structurées avec un schéma JSON
  • Construire un assistant IA pratique avec historique de conversation

Prérequis

Avant de commencer, assurez-vous d'avoir :

  • Node.js 20+ installé (node --version)
  • Des connaissances en TypeScript (types, async/await, modules)
  • Une clé API Google AI Studio — obtenez-en une gratuitement sur aistudio.google.com
  • Un éditeur de code — VS Code ou Cursor recommandé
  • Une compréhension basique des API REST et de la programmation asynchrone

Étape 1 : Configuration du projet

Créez un nouveau projet TypeScript et installez le SDK Google Generative AI :

mkdir gemini-ai-app && cd gemini-ai-app
npm init -y
npm install @google/generative-ai
npm install -D typescript @types/node tsx

Initialisez TypeScript :

npx tsc --init --target ES2022 --module NodeNext --moduleResolution NodeNext --outDir dist --rootDir src --strict

Créez la structure du projet :

mkdir src
touch src/index.ts .env

Ajoutez votre clé API dans .env :

GEMINI_API_KEY=your_api_key_here

Mettez à jour les scripts de package.json :

{
  "scripts": {
    "dev": "tsx watch src/index.ts",
    "build": "tsc",
    "start": "node dist/index.js"
  }
}

Étape 2 : Votre première génération de texte

Commençons par un exemple simple de génération de texte. Créez src/index.ts :

import { GoogleGenerativeAI } from "@google/generative-ai";
 
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY!);
 
async function generateText() {
  const model = genAI.getGenerativeModel({
    model: "gemini-2.5-pro",
  });
 
  const result = await model.generateContent(
    "Expliquez l'informatique quantique en 3 phrases pour un développeur logiciel."
  );
 
  console.log(result.response.text());
}
 
generateText();

Exécutez-le :

GEMINI_API_KEY=your_key tsx src/index.ts

Vous devriez voir une explication concise de l'informatique quantique. La méthode generateContent envoie une requête unique et retourne la réponse complète.

Comprendre l'objet Response

La réponse contient plus que du texte :

async function inspectResponse() {
  const model = genAI.getGenerativeModel({ model: "gemini-2.5-pro" });
 
  const result = await model.generateContent("Bonjour, Gemini !");
  const response = result.response;
 
  console.log("Texte:", response.text());
  console.log("Utilisation:", response.usageMetadata);
  // { promptTokenCount: 4, candidatesTokenCount: 12, totalTokenCount: 16 }
}

Le champ usageMetadata vous aide à suivre la consommation de tokens pour la gestion des coûts.


Étape 3 : Choisir le bon modèle

Gemini propose plusieurs modèles optimisés pour différents cas d'utilisation :

ModèleIdéal pourFenêtre de contexteVitesse
gemini-2.5-proRaisonnement complexe, codage, analyse1M tokensModérée
gemini-2.5-flashRéponses rapides, haut débit1M tokensRapide
gemini-2.5-flash-liteÉconomique, tâches simples1M tokensLa plus rapide
// Pour les analyses complexes
const pro = genAI.getGenerativeModel({ model: "gemini-2.5-pro" });
 
// Pour les applications nécessitant de la vitesse
const flash = genAI.getGenerativeModel({ model: "gemini-2.5-flash" });
 
// Pour les tâches simples à grand volume
const lite = genAI.getGenerativeModel({ model: "gemini-2.5-flash-lite" });

Conseil : Commencez avec gemini-2.5-flash pour le développement. Passez à pro uniquement quand vous avez besoin de ses capacités de raisonnement améliorées. Flash est nettement moins cher et plus rapide.


Étape 4 : Entrées multimodales — Images et PDF

L'une des fonctionnalités les plus puissantes de Gemini est sa compréhension multimodale native. Vous pouvez envoyer des images, des PDF, de l'audio et de la vidéo avec du texte.

Analyser une image

import { GoogleGenerativeAI } from "@google/generative-ai";
import * as fs from "fs";
import * as path from "path";
 
async function analyzeImage(imagePath: string) {
  const model = genAI.getGenerativeModel({ model: "gemini-2.5-flash" });
 
  const imageData = fs.readFileSync(imagePath);
  const base64Image = imageData.toString("base64");
  const mimeType = imagePath.endsWith(".png") ? "image/png" : "image/jpeg";
 
  const result = await model.generateContent([
    {
      inlineData: {
        mimeType,
        data: base64Image,
      },
    },
    "Décrivez cette image en détail. Quels objets, couleurs et scènes voyez-vous ?",
  ]);
 
  console.log(result.response.text());
}
 
analyzeImage("./sample-image.jpg");

Traiter un document PDF

async function analyzePDF(pdfPath: string) {
  const model = genAI.getGenerativeModel({ model: "gemini-2.5-pro" });
 
  const pdfData = fs.readFileSync(pdfPath);
  const base64PDF = pdfData.toString("base64");
 
  const result = await model.generateContent([
    {
      inlineData: {
        mimeType: "application/pdf",
        data: base64PDF,
      },
    },
    "Résumez les points clés de ce document. Listez les sujets principaux et les actions à entreprendre.",
  ]);
 
  console.log(result.response.text());
}

Comparer plusieurs images

async function compareImages(image1Path: string, image2Path: string) {
  const model = genAI.getGenerativeModel({ model: "gemini-2.5-flash" });
 
  const image1 = fs.readFileSync(image1Path).toString("base64");
  const image2 = fs.readFileSync(image2Path).toString("base64");
 
  const result = await model.generateContent([
    { inlineData: { mimeType: "image/jpeg", data: image1 } },
    { inlineData: { mimeType: "image/jpeg", data: image2 } },
    "Comparez ces deux images. Quelles sont les différences et les similitudes ?",
  ]);
 
  console.log(result.response.text());
}

Étape 5 : Streaming des réponses

Pour une meilleure expérience utilisateur, diffusez les réponses token par token au lieu d'attendre la réponse complète :

async function streamResponse(prompt: string) {
  const model = genAI.getGenerativeModel({ model: "gemini-2.5-flash" });
 
  const result = await model.generateContentStream(prompt);
 
  process.stdout.write("Gemini: ");
 
  for await (const chunk of result.stream) {
    const text = chunk.text();
    process.stdout.write(text);
  }
 
  console.log("\n");
 
  // Accéder à la réponse agrégée après le streaming
  const aggregated = await result.response;
  console.log("Total tokens:", aggregated.usageMetadata?.totalTokenCount);
}
 
streamResponse("Écrivez un court poème sur TypeScript.");

Streaming dans un serveur web

Voici comment intégrer le streaming avec un serveur HTTP simple :

import { createServer } from "http";
 
const server = createServer(async (req, res) => {
  if (req.method === "POST" && req.url === "/chat") {
    const body = await getBody(req);
    const { message } = JSON.parse(body);
 
    const model = genAI.getGenerativeModel({ model: "gemini-2.5-flash" });
    const result = await model.generateContentStream(message);
 
    res.writeHead(200, {
      "Content-Type": "text/event-stream",
      "Cache-Control": "no-cache",
      Connection: "keep-alive",
    });
 
    for await (const chunk of result.stream) {
      res.write(`data: ${JSON.stringify({ text: chunk.text() })}\n\n`);
    }
 
    res.write("data: [DONE]\n\n");
    res.end();
  }
});
 
server.listen(3000, () => console.log("Serveur en cours sur le port 3000"));
 
function getBody(req: any): Promise<string> {
  return new Promise((resolve) => {
    let body = "";
    req.on("data", (chunk: string) => (body += chunk));
    req.on("end", () => resolve(body));
  });
}

Étape 6 : Appels de fonctions

Les appels de fonctions permettent à Gemini d'invoquer vos fonctions TypeScript pour récupérer des données en temps réel, interagir avec des API ou effectuer des calculs.

Définir les outils

import {
  GoogleGenerativeAI,
  FunctionDeclarationSchemaType,
} from "@google/generative-ai";
 
const tools = [
  {
    functionDeclarations: [
      {
        name: "getWeather",
        description:
          "Obtenir la météo actuelle pour un lieu spécifique",
        parameters: {
          type: FunctionDeclarationSchemaType.OBJECT,
          properties: {
            location: {
              type: FunctionDeclarationSchemaType.STRING,
              description: "Nom de la ville, ex: 'Tunis' ou 'Paris'",
            },
            unit: {
              type: FunctionDeclarationSchemaType.STRING,
              enum: ["celsius", "fahrenheit"],
              description: "Unité de température",
            },
          },
          required: ["location"],
        },
      },
      {
        name: "searchProducts",
        description: "Rechercher des produits dans le catalogue",
        parameters: {
          type: FunctionDeclarationSchemaType.OBJECT,
          properties: {
            query: {
              type: FunctionDeclarationSchemaType.STRING,
              description: "Requête de recherche",
            },
            maxPrice: {
              type: FunctionDeclarationSchemaType.NUMBER,
              description: "Filtre de prix maximum",
            },
          },
          required: ["query"],
        },
      },
    ],
  },
];

Gérer les appels de fonctions

// Implémentations de fonctions simulées
function getWeather(location: string, unit = "celsius") {
  const mockData: Record<string, { temp: number; condition: string }> = {
    tunis: { temp: 24, condition: "Ensoleillé" },
    paris: { temp: 15, condition: "Nuageux" },
    tokyo: { temp: 20, condition: "Dégagé" },
  };
 
  const data = mockData[location.toLowerCase()] || {
    temp: 20,
    condition: "Inconnu",
  };
 
  return {
    location,
    temperature: data.temp,
    unit,
    condition: data.condition,
  };
}
 
function searchProducts(query: string, maxPrice?: number) {
  return {
    results: [
      { name: `${query} Pro`, price: 99.99, rating: 4.5 },
      { name: `${query} Lite`, price: 49.99, rating: 4.2 },
    ].filter((p) => !maxPrice || p.price <= maxPrice),
  };
}
 
async function chatWithTools(userMessage: string) {
  const model = genAI.getGenerativeModel({
    model: "gemini-2.5-flash",
    tools,
  });
 
  const chat = model.startChat();
  const result = await chat.sendMessage(userMessage);
 
  const response = result.response;
  const functionCalls = response.functionCalls();
 
  if (functionCalls && functionCalls.length > 0) {
    const functionResponses = functionCalls.map((call) => {
      let result;
      switch (call.name) {
        case "getWeather":
          result = getWeather(
            call.args.location as string,
            call.args.unit as string
          );
          break;
        case "searchProducts":
          result = searchProducts(
            call.args.query as string,
            call.args.maxPrice as number
          );
          break;
        default:
          result = { error: "Fonction inconnue" };
      }
 
      return {
        functionResponse: {
          name: call.name,
          response: result,
        },
      };
    });
 
    // Renvoyer les résultats des fonctions à Gemini
    const finalResult = await chat.sendMessage(functionResponses);
    console.log(finalResult.response.text());
  } else {
    console.log(response.text());
  }
}
 
chatWithTools("Quelle est la météo à Tunis et trouvez-moi des options de laptop à moins de 80$ ?");

Gemini appellera les deux fonctions en parallèle et synthétisera les résultats en une réponse en langage naturel.


Étape 7 : Sorties structurées avec schéma JSON

Forcez Gemini à retourner des données dans une structure JSON spécifique — idéal pour construire des pipelines de données fiables :

async function extractStructuredData(text: string) {
  const model = genAI.getGenerativeModel({
    model: "gemini-2.5-flash",
    generationConfig: {
      responseMimeType: "application/json",
      responseSchema: {
        type: FunctionDeclarationSchemaType.OBJECT,
        properties: {
          sentiment: {
            type: FunctionDeclarationSchemaType.STRING,
            enum: ["positive", "negative", "neutral"],
          },
          confidence: {
            type: FunctionDeclarationSchemaType.NUMBER,
          },
          topics: {
            type: FunctionDeclarationSchemaType.ARRAY,
            items: {
              type: FunctionDeclarationSchemaType.STRING,
            },
          },
          summary: {
            type: FunctionDeclarationSchemaType.STRING,
          },
        },
        required: ["sentiment", "confidence", "topics", "summary"],
      },
    },
  });
 
  const result = await model.generateContent(
    `Analysez le texte suivant :\n\n${text}`
  );
 
  const data = JSON.parse(result.response.text());
  return data;
}
 
// Utilisation
const analysis = await extractStructuredData(
  "La nouvelle API Gemini est incroyable ! La documentation est claire, " +
  "le SDK TypeScript est bien conçu, et les tarifs sont très compétitifs. " +
  "Cependant, les limites de débit peuvent être préoccupantes pour les applications à fort trafic."
);
 
console.log(analysis);
// {
//   sentiment: "positive",
//   confidence: 0.85,
//   topics: ["API", "documentation", "SDK", "tarification", "limites de débit"],
//   summary: "Avis positif sur Gemini API avec une préoccupation mineure sur les limites de débit"
// }

Étape 8 : Construire un assistant IA conversationnel

Rassemblons tout dans un assistant IA pratique avec historique de conversation, instructions système et paramètres de sécurité :

import {
  GoogleGenerativeAI,
  HarmCategory,
  HarmBlockThreshold,
} from "@google/generative-ai";
import * as readline from "readline";
 
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY!);
 
async function startAssistant() {
  const model = genAI.getGenerativeModel({
    model: "gemini-2.5-flash",
    systemInstruction: `Vous êtes un assistant de programmation spécialisé en TypeScript et Node.js.
    Vous fournissez des réponses concises et pratiques avec des exemples de code quand c'est approprié.
    Vous considérez toujours les meilleures pratiques et les implications de sécurité.
    Si vous n'êtes pas sûr de quelque chose, dites-le plutôt que de deviner.`,
    safetySettings: [
      {
        category: HarmCategory.HARM_CATEGORY_HARASSMENT,
        threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE,
      },
      {
        category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
        threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE,
      },
    ],
    generationConfig: {
      temperature: 0.7,
      topP: 0.95,
      topK: 40,
      maxOutputTokens: 2048,
    },
  });
 
  const chat = model.startChat({
    history: [],
  });
 
  const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
  });
 
  console.log("Assistant IA prêt ! Tapez 'exit' pour quitter.\n");
 
  const askQuestion = () => {
    rl.question("Vous: ", async (input) => {
      const trimmed = input.trim();
      if (trimmed.toLowerCase() === "exit") {
        console.log("Au revoir !");
        rl.close();
        return;
      }
 
      try {
        const result = await chat.sendMessageStream(trimmed);
 
        process.stdout.write("Assistant: ");
        for await (const chunk of result.stream) {
          process.stdout.write(chunk.text());
        }
        console.log("\n");
      } catch (error: any) {
        console.error("Erreur:", error.message);
      }
 
      askQuestion();
    });
  };
 
  askQuestion();
}
 
startAssistant();

Explication de la configuration de génération

ParamètrePar défautDescription
temperature1.0Contrôle le hasard. Plus bas = plus concentré, plus haut = plus créatif
topP0.95Échantillonnage par noyau. Considère les tokens avec probabilité cumulative jusqu'à cette valeur
topK40Ne considère que les K tokens les plus probables à chaque étape
maxOutputTokensVariableNombre maximum de tokens à générer

Étape 9 : Gestion des erreurs et limitation de débit

Les applications en production nécessitent une gestion robuste des erreurs :

import { GoogleGenerativeAI, GoogleGenerativeAIError } from "@google/generative-ai";
 
async function safeGenerate(prompt: string, retries = 3): Promise<string> {
  const model = genAI.getGenerativeModel({ model: "gemini-2.5-flash" });
 
  for (let attempt = 1; attempt <= retries; attempt++) {
    try {
      const result = await model.generateContent(prompt);
      return result.response.text();
    } catch (error: any) {
      const status = error?.status;
 
      if (status === 429) {
        // Limite de débit atteinte — backoff exponentiel
        const delay = Math.pow(2, attempt) * 1000;
        console.warn(
          `Limite de débit atteinte. Nouvelle tentative dans ${delay / 1000}s (tentative ${attempt}/${retries})`
        );
        await new Promise((r) => setTimeout(r, delay));
        continue;
      }
 
      if (status === 400) {
        console.error("Requête invalide — vérifiez votre prompt ou vos paramètres");
        throw error;
      }
 
      if (status === 403) {
        console.error("Clé API invalide ou quota dépassé");
        throw error;
      }
 
      if (attempt === retries) throw error;
 
      console.warn(`Erreur (tentative ${attempt}/${retries}):`, error.message);
      await new Promise((r) => setTimeout(r, 1000 * attempt));
    }
  }
 
  throw new Error("Nombre maximum de tentatives dépassé");
}

Bonnes pratiques pour les limites de débit

  1. Utilisez le backoff exponentiel — doublez le temps d'attente entre les tentatives
  2. Mettez les réponses en cache — stockez les résultats pour des prompts identiques
  3. Utilisez Flash pour le haut volume — il a des limites de débit plus élevées que Pro
  4. Groupez les requêtes — regroupez les prompts liés quand c'est possible

Étape 10 : Conseils pour la production

Configuration de l'environnement

// src/config.ts
interface GeminiConfig {
  apiKey: string;
  model: string;
  maxRetries: number;
  timeout: number;
}
 
export function getConfig(): GeminiConfig {
  const apiKey = process.env.GEMINI_API_KEY;
  if (!apiKey) {
    throw new Error("La variable d'environnement GEMINI_API_KEY est requise");
  }
 
  return {
    apiKey,
    model: process.env.GEMINI_MODEL || "gemini-2.5-flash",
    maxRetries: parseInt(process.env.GEMINI_MAX_RETRIES || "3", 10),
    timeout: parseInt(process.env.GEMINI_TIMEOUT || "30000", 10),
  };
}

Comptage des tokens

Avant d'envoyer de longs prompts, vérifiez le nombre de tokens :

async function countTokens(content: string) {
  const model = genAI.getGenerativeModel({ model: "gemini-2.5-flash" });
 
  const result = await model.countTokens(content);
  console.log(`Nombre de tokens: ${result.totalTokens}`);
 
  return result.totalTokens;
}

Estimation des coûts

function estimateCost(
  inputTokens: number,
  outputTokens: number,
  model: "pro" | "flash" | "flash-lite"
) {
  // Prix approximatifs par million de tokens (vérifiez les prix actuels)
  const pricing = {
    pro: { input: 1.25, output: 10.0 },
    flash: { input: 0.15, output: 0.6 },
    "flash-lite": { input: 0.075, output: 0.3 },
  };
 
  const p = pricing[model];
  const inputCost = (inputTokens / 1_000_000) * p.input;
  const outputCost = (outputTokens / 1_000_000) * p.output;
 
  return {
    inputCost: `$${inputCost.toFixed(4)}`,
    outputCost: `$${outputCost.toFixed(4)}`,
    totalCost: `$${(inputCost + outputCost).toFixed(4)}`,
  };
}

Dépannage

Problèmes courants

"API key not valid" — Clé API invalide

  • Vérifiez votre clé sur aistudio.google.com
  • Assurez-vous que l'API Generative AI est activée dans votre projet Google Cloud
  • Vérifiez que votre clé n'est pas restreinte à des API spécifiques

"Resource exhausted" — Erreurs 429

  • Vous avez atteint la limite de débit. Implémentez un backoff exponentiel
  • Envisagez de passer à un forfait payant pour des limites plus élevées
  • Utilisez gemini-2.5-flash qui a des limites de débit plus généreuses

"Content blocked by safety filters" — Contenu bloqué par les filtres de sécurité

  • Ajustez les seuils de safetySettings (mais soyez responsable)
  • Reformulez le prompt pour éviter de déclencher les filtres
  • Consultez les politiques d'utilisation de Google

Réponses vides

  • Le modèle a peut-être été bloqué par les filtres de sécurité sans retourner de texte
  • Vérifiez response.promptFeedback pour les raisons du blocage

Prochaines étapes

Maintenant que vous maîtrisez les fondamentaux de Gemini API, explorez ces sujets avancés :

  • Gemini avec LangChain.js — Construire des chaînes et des agents IA complexes
  • Vertex AI — Déploiement de niveau entreprise avec Google Cloud
  • Fine-tuning — Personnaliser les modèles Gemini pour votre domaine
  • Mise en cache du contexte — Réduire les coûts pour les fenêtres de contexte répétées
  • Ancrage avec Google Search — Enrichir les réponses avec des données web en temps réel

Conclusion

Vous avez construit une boîte à outils complète pour les applications IA avec Google Gemini API et TypeScript. De la simple génération de texte à l'analyse multimodale, le streaming, les appels de fonctions et les sorties structurées — vous disposez maintenant de tous les composants pour créer des applications IA sophistiquées.

La combinaison d'une fenêtre de contexte massive, de tarifs compétitifs et d'un support multimodal natif fait de Gemini API un excellent choix pour les applications IA en production. Commencez avec Flash pour la rapidité de développement, et passez à Pro quand vous avez besoin de capacités de raisonnement améliorées.


Vous voulez lire plus de tutoriels? Découvrez notre dernier tutoriel sur Utiliser les dictionnaires de prononciation avec le SDK ElevenLabs.

Discutez de votre projet avec nous

Nous sommes ici pour vous aider avec vos besoins en développement Web. Planifiez un appel pour discuter de votre projet et comment nous pouvons vous aider.

Trouvons les meilleures solutions pour vos besoins.

Articles connexes

Construire un Chatbot IA Local avec Ollama et Next.js : Guide Complet

Construisez un chatbot IA privé fonctionnant entièrement sur votre machine locale avec Ollama et Next.js. Ce tutoriel pratique couvre l'installation, le streaming des réponses, la sélection de modèles et le déploiement d'une interface de chat prête pour la production — le tout sans envoyer de données dans le cloud.

25 min read·