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 :
Plongeons-nous et commençons à créer cet excellent assistant IA !
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é.
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 :
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é.
Il est temps de démarrer en configurant notre application Next.js. Commençons par cette commande :
npx create-next-app@latest
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 :
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
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
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
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> ) }
Maintenant, si nous exécutons notre application, nous devrions voir ce qui suit :
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 /> ); }
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 {} }
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, } }
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);
Enfin, nous allons de l'avant et créons une instance d'un MediaRecorder pour enregistrer cet audio :
npx create-next-app@latest
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
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
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> ) }
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 /> ); }
Passons de l’autre côté de la médaille, le backend !
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 {} }
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, } }
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);
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 });
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)
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
npm i ai ollama-ai-provider openai
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
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> ) }
Et c’est tout le code backend ! Maintenant, revenons au frontend pour terminer le câblage.
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 /> ); }
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 {} }
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, } }
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!