RAICODE
ProcessusProjetsBlogOffresClientsContact
development

Intégrer l'IA dans Votre Application Web : Guide Pratique avec l'API OpenAI

Tutoriel complet pour ajouter des fonctionnalités IA à vos applications : chatbots, génération de contenu, analyse de texte. Exemples avec Next.js et l'API OpenAI.

Mustapha Hamadi
Développeur Full-Stack
7 décembre 2025
15 min read
Intégrer l'IA dans Votre Application Web : Guide Pratique avec l'API OpenAI
#Intelligence Artificielle#OpenAI#Next.js
Partager :

title: "Intégrer l'IA dans Votre Application Web : Guide Pratique avec l'API OpenAI" description: "Tutoriel complet pour ajouter des fonctionnalités IA à vos applications : chatbots, génération de contenu, analyse de texte. Exemples avec Next.js et l'API OpenAI." date: "2025-12-07" author: name: "Mustapha Hamadi" role: "Développeur Full-Stack" image: "/avatar.jpg" tags: ["Intelligence Artificielle", "OpenAI", "Next.js"] category: "development" image: "/blog/integrer-ia-application-web-openai-guide-hero.png" ogImage: "/blog/integrer-ia-application-web-openai-guide-hero.png" featured: false published: true keywords: ["OpenAI API", "intelligence artificielle", "chatbot", "GPT-4", "Next.js IA", "génération de contenu", "NLP", "machine learning", "API REST", "streaming", "embeddings", "fonction calling"]

Intégrer l'IA dans Votre Application Web : Guide Pratique avec l'API OpenAI

L'intelligence artificielle n'est plus réservée aux géants de la tech. Avec les APIs modernes comme OpenAI, n'importe quel développeur peut intégrer des fonctionnalités IA sophistiquées dans ses applications. Ce guide vous montre comment ajouter des capacités d'IA à votre application Next.js, étape par étape.

Pourquoi Intégrer l'IA dans Vos Applications ?

Cas d'Usage Concrets

L'IA peut transformer l'expérience utilisateur de nombreuses façons :

Support client intelligent

  • Chatbots capables de comprendre le contexte
  • Réponses automatiques personnalisées
  • Escalade intelligente vers les agents humains

Création de contenu

  • Génération de descriptions produits
  • Rédaction d'emails personnalisés
  • Résumés automatiques de documents

Analyse et insights

  • Analyse de sentiment des avis clients
  • Classification automatique de tickets
  • Extraction d'informations clés

Productivité utilisateur

  • Complétion automatique de formulaires
  • Suggestions intelligentes
  • Recherche sémantique

Configuration Initiale

Créer un Compte OpenAI

  1. Rendez-vous sur platform.openai.com
  2. Créez un compte ou connectez-vous
  3. Générez une clé API dans Settings > API Keys
  4. Configurez un budget mensuel pour éviter les surprises

Installation des Dépendances

# SDK officiel OpenAI
npm install openai

# Pour le streaming côté client
npm install ai

# Variables d'environnement
npm install dotenv

Configuration Sécurisée

# .env.local (ne jamais commiter ce fichier)
OPENAI_API_KEY=sk-votre-cle-api-ici
// lib/openai.ts
import OpenAI from 'openai';

if (!process.env.OPENAI_API_KEY) {
  throw new Error('OPENAI_API_KEY manquante dans les variables d\'environnement');
}

export const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
});

Créer un Chatbot Intelligent

Architecture de Base

app/
├── api/
│   └── chat/
│       └── route.ts      # API endpoint
├── components/
│   ├── chat-interface.tsx
│   └── message-bubble.tsx
└── lib/
    └── openai.ts

API Route avec Streaming

Le streaming permet d'afficher les réponses en temps réel, améliorant considérablement l'expérience utilisateur.

// app/api/chat/route.ts
import { openai } from '@/lib/openai';
import { OpenAIStream, StreamingTextResponse } from 'ai';

export const runtime = 'edge';

