Maison > interface Web > js tutoriel > Comment créer un assistant IA avec OpenAI, Vercel AI SDK et Ollama avec Next.js

Comment créer un assistant IA avec OpenAI, Vercel AI SDK et Ollama avec Next.js

DDD
Libérer: 2024-11-07 03:30:03
original
690 Les gens l'ont consulté

Dans l'article de blog d'aujourd'hui, nous allons créer un assistant IA en utilisant trois modèles d'IA différents : Whisper et TTS d'OpenAI et Llama 3.1 de Meta.

En explorant l'IA, j'ai voulu essayer différentes choses et créer un assistant IA qui fonctionne par la voix. Cette curiosité m’a amené à combiner les modèles Whisper et TTS d’OpenAI avec Llama 3.1 de Meta pour créer un assistant à commande vocale.

Voici comment ces modèles fonctionneront ensemble :

  • Tout d'abord, nous enverrons notre audio au modèle Whisper, qui le convertira de la parole en texte.
  • Ensuite, nous transmettrons ce texte au modèle Llama 3.1. Lama comprendra le texte et générera une réponse.
  • Enfin, nous prendrons la réponse de Llama et l'enverrons au modèle TTS, transformant ainsi le texte en parole. Nous diffuserons ensuite cet audio au client.

Plongeons-nous et commençons à créer cet excellent assistant IA !

Démarrer

Nous utiliserons différents outils pour construire notre assistant. Pour construire notre côté client, nous utiliserons Next.js. Cependant, vous pouvez choisir le framework que vous préférez.

Pour utiliser nos modèles OpenAI, nous utiliserons leur SDK TypeScript/JavaScript. Pour utiliser cette API, nous avons besoin de la variable d'environnement suivante : OPENAI_API_KEY—

Pour obtenir cette clé, nous devons nous connecter au tableau de bord OpenAI et trouver la section Clés API. Ici, nous pouvons générer une nouvelle clé.

Open AI dashboard inside the API keys section

Génial. Désormais, pour utiliser notre modèle Llama 3.1, nous utiliserons Ollama et le SDK Vercel AI, en utilisant un fournisseur appelé ollama-ai-provider.

Ollama nous permettra de télécharger notre modèle préféré (nous pourrions même en utiliser un autre, comme Phi) et de l'exécuter localement. Le SDK Vercel facilitera son utilisation dans notre projet Next.js.

Pour utiliser Ollama, il suffit de le télécharger et de choisir notre modèle préféré. Pour cet article de blog, nous allons sélectionner Llama 3.1. Après avoir installé Ollama, nous pouvons vérifier s'il fonctionne en ouvrant notre terminal et en écrivant la commande suivante :

Terminal, with the command ‘ollama run llama3.1’

Remarquez que j'ai écrit «llama3.1» parce que c'est le modèle que j'ai choisi, mais vous devez utiliser celui que vous avez téléchargé.

Lancer les choses

Il est temps de démarrer en configurant notre application Next.js. Commençons par cette commande :

npx create-next-app@latest
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Après avoir exécuté la commande, vous verrez quelques invites pour définir les détails de l'application. Allons-y étape par étape :

  • Nommez votre application.
  • Activer le routeur d'application.

Les autres étapes sont facultatives et dépendent entièrement de vous. Dans mon cas, j'ai également choisi d'utiliser TypeScript et Tailwind CSS.

Maintenant que c'est fait, entrons dans notre projet et installons les dépendances dont nous avons besoin pour exécuter nos modèles :

npx create-next-app@latest
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Construire notre logique client

Maintenant, notre objectif est d'enregistrer notre voix, de l'envoyer au backend, puis d'en recevoir une réponse vocale.

Pour enregistrer notre audio, nous devons utiliser des fonctions côté client, ce qui signifie que nous devons utiliser des composants clients. Dans notre cas, nous ne voulons pas transformer l’intégralité de notre page pour utiliser les fonctionnalités du client et avoir l’arborescence entière dans le bundle client ; à la place, nous préférerions utiliser des composants serveur et importer nos composants clients pour améliorer progressivement notre application.

Créons donc un composant distinct qui gérera la logique côté client.

Dans notre dossier d'application, créons un dossier de composants, et ici, nous allons créer notre composant :

npm i ai ollama-ai-provider openai
Copier après la connexion
Copier après la connexion
Copier après la connexion

Allons-y et initialisons notre composant. Je suis allé de l'avant et j'ai ajouté un bouton avec quelques styles :

app
 ↳components
  ↳audio-recorder.tsx
Copier après la connexion
Copier après la connexion
Copier après la connexion

