Comment créer son propre site de ChatBot tel que ChatGPT grâce à OpenAI et Vercel AI SDK

Bienvenue dans ce guide pratique qui vous montrera comment créer un chatbot en utilisant l'API OpenAI et le SDK Vercel AI. L'objectif de ce guide est de vous fournir une compréhension claire et concise de comment développer un chatbot fonctionnel. Nous allons utiliser l'API OpenAI, qui fournit l'accès à des modèles de langage tels que GPT-3, et le SDK Vercel AI, pour faciliter l'intégration de notre chatbot dans une application web.

Ce guide est adapté aussi bien aux développeurs expérimentés qu'aux débutants qui cherchent à comprendre le fonctionnement des chatbots. Il est conçu pour être un parcours d'apprentissage à votre rythme. Dans ce guide, nous allons voir comment utiliser les utilitaires pour créer un chat bot et une application de complétion de texte.

Guide : Chat Bot

Créer une application Next.js

Créez une application Next.js et installez ai et openai-edge. Nous préférons actuellement cette dernière bibliothèque openai-edge au SDK officiel d'OpenAI car le SDK officiel utilise axios qui n'est pas compatible avec les fonctions Vercel Edge.

pnpm dlx create-next-app my-ai-app
cd my-ai-app
pnpm install ai openai-edge
💡

Si vous avez des choix dans votre terminal, n'oubliez pas de valider TypeScript, TailWind et App Routeur. Vous pouvez laissez les autres paramètres par défaut.

Ajoutez votre clé API OpenAI à .env

Créez un fichier .env à la racine de votre projet et ajoutez votre clé API OpenAI :

OPENAI_API_KEY=xxxxxxxxx

Créer un gestionnaire de routes

Créer un gestionnaire de route Next.js qui utilise le Edge Runtime que nous utiliserons pour générer un achèvement de chat via OpenAI que nous renverrons ensuite à notre Next.js.

Vous allez devoir créer les dossiers ainsi que les fichiers. Pour cet exemple, nous allons créer un gestionnaire de route à app/api/chat/route.ts qui accepte une requête POST avec un tableau de chaînes de caractères pour les messages :

app/api/chat/route.ts

import { Configuration, OpenAIApi } from 'openai-edge'
import { OpenAIStream, StreamingTextResponse } from 'ai'
 
// Create an OpenAI API client (that's edge friendly!)
const config = new Configuration({
  apiKey: process.env.OPENAI_API_KEY
})
const openai = new OpenAIApi(config)
 
// IMPORTANT! Set the runtime to edge
export const runtime = 'edge'
 
export async function POST(req: Request) {
  // Extract the `messages` from the body of the request
  const { messages } = await req.json()
 
  // Ask OpenAI for a streaming chat completion given the prompt
  const response = await openai.createChatCompletion({
    model: 'gpt-3.5-turbo',
    stream: true,
    messages
  })
  // Convert the response into a friendly text-stream
  const stream = OpenAIStream(response)
  // Respond with the stream
  return new StreamingTextResponse(stream)
}
💡

Vercel AI SDK fournit deux aides utilitaires pour réaliser ce qui précède de manière transparente : Tout d'abord, nous transmettons la response en continu que nous recevons d'OpenAI à OpenAIStream. Cette méthode décode/extrait les jetons de texte dans la réponse et les réencode correctement pour une consommation simple. Nous pouvons ensuite passer ce nouveau flux directement à StreamingTextResponse. Il s'agit d'une autre classe utilitaire qui étend la classe normale Node/Edge Runtime Response avec les en-têtes par défaut que vous souhaitez probablement (indice : 'Content-Type' : 'text/plain ; charset=utf-8' est déjà défini pour vous).

Créer l'interface utilisateur

Créez un composant Client avec un formulaire que nous utiliserons pour recueillir le prompt de l'utilisateur et renvoyer l'achèvement à partir d'un flux. Par défaut, le crochet useChat utilisera le gestionnaire de route POST que nous avons créé plus haut (il utilise par défaut /api/chat). Vous pouvez surcharger ceci en passant un prop api à useChat({ api : '...'}).

app/page.tsx

'use client'
 
import { useChat } from 'ai/react'
 
export default function Chat() {
  const { messages, input, handleInputChange, handleSubmit } = useChat()
 
  return (
    <div className="mx-auto w-full max-w-md py-24 flex flex-col stretch">
      {messages.map(m => (
        <div key={m.id}>
          {m.role === 'user' ? 'User: ' : 'AI: '}
          {m.content}
        </div>
      ))}
 
      <form onSubmit={handleSubmit}>
        <label>
          Say something...
          <input
            className="fixed w-full max-w-md bottom-0 border border-gray-300 rounded mb-8 shadow-xl p-2"
            value={input}
            onChange={handleInputChange}
          />
        </label>
        <button type="submit">Send</button>
      </form>
    </div>
  )
}

Pour apprendre à personnaliser votre interface, consultez le site de TailWind CSS :

Tailwind CSS - Rapidly build modern websites without ever leaving your HTML.
Tailwind CSS is a utility-first CSS framework for rapidly building modern websites without ever leaving your HTML.