export async function POST(req: Request) {
  try {
    const { messages, systemPrompt } = await req.json();

    // Validation des entrées
    if (!messages || !Array.isArray(messages)) {
      return new Response(
        JSON.stringify({ error: 'Messages invalides' }),
        { status: 400 }
      );
    }

    // Appel à l'API OpenAI avec streaming
    const response = await openai.chat.completions.create({
      model: 'gpt-4-turbo-preview',
      stream: true,
      messages: [
        {
          role: 'system',
          content: systemPrompt || `Tu es un assistant utile et professionnel.
            Tu réponds en français de manière concise et précise.
            Si tu ne connais pas la réponse, dis-le honnêtement.`,
        },
        ...messages,
      ],
      temperature: 0.7,
      max_tokens: 1000,
    });

    // Transformer le stream pour le client
    const stream = OpenAIStream(response);
    return new StreamingTextResponse(stream);

  } catch (error) {
    console.error('Erreur API Chat:', error);
    return new Response(
      JSON.stringify({ error: 'Erreur interne du serveur' }),
      { status: 500 }
    );
  }
}

Interface de Chat React

// components/chat-interface.tsx
'use client';

import { useChat } from 'ai/react';
import { useState, useRef, useEffect } from 'react';
import { Send, Loader2, Bot, User } from 'lucide-react';

export function ChatInterface() {
  const messagesEndRef = useRef<HTMLDivElement>(null);

  const {
    messages,
    input,
    handleInputChange,
    handleSubmit,
    isLoading,
    error,
  } = useChat({
    api: '/api/chat',
    onError: (error) => {
      console.error('Erreur chat:', error);
    },
  });

  // Auto-scroll vers le dernier message
  useEffect(() => {
    messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
  }, [messages]);

  return (
    <div className="flex flex-col h-[600px] max-w-2xl mx-auto
                    bg-white rounded-xl shadow-lg overflow-hidden">
      {/* En-tête */}
      <div className="bg-blue-600 text-white px-6 py-4">
        <div className="flex items-center gap-3">
          <Bot className="w-8 h-8" />
          <div>
            <h2 className="font-semibold">Assistant IA</h2>
            <p className="text-sm text-blue-100">
              Posez-moi vos questions
            </p>
          </div>
        </div>
      </div>

      {/* Zone de messages */}
      <div className="flex-1 overflow-y-auto p-4 space-y-4">
        {messages.length === 0 && (
          <div className="text-center text-gray-500 mt-8">
            <Bot className="w-12 h-12 mx-auto mb-4 text-gray-300" />
            <p>Commencez une conversation en posant une question.</p>
          </div>
        )}

        {messages.map((message) => (
          <div
            key={message.id}
            className={`flex gap-3 ${
              message.role === 'user' ? 'justify-end' : 'justify-start'
            }`}
          >
            {message.role === 'assistant' && (
              <div className="w-8 h-8 bg-blue-100 rounded-full
                              flex items-center justify-center flex-shrink-0">
                <Bot className="w-5 h-5 text-blue-600" />
              </div>
            )}

            <div
              className={`max-w-[80%] px-4 py-3 rounded-2xl ${
                message.role === 'user'
                  ? 'bg-blue-600 text-white rounded-br-md'
                  : 'bg-gray-100 text-gray-800 rounded-bl-md'
              }`}
            >
              <p className="whitespace-pre-wrap">{message.content}</p>
            </div>

            {message.role === 'user' && (
              <div className="w-8 h-8 bg-gray-200 rounded-full
                              flex items-center justify-center flex-shrink-0">
                <User className="w-5 h-5 text-gray-600" />
              </div>
            )}
          </div>
        ))}

        {isLoading && (
          <div className="flex gap-3">
            <div className="w-8 h-8 bg-blue-100 rounded-full
                            flex items-center justify-center">
              <Bot className="w-5 h-5 text-blue-600" />
            </div>
            <div className="bg-gray-100 px-4 py-3 rounded-2xl rounded-bl-md">
              <Loader2 className="w-5 h-5 animate-spin text-gray-400" />
            </div>
          </div>
        )}

        {error && (
          <div className="bg-red-50 text-red-600 px-4 py-3 rounded-lg">
            Une erreur s'est produite. Veuillez réessayer.
          </div>
        )}

        <div ref={messagesEndRef} />
      </div>

      {/* Zone de saisie */}
      <form onSubmit={handleSubmit} className="border-t p-4">
        <div className="flex gap-2">
          <input
            type="text"
            value={input}
            onChange={handleInputChange}
            placeholder="Écrivez votre message..."
            className="flex-1 px-4 py-3 border rounded-lg
                       focus:outline-none focus:ring-2 focus:ring-blue-500"
            disabled={isLoading}
          />
          <button
            type="submit"
            disabled={isLoading || !input.trim()}
            className="bg-blue-600 text-white px-4 py-3 rounded-lg
                       hover:bg-blue-700 disabled:opacity-50
                       disabled:cursor-not-allowed transition-colors"
          >
            <Send className="w-5 h-5" />
          </button>
        </div>
      </form>
    </div>
  );
}

Génération de Contenu

API pour Générer du Texte

// app/api/generate/route.ts
import { openai } from '@/lib/openai';
import { NextRequest, NextResponse } from 'next/server';
import { z } from 'zod';

const generateSchema = z.object({
  type: z.enum(['product', 'email', 'summary', 'blog']),
  context: z.string().min(10),
  tone: z.enum(['professional', 'casual', 'creative']).optional(),
  length: z.enum(['short', 'medium', 'long']).optional(),
});

const prompts = {
  product: (context: string, tone: string) => `
    Génère une description produit ${tone} pour : ${context}
    - Maximum 150 mots
    - Mets en avant les bénéfices
    - Inclus un appel à l'action
  `,
  email: (context: string, tone: string) => `
    Rédige un email ${tone} pour : ${context}
    - Objet accrocheur
    - Corps concis et clair
    - Signature professionnelle
  `,
  summary: (context: string) => `
    Résume ce texte en conservant les points essentiels :
    ${context}
    - Maximum 100 mots
    - Bullet points pour la clarté
  `,
  blog: (context: string, tone: string) => `
    Écris une introduction de blog ${tone} sur : ${context}
    - 2-3 paragraphes engageants
    - Hook accrocheur en première phrase
    - Annonce ce que le lecteur va apprendre
  `,
};

export async function POST(req: NextRequest) {
  try {
    const body = await req.json();
    const { type, context, tone = 'professional', length = 'medium' } =
      generateSchema.parse(body);

    const maxTokens = {
      short: 150,
      medium: 300,
      long: 500,
    };

    const prompt = prompts[type](context, tone);

    const response = await openai.chat.completions.create({
      model: 'gpt-4-turbo-preview',
      messages: [
        {
          role: 'system',
          content: 'Tu es un rédacteur professionnel français. Tu génères du contenu de haute qualité, engageant et adapté au contexte.',
        },
        {
          role: 'user',
          content: prompt,
        },
      ],
      temperature: 0.8,
      max_tokens: maxTokens[length],
    });

    const generatedContent = response.choices[0]?.message?.content;

    return NextResponse.json({
      content: generatedContent,
      usage: response.usage,
    });

  } catch (error) {
    if (error instanceof z.ZodError) {
      return NextResponse.json(
        { error: 'Paramètres invalides', details: error.errors },
        { status: 400 }
      );
    }

    console.error('Erreur génération:', error);
    return NextResponse.json(
      { error: 'Erreur lors de la génération' },
      { status: 500 }
    );
  }
}

Composant de Génération de Contenu

// components/content-generator.tsx
'use client';

import { useState } from 'react';
import { Sparkles, Copy, Check, Loader2 } from 'lucide-react';

type ContentType = 'product' | 'email' | 'summary' | 'blog';

export function ContentGenerator() {
  const [type, setType] = useState<ContentType>('product');
  const [context, setContext] = useState('');
  const [tone, setTone] = useState('professional');
  const [result, setResult] = useState('');
  const [isLoading, setIsLoading] = useState(false);
  const [copied, setCopied] = useState(false);

  const handleGenerate = async () => {
    if (!context.trim()) return;

    setIsLoading(true);
    try {
      const response = await fetch('/api/generate', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ type, context, tone }),
      });

      const data = await response.json();

      if (data.error) {
        throw new Error(data.error);
      }

      setResult(data.content);
    } catch (error) {
      console.error('Erreur:', error);
      setResult('Une erreur s\'est produite. Veuillez réessayer.');
    } finally {
      setIsLoading(false);
    }
  };

  const copyToClipboard = async () => {
    await navigator.clipboard.writeText(result);
    setCopied(true);
    setTimeout(() => setCopied(false), 2000);
  };

  return (
    <div className="max-w-2xl mx-auto p-6 bg-white rounded-xl shadow-lg">
      <h2 className="text-2xl font-bold mb-6 flex items-center gap-2">
        <Sparkles className="w-6 h-6 text-yellow-500" />
        Générateur de Contenu IA
      </h2>

      <div className="space-y-4">
        {/* Type de contenu */}
        <div>
          <label className="block text-sm font-medium mb-2">
            Type de contenu
          </label>
          <div className="grid grid-cols-4 gap-2">
            {(['product', 'email', 'summary', 'blog'] as const).map((t) => (
              <button
                key={t}
                onClick={() => setType(t)}
                className={`px-4 py-2 rounded-lg text-sm font-medium
                           transition-colors ${
                  type === t
                    ? 'bg-blue-600 text-white'
                    : 'bg-gray-100 hover:bg-gray-200'
                }`}
              >
                {t === 'product' && 'Produit'}
                {t === 'email' && 'Email'}
                {t === 'summary' && 'Résumé'}
                {t === 'blog' && 'Blog'}
              </button>
            ))}
          </div>
        </div>

        {/* Ton */}
        <div>
          <label className="block text-sm font-medium mb-2">Ton</label>
          <select
            value={tone}
            onChange={(e) => setTone(e.target.value)}
            className="w-full px-4 py-2 border rounded-lg"
          >
            <option value="professional">Professionnel</option>
            <option value="casual">Décontracté</option>
            <option value="creative">Créatif</option>
          </select>
        </div>

        {/* Contexte */}
        <div>
          <label className="block text-sm font-medium mb-2">
            Décrivez ce que vous voulez générer
          </label>
          <textarea
            value={context}
            onChange={(e) => setContext(e.target.value)}
            placeholder="Ex: Un logiciel de gestion de projet pour les PME avec suivi du temps et facturation intégrée..."
            rows={4}
            className="w-full px-4 py-3 border rounded-lg resize-none"
          />
        </div>

        {/* Bouton générer */}
        <button
          onClick={handleGenerate}
          disabled={isLoading || !context.trim()}
          className="w-full bg-blue-600 text-white py-3 rounded-lg
                     font-semibold hover:bg-blue-700 disabled:opacity-50
                     flex items-center justify-center gap-2"
        >
          {isLoading ? (
            <>
              <Loader2 className="w-5 h-5 animate-spin" />
              Génération en cours...
            </>
          ) : (
            <>
              <Sparkles className="w-5 h-5" />
              Générer
            </>
          )}
        </button>

        {/* Résultat */}
        {result && (
          <div className="relative bg-gray-50 p-4 rounded-lg">
            <button
              onClick={copyToClipboard}
              className="absolute top-2 right-2 p-2 hover:bg-gray-200
                         rounded-lg transition-colors"
            >
              {copied ? (
                <Check className="w-5 h-5 text-green-500" />
              ) : (
                <Copy className="w-5 h-5 text-gray-500" />
              )}
            </button>
            <p className="whitespace-pre-wrap pr-10">{result}</p>
          </div>
        )}
      </div>
    </div>
  );
}

Function Calling : Actions Automatisées

Définir des Fonctions pour l'IA

Le function calling permet à l'IA d'appeler des fonctions de votre application.

// lib/ai-functions.ts
import { openai } from './openai';

// Définition des fonctions disponibles
const functions = [
  {
    name: 'search_products',
    description: 'Recherche des produits dans le catalogue',
    parameters: {
      type: 'object',
      properties: {
        query: {
          type: 'string',
          description: 'Termes de recherche',
        },
        category: {
          type: 'string',
          enum: ['electronics', 'clothing', 'books', 'home'],
          description: 'Catégorie de produits',
        },
        maxPrice: {
          type: 'number',
          description: 'Prix maximum en euros',
        },
      },
      required: ['query'],
    },
  },
  {
    name: 'create_order',
    description: 'Crée une commande pour un produit',
    parameters: {
      type: 'object',
      properties: {
        productId: {
          type: 'string',
          description: 'ID du produit à commander',
        },
        quantity: {
          type: 'number',
          description: 'Quantité souhaitée',
        },
      },
      required: ['productId', 'quantity'],
    },
  },
  {
    name: 'get_order_status',
    description: 'Récupère le statut d\'une commande',
    parameters: {
      type: 'object',
      properties: {
        orderId: {
          type: 'string',
          description: 'Numéro de commande',
        },
      },
      required: ['orderId'],
    },
  },
];

// Implémentation des fonctions
async function searchProducts(params: {
  query: string;
  category?: string;
  maxPrice?: number;
}) {
  // Simulation - remplacer par votre logique réelle
  return [
    { id: 'prod_1', name: 'Laptop Pro', price: 999, category: 'electronics' },
    { id: 'prod_2', name: 'Écran 27"', price: 349, category: 'electronics' },
  ];
}

async function createOrder(params: { productId: string; quantity: number }) {
  // Simulation
  return {
    orderId: `ORD_${Date.now()}`,
    status: 'confirmed',
    estimatedDelivery: '2025-12-10',
  };
}

async function getOrderStatus(params: { orderId: string }) {
  // Simulation
  return {
    orderId: params.orderId,
    status: 'en_transit',
    location: 'Centre de distribution Paris',
  };
}

// Exécuter la fonction demandée par l'IA
export async function executeFunction(
  name: string,
  args: Record<string, unknown>
) {
  switch (name) {
    case 'search_products':
      return searchProducts(args as Parameters<typeof searchProducts>[0]);
    case 'create_order':
      return createOrder(args as Parameters<typeof createOrder>[0]);
    case 'get_order_status':
      return getOrderStatus(args as Parameters<typeof getOrderStatus>[0]);
    default:
      throw new Error(`Fonction inconnue: ${name}`);
  }
}

// Chat avec function calling
export async function chatWithFunctions(
  messages: Array<{ role: 'user' | 'assistant'; content: string }>
) {
  const response = await openai.chat.completions.create({
    model: 'gpt-4-turbo-preview',
    messages: [
      {
        role: 'system',
        content: `Tu es un assistant e-commerce. Tu aides les utilisateurs
                  à rechercher des produits, passer des commandes et suivre
                  leurs livraisons. Utilise les fonctions disponibles pour
                  répondre aux demandes.`,
      },
      ...messages,
    ],
    functions,
    function_call: 'auto',
  });

  const message = response.choices[0]?.message;

  // Si l'IA veut appeler une fonction
  if (message?.function_call) {
    const functionName = message.function_call.name;
    const functionArgs = JSON.parse(message.function_call.arguments);

    // Exécuter la fonction
    const functionResult = await executeFunction(functionName, functionArgs);

    // Renvoyer le résultat à l'IA pour formulation
    const followUp = await openai.chat.completions.create({
      model: 'gpt-4-turbo-preview',
      messages: [
        ...messages,
        message,
        {
          role: 'function',
          name: functionName,
          content: JSON.stringify(functionResult),
        },
      ],
    });

    return followUp.choices[0]?.message?.content;
  }

  return message?.content;
}

Embeddings et Recherche Sémantique

Créer des Embeddings

Les embeddings transforment du texte en vecteurs, permettant une recherche par similarité.

// lib/embeddings.ts
import { openai } from './openai';

export async function createEmbedding(text: string): Promise<number[]> {
  const response = await openai.embeddings.create({
    model: 'text-embedding-3-small',
    input: text,
  });

  return response.data[0].embedding;
}

// Similarité cosinus entre deux vecteurs
export function cosineSimilarity(a: number[], b: number[]): number {
  let dotProduct = 0;
  let normA = 0;
  let normB = 0;

  for (let i = 0; i < a.length; i++) {
    dotProduct += a[i] * b[i];
    normA += a[i] * a[i];
    normB += b[i] * b[i];
  }

  return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
}

// Recherche sémantique dans une base de documents
export async function semanticSearch(
  query: string,
  documents: Array<{ id: string; content: string; embedding: number[] }>,
  topK = 5
) {
  const queryEmbedding = await createEmbedding(query);

  const results = documents
    .map((doc) => ({
      ...doc,
      similarity: cosineSimilarity(queryEmbedding, doc.embedding),
    }))
    .sort((a, b) => b.similarity - a.similarity)
    .slice(0, topK);

  return results;
}

RAG (Retrieval-Augmented Generation)

Combinez la recherche sémantique avec la génération pour des réponses basées sur vos données.

// lib/rag.ts
import { openai } from './openai';
import { semanticSearch, createEmbedding } from './embeddings';

interface Document {
  id: string;
  title: string;
  content: string;
  embedding: number[];
}

export async function ragAnswer(
  question: string,
  documents: Document[]
): Promise<string> {
  // 1. Recherche des documents pertinents
  const relevantDocs = await semanticSearch(question, documents, 3);

  // 2. Construire le contexte
  const context = relevantDocs
    .map((doc) => `## ${doc.title}\n${doc.content}`)
    .join('\n\n');

  // 3. Générer la réponse avec le contexte
  const response = await openai.chat.completions.create({
    model: 'gpt-4-turbo-preview',
    messages: [
      {
        role: 'system',
        content: `Tu es un assistant expert. Réponds aux questions en te
                  basant UNIQUEMENT sur le contexte fourni. Si l'information
                  n'est pas dans le contexte, dis-le clairement.`,
      },
      {
        role: 'user',
        content: `Contexte:\n${context}\n\nQuestion: ${question}`,
      },
    ],
    temperature: 0.3, // Plus déterministe pour les réponses factuelles
  });

  return response.choices[0]?.message?.content ?? 'Réponse non disponible';
}

Gestion des Coûts et Optimisation

Estimer les Coûts

// lib/cost-estimator.ts
const PRICING = {
  'gpt-4-turbo-preview': { input: 0.01, output: 0.03 }, // par 1K tokens
  'gpt-3.5-turbo': { input: 0.0005, output: 0.0015 },
  'text-embedding-3-small': { input: 0.00002 },
};

export function estimateCost(
  model: keyof typeof PRICING,
  inputTokens: number,
  outputTokens: number = 0
): number {
  const pricing = PRICING[model];
  const inputCost = (inputTokens / 1000) * pricing.input;
  const outputCost = 'output' in pricing
    ? (outputTokens / 1000) * pricing.output
    : 0;

  return inputCost + outputCost;
}

// Middleware pour tracker les coûts
export function trackUsage(usage: { prompt_tokens: number; completion_tokens: number }) {
  const cost = estimateCost(
    'gpt-4-turbo-preview',
    usage.prompt_tokens,
    usage.completion_tokens
  );

  console.log(`Coût estimé: $${cost.toFixed(4)}`);
  // Enregistrer en base de données pour suivi
}

Stratégies d'Optimisation

// lib/optimized-ai.ts

// 1. Cache des réponses fréquentes
const responseCache = new Map<string, { response: string; timestamp: number }>();
const CACHE_TTL = 3600000; // 1 heure

export async function cachedCompletion(prompt: string): Promise<string> {
  const cached = responseCache.get(prompt);

  if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
    return cached.response;
  }

  const response = await generateCompletion(prompt);
  responseCache.set(prompt, { response, timestamp: Date.now() });

  return response;
}

// 2. Sélection du modèle selon la complexité
export function selectModel(taskComplexity: 'simple' | 'medium' | 'complex') {
  switch (taskComplexity) {
    case 'simple':
      return 'gpt-3.5-turbo'; // Rapide et économique
    case 'medium':
      return 'gpt-4-turbo-preview';
    case 'complex':
      return 'gpt-4-turbo-preview';
  }
}

// 3. Limiter la longueur des réponses
export async function conciseCompletion(prompt: string, maxWords: number = 100) {
  return openai.chat.completions.create({
    model: 'gpt-3.5-turbo',
    messages: [
      {
        role: 'system',
        content: `Réponds en maximum ${maxWords} mots. Sois concis.`,
      },
      { role: 'user', content: prompt },
    ],
    max_tokens: Math.ceil(maxWords * 1.5), // Marge pour la tokenisation
  });
}

Sécurité et Bonnes Pratiques

Validation des Entrées

// lib/input-validation.ts
import { z } from 'zod';

// Schéma de validation strict
const chatInputSchema = z.object({
  message: z
    .string()
    .min(1, 'Le message ne peut pas être vide')
    .max(4000, 'Message trop long')
    .refine(
      (msg) => !containsPromptInjection(msg),
      'Contenu non autorisé détecté'
    ),
});

// Détection basique d'injection de prompt
function containsPromptInjection(text: string): boolean {
  const patterns = [
    /ignore\s+(previous|above|all)\s+instructions/i,
    /you\s+are\s+now/i,
    /new\s+instructions?:/i,
    /system\s*:/i,
  ];

  return patterns.some((pattern) => pattern.test(text));
}

// Sanitization avant envoi à l'API
export function sanitizeInput(text: string): string {
  return text
    .trim()
    .replace(/\s+/g, ' ') // Normaliser les espaces
    .slice(0, 4000); // Limiter la longueur
}

Rate Limiting

// lib/rate-limit.ts
const rateLimit = new Map<string, { count: number; resetAt: number }>();

export function checkRateLimit(
  userId: string,
  limit: number = 10,
  windowMs: number = 60000
): boolean {
  const now = Date.now();
  const userLimit = rateLimit.get(userId);

  if (!userLimit || now > userLimit.resetAt) {
    rateLimit.set(userId, { count: 1, resetAt: now + windowMs });
    return true;
  }

  if (userLimit.count >= limit) {
    return false;
  }

  userLimit.count++;
  return true;
}

// Utilisation dans l'API
export async function POST(req: Request) {
  const userId = getUserId(req); // Votre logique d'authentification

  if (!checkRateLimit(userId, 20, 60000)) {
    return new Response(
      JSON.stringify({ error: 'Trop de requêtes. Réessayez dans une minute.' }),
      { status: 429 }
    );
  }

  // Continuer avec la requête...
}

Conclusion

L'intégration de l'IA dans vos applications web est désormais accessible à tout développeur. Les points essentiels à retenir :

Commencez simple : Un chatbot basique ou un générateur de contenu suffisent pour apporter de la valeur. Complexifiez progressivement.

Streaming obligatoire : Pour les réponses longues, le streaming améliore drastiquement l'expérience utilisateur.

Maîtrisez les coûts : Utilisez le cache, choisissez le bon modèle, et limitez les tokens pour contrôler vos dépenses.

Sécurisez tout : Validez les entrées, limitez les requêtes, et ne faites jamais confiance aux données utilisateur.

Itérez sur les prompts : La qualité de vos prompts détermine la qualité des réponses. Testez et affinez continuellement.

L'IA n'est pas une baguette magique, mais un outil puissant qui, bien utilisé, peut transformer l'expérience de vos utilisateurs.


Vous souhaitez intégrer l'IA dans votre application ? Contactez Raicode pour un accompagnement sur mesure.

Partager :

Prêt à lancer votre projet ?

Transformez vos idées en réalité avec un développeur passionné par la performance et le SEO. Discutons de votre projet dès aujourd'hui.

Demander un devis
Voir mes réalisations
Réponse < 48h
15+ projets livrés
100% satisfaction client

Table des matières

Articles similaires

De 0 à Production en 4 Heures : Speed-Run d'un Site E-commerce
development

De 0 à Production en 4 Heures : Speed-Run d'un Site E-commerce

8 décembre 2025
15 min read
Sécuriser une Application Next.js : Authentification et Bonnes Pratiques
development

Sécuriser une Application Next.js : Authentification et Bonnes Pratiques

7 décembre 2025
15 min read
Next.js 15 : App Router, Server Actions et les Nouvelles Fonctionnalités à Connaître
development

Next.js 15 : App Router, Server Actions et les Nouvelles Fonctionnalités à Connaître

5 décembre 2025
12 min read
RAICODE

Développeur Full-Stack spécialisé en Next.js & React.
Je crée des applications web performantes et sur mesure.

SERVICES

  • Sites Vitrines
  • Applications SaaS
  • E-commerce
  • API & Backend

NAVIGATION

  • Processus
  • Projets
  • Blog
  • Tarifs
  • Contact

LÉGAL

  • Mentions légales
  • Confidentialité
  • CGU
  • CGV

© 2025 Raicode. Tous droits réservés.

Créé parRaicode.
↑ Retour en haut