Et puis importez-le dans notre composant Page Server :

// app/components/audio-recorder.tsx
'use client'
export default function AudioRecorder() {
    function handleClick(){
      console.log('click')
    }

    return (
        <section>
        <button onClick={handleClick}
                    className={`bg-blue-500 text-white px-4 py-2 rounded shadow-md hover:bg-blue-400 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:ring-offset-white transition duration-300 ease-in-out absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2`}>
                Record voice
            </button>
        </section>
    )
}
Copier après la connexion
Copier après la connexion
Copier après la connexion

Maintenant, si nous exécutons notre application, nous devrions voir ce qui suit :

First look of the app, showing a centered blue button

Génial ! Maintenant, notre bouton ne fait rien, mais notre objectif est d'enregistrer notre audio et de l'envoyer quelque part ; pour cela, créons un hook qui contiendra notre logique :

// app/page.tsx
import AudioRecorder from '@/app/components/audio-recorder';

export default function Home() {
  return (
      <AudioRecorder />
  );
}
Copier après la connexion
Copier après la connexion
Copier après la connexion

Nous utiliserons deux API pour enregistrer notre voix : le navigateur et MediaRecorder. L'API du navigateur nous donnera des informations sur les appareils multimédias de l'utilisateur, comme l'audio multimédia de l'utilisateur, et MediaRecorder nous aidera à en enregistrer l'audio. Voici comment ils vont jouer ensemble :

app
 ↳hooks
  ↳useRecordVoice.ts

import { useEffect, useRef, useState } from 'react';

export function useRecordVoice() {
  return {}
}
Copier après la connexion
Copier après la connexion
Copier après la connexion

Expliquons ce code étape par étape. Premièrement, nous créons deux nouveaux états. Le premier sert à garder une trace du moment où nous enregistrons, et le second stocke l'instance de notre MediaRecorder.

// apps/hooks/useRecordVoice.ts
import { useEffect, useRef, useState } from 'react';

export function useRecordVoice() {
    const [isRecording, setIsRecording] = useState(false);
    const [mediaRecorder, setMediaRecorder] = useState<MediaRecorder | null>(null);

     const startRecording = async () => {
        if(!navigator?.mediaDevices){
            console.error('Media devices not supported');
            return;
        }

        const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
        const mediaRecorder = new MediaRecorder(stream);
        setIsRecording(true)
        setMediaRecorder(mediaRecorder);
        mediaRecorder.start(0)
    }

    const stopRecording = () =>{
        if(mediaRecorder) {
            setIsRecording(false)
            mediaRecorder.stop();
        }
    }

  return {
    isRecording,
    startRecording,
    stopRecording,
  }
}
Copier après la connexion
Copier après la connexion
Copier après la connexion

Ensuite, nous créerons notre première méthode, startRecording. Ici, nous allons avoir la logique pour commencer à enregistrer notre audio.
Nous vérifions d'abord si l'utilisateur dispose d'appareils multimédias grâce à l'API du navigateur qui nous donne des informations sur l'environnement de navigation de notre utilisateur :

Si nous n’avons pas d’appareil multimédia pour enregistrer notre audio, nous revenons simplement. S'ils le font, créons un flux à l'aide de leur appareil multimédia audio.

 const [isRecording, setIsRecording] = useState(false);
    const [mediaRecorder, setMediaRecorder] = useState<MediaRecorder | null>(null);
Copier après la connexion
Copier après la connexion

Enfin, nous allons de l'avant et créons une instance d'un MediaRecorder pour enregistrer cet audio :

npx create-next-app@latest
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Ensuite, nous avons besoin d'une méthode pour arrêter notre enregistrement, qui sera notre stopRecording. Ici, nous arrêterons simplement notre enregistrement au cas où un enregistreur multimédia existerait.

npm i ai ollama-ai-provider openai
Copier après la connexion
Copier après la connexion
Copier après la connexion

Nous enregistrons notre audio, mais nous ne le stockons nulle part. Ajoutons un nouveau useEffect et un nouveau ref pour y parvenir.
Nous aurions besoin d'une nouvelle référence, et c'est là que nos morceaux de données audio seront stockés.

app
 ↳components
  ↳audio-recorder.tsx
Copier après la connexion
Copier après la connexion
Copier après la connexion

Dans notre useEffect, nous allons faire deux choses principales : stocker ces morceaux dans notre référence, et quand il s'arrêtera, nous allons créer un nouveau Blob de type audio/mp3 :