Utiliser votre ChatBot

D'abord, assurez-vous que Node.js est installé sur votre machine. C'est nécessaire pour exécuter votre application Next.js. Vous pouvez le télécharger depuis le site officiel de Node.js.

En supposant que vous avez suivi le guide correctement, voici les étapes que vous devez suivre pour lancer votre application :

  1. Ouvrez votre terminal ou invite de commande.
  2. Accédez au répertoire où se trouve votre my-ai-app. Par exemple, s'il se trouve dans le répertoire Documents, vous utiliseriez la commande :
cd Documents/my-ai-app

N'oubliez pas de remplacer Documents/my-ai-app par le chemin correct vers votre application.

  1. Une fois que vous êtes dans le bon répertoire, vous pouvez démarrer votre application Next.js en exécutant la commande suivante :
pnpm dev

Ou si vous avez utilisé npm au lieu de pnpm, utilisez :

npm run dev
  1. Votre application devrait maintenant être en cours d'exécution. Ouvrez un navigateur web et allez à localhost:3000 (ou l'adresse indiquée dans votre terminal). Vous devriez voir votre application en cours d'exécution.
  2. Si vous avez tout configuré correctement, votre chatbot devrait être fonctionnel sur votre page web. Vous pouvez le tester en envoyant un message à l'aide du champ de saisie de chat.
Interface du ChatBot

Pour mettre fin à l'exécution de votre application, retournez à votre terminal et interrompez le processus en appuyant sur les touches Ctrl+C.

Actuellement, votre application n'est accessible que localement sur votre ordinateur. Pour la rendre accessible à tous sur internet, vous pouvez opter pour l'hébergement de votre projet sur une plateforme comme Vercel.

Guide : Complétion de texte

Utiliser l'API de complétion

Comme dans l'exemple du Chat Bot ci-dessus, nous allons créer un Next.js Route Handler qui génère une complétion de texte via OpenAI que nous allons ensuite renvoyer à notre Next.js. Il accepte une requête POST avec une chaîne de prompt :

app/api/completion/route.ts

import { Configuration, OpenAIApi } from 'openai-edge'
import { OpenAIStream, StreamingTextResponse } from 'ai'
 
// Create an OpenAI API client (that's edge friendly!)
const config = new Configuration({
  apiKey: process.env.OPENAI_API_KEY
})
const openai = new OpenAIApi(config)
 
// IMPORTANT! Set the runtime to edge
export const runtime = 'edge'
 
export async function POST(req: Request) {
  // Extract the `prompt` from the body of the request
  const { prompt } = await req.json()
 
  // Ask OpenAI for a streaming completion given the prompt
  const response = await openai.createCompletion({
    model: 'text-davinci-003',
    stream: true,
    prompt
  })
 
  // Convert the response into a friendly text-stream
  const stream = OpenAIStream(response)
 
  // Respond with the stream
  return new StreamingTextResponse(stream)
}

Créer l'interface utilisateur

Nous pouvons utiliser le hook useCompletion pour faciliter le câblage de l'interface utilisateur. Par défaut, le crochet useCompletion utilisera le gestionnaire de route POST que nous avons créé ci-dessus (il utilise par défaut /api/completion). Vous pouvez surcharger ceci en passant un prop api à useCompletion({ api : '...'}).

app/page.tsx

'use client'
 
import { useCompletion } from 'ai/react'
 
export default function Completion() {
  const {
    completion,
    input,
    stop,
    isLoading,
    handleInputChange,
    handleSubmit
  } = useCompletion({
    api: '/api/completion'
  })
 
  return (
    <div className="mx-auto w-full max-w-md py-24 flex flex-col stretch">
      <form onSubmit={handleSubmit}>
        <label>
          Say something...
          <input
            className="fixed w-full max-w-md bottom-0 border border-gray-300 rounded mb-8 shadow-xl p-2"
            value={input}
            onChange={handleInputChange}
          />
        </label>
        <output>Completion result: {completion}</output>
        <button type="button" onClick={stop}>
          Stop
        </button>
        <button disabled={isLoading} type="submit">
          Send
        </button>
      </form>
    </div>
  )
}

Guide : Sauvegarder dans la base de données après avoir terminé

Il est courant de vouloir sauvegarder le résultat d'un achèvement dans une base de données après l'avoir transmis à l'utilisateur. L'adaptateur OpenAIStream accepte quelques rappels optionnels qui peuvent être utilisés à cette fin.

app/api/completion/route.ts

export async function POST(req: Request) {
  // ...
 
  // Convert the response into a friendly text-stream
  const stream = OpenAIStream(response, {
    onStart: async () => {
      // This callback is called when the stream starts
      // You can use this to save the prompt to your database
      await savePromptToDatabase(prompt)
    },
    onToken: async (token: string) => {
      // This callback is called for each token in the stream
      // You can use this to debug the stream or save the tokens to your database
      console.log(token)
    },
    onCompletion: async (completion: string) => {
      // This callback is called when the stream completes
      // You can use this to save the final completion to your database
      await saveCompletionToDatabase(completion)
    }
  })
 
  // Respond with the stream
  return new StreamingTextResponse(stream)
}