// app/components/audio-recorder.tsx
'use client'
export default function AudioRecorder() {
    function handleClick(){
      console.log('click')
    }

    return (
        <section>
        <button onClick={handleClick}
                    className={`bg-blue-500 text-white px-4 py-2 rounded shadow-md hover:bg-blue-400 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:ring-offset-white transition duration-300 ease-in-out absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2`}>
                Record voice
            </button>
        </section>
    )
}
Copier après la connexion
Copier après la connexion
Copier après la connexion

Il est temps de câbler ce crochet avec notre composant AudioRecorder :

// app/page.tsx
import AudioRecorder from '@/app/components/audio-recorder';

export default function Home() {
  return (
      <AudioRecorder />
  );
}
Copier après la connexion
Copier après la connexion
Copier après la connexion

Passons de l’autre côté de la médaille, le backend !

Configuration de notre côté serveur

Nous souhaitons utiliser nos modèles sur le serveur pour assurer la sécurité et fonctionner plus rapidement. Créons une nouvelle route et ajoutons un gestionnaire pour celle-ci à l'aide des gestionnaires de route de Next.js. Dans notre dossier App, créons un dossier « Api » contenant l'itinéraire suivant :

Nous souhaitons utiliser nos modèles sur le serveur pour assurer la sécurité et fonctionner plus rapidement. Créons une nouvelle route et ajoutons un gestionnaire pour celle-ci à l'aide des gestionnaires de route de Next.js. Dans notre dossier App, créons un dossier « Api » contenant l'itinéraire suivant :

app
 ↳hooks
  ↳useRecordVoice.ts

import { useEffect, useRef, useState } from 'react';

export function useRecordVoice() {
  return {}
}
Copier après la connexion
Copier après la connexion
Copier après la connexion

Notre itinéraire s’appelle « chat ». Dans le fichier route.ts, nous allons configurer notre gestionnaire. Commençons par configurer notre SDK OpenAI.

// apps/hooks/useRecordVoice.ts
import { useEffect, useRef, useState } from 'react';

export function useRecordVoice() {
    const [isRecording, setIsRecording] = useState(false);
    const [mediaRecorder, setMediaRecorder] = useState<MediaRecorder | null>(null);

     const startRecording = async () => {
        if(!navigator?.mediaDevices){
            console.error('Media devices not supported');
            return;
        }

        const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
        const mediaRecorder = new MediaRecorder(stream);
        setIsRecording(true)
        setMediaRecorder(mediaRecorder);
        mediaRecorder.start(0)
    }

    const stopRecording = () =>{
        if(mediaRecorder) {
            setIsRecording(false)
            mediaRecorder.stop();
        }
    }

  return {
    isRecording,
    startRecording,
    stopRecording,
  }
}
Copier après la connexion
Copier après la connexion
Copier après la connexion

Dans cet itinéraire, nous enverrons l’audio depuis le front-end sous forme de chaîne base64. Ensuite, nous le recevrons et le transformerons en objet Buffer.

 const [isRecording, setIsRecording] = useState(false);
    const [mediaRecorder, setMediaRecorder] = useState<MediaRecorder | null>(null);
Copier après la connexion
Copier après la connexion

Il est temps d’utiliser notre premier modèle. Nous souhaitons transformer cet audio en texte et utiliser le modèle Whisper Speech-To-Text d'OpenAI. Whisper a besoin d'un fichier audio pour créer le texte. Puisque nous avons un Buffer au lieu d'un fichier, nous utiliserons leur méthode « toFile » pour convertir notre Buffer audio en un fichier audio comme ceci :

// check if they have media devices
if(!navigator?.mediaDevices){
 console.error('Media devices not supported');
 return;
}
// create stream using the audio media device
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
Copier après la connexion

Remarquez que nous avons spécifié « mp3 ». C'est l'une des nombreuses extensions que le modèle Whisper peut utiliser. Vous pouvez voir la liste complète des extensions prises en charge ici : https://platform.openai.com/docs/api-reference/audio/createTranscription#audio-createtranscription-file

Maintenant que notre fichier est prêt, passons-le à Whisper ! En utilisant notre instance OpenAI, voici comment nous invoquerons notre modèle :

// create an instance passing in the stream as parameter
const mediaRecorder = new MediaRecorder(stream);
// Set this state to true to 
setIsRecording(true)
// Store the instance in the state
setMediaRecorder(mediaRecorder);
// Start recording inmediately
mediaRecorder.start(0)
Copier après la connexion

C'est ça ! Maintenant, nous pouvons passer à l'étape suivante : utiliser Llama 3.1 pour interpréter ce texte et nous donner une réponse. Nous utiliserons deux méthodes pour cela. Tout d’abord, nous utiliserons « ollama » du package « ollama-ai-provider », qui nous permet d’utiliser ce modèle avec notre Ollama exécuté localement. Ensuite, nous utiliserons « generateText » du SDK Vercel AI pour générer le texte.
Remarque : pour que notre Ollama s'exécute localement, nous devons écrire la commande suivante dans le terminal :

npx create-next-app@latest
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
npm i ai ollama-ai-provider openai
Copier après la connexion
Copier après la connexion
Copier après la connexion

Enfin, nous avons notre dernier modèle : TTS d'OpenAI. Nous souhaitons répondre à notre utilisateur avec de l'audio, ce modèle sera donc très utile. Cela transformera notre texte en discours :

app
 ↳components
  ↳audio-recorder.tsx
Copier après la connexion
Copier après la connexion
Copier après la connexion

Le modèle TTS transformera notre réponse en fichier audio. Nous souhaitons diffuser cet audio à l'utilisateur comme ceci :

// app/components/audio-recorder.tsx
'use client'
export default function AudioRecorder() {
    function handleClick(){
      console.log('click')
    }

    return (
        <section>
        <button onClick={handleClick}
                    className={`bg-blue-500 text-white px-4 py-2 rounded shadow-md hover:bg-blue-400 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:ring-offset-white transition duration-300 ease-in-out absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2`}>
                Record voice
            </button>
        </section>
    )
}
Copier après la connexion
Copier après la connexion
Copier après la connexion

Et c’est tout le code backend ! Maintenant, revenons au frontend pour terminer le câblage.

Rassembler tout cela

Dans notre hook useRecordVoice.tsx, créons une nouvelle méthode qui appellera notre point de terminaison API. Cette méthode récupérera également la réponse et lira à l'utilisateur l'audio que nous diffusons depuis le backend.

// app/page.tsx
import AudioRecorder from '@/app/components/audio-recorder';

export default function Home() {
  return (
      <AudioRecorder />
  );
}
Copier après la connexion
Copier après la connexion
Copier après la connexion

Super ! Maintenant que nous recevons notre réponse en streaming, nous devons la gérer et restituer l'audio à l'utilisateur. Nous utiliserons l'API AudioContext pour cela. Cette API nous permet de stocker l'audio, de le décoder et de le lire à l'utilisateur une fois qu'il est prêt :

app
 ↳hooks
  ↳useRecordVoice.ts

import { useEffect, useRef, useState } from 'react';

export function useRecordVoice() {
  return {}
}
Copier après la connexion
Copier après la connexion
Copier après la connexion

Et c'est tout ! L'utilisateur devrait maintenant entendre la réponse audio sur son appareil. Pour conclure, rendons notre application un peu plus agréable en ajoutant un petit indicateur de chargement :

// apps/hooks/useRecordVoice.ts
import { useEffect, useRef, useState } from 'react';

export function useRecordVoice() {
    const [isRecording, setIsRecording] = useState(false);
    const [mediaRecorder, setMediaRecorder] = useState<MediaRecorder | null>(null);

     const startRecording = async () => {
        if(!navigator?.mediaDevices){
            console.error('Media devices not supported');
            return;
        }

        const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
        const mediaRecorder = new MediaRecorder(stream);
        setIsRecording(true)
        setMediaRecorder(mediaRecorder);
        mediaRecorder.start(0)
    }

    const stopRecording = () =>{
        if(mediaRecorder) {
            setIsRecording(false)
            mediaRecorder.stop();
        }
    }

  return {
    isRecording,
    startRecording,
    stopRecording,
  }
}
Copier après la connexion
Copier après la connexion
Copier après la connexion

Conclusion

Dans cet article de blog, nous avons vu comment la combinaison de plusieurs modèles d'IA peut nous aider à atteindre nos objectifs. Nous avons appris à exécuter des modèles d'IA comme Llama 3.1 localement et à les utiliser dans notre application Next.js. Nous avons également découvert comment envoyer de l'audio à ces modèles et renvoyer une réponse, en lisant l'audio à l'utilisateur.

Ce n'est qu'une des nombreuses façons d'utiliser l'IA : les possibilités sont infinies. Les modèles d’IA sont des outils étonnants qui nous permettent de créer des choses autrefois difficiles à réaliser avec une telle qualité. Merci d'avoir lu ; maintenant, c'est à votre tour de construire quelque chose d'incroyable avec l'IA !

Vous pouvez retrouver la démo complète sur GitHub : AI Assistant avec Whisper TTS et Ollama utilisant Next.js

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal