Heim  >  Artikel  >  Web-Frontend  >  So erstellen Sie einen KI-Assistenten mit OpenAI, Vercel AI SDK und Ollama mit Next.js

So erstellen Sie einen KI-Assistenten mit OpenAI, Vercel AI SDK und Ollama mit Next.js

DDD
DDDOriginal
2024-11-07 03:30:03598Durchsuche

Im heutigen Blogbeitrag erstellen wir einen KI-Assistenten mit drei verschiedenen KI-Modellen: Whisper und TTS von OpenAI und Llama 3.1 von Meta.

Während ich mich mit KI beschäftigte, wollte ich verschiedene Dinge ausprobieren und einen KI-Assistenten entwickeln, der per Stimme funktioniert. Diese Neugier veranlasste mich, die Whisper- und TTS-Modelle von OpenAI mit Llama 3.1 von Meta zu kombinieren, um einen sprachaktivierten Assistenten zu entwickeln.

So funktionieren diese Modelle zusammen:

  • Zuerst senden wir unser Audio an das Whisper-Modell, das es von Sprache in Text umwandelt.
  • Als nächstes übergeben wir diesen Text an das Llama 3.1-Modell. Lama wird den Text verstehen und eine Antwort generieren.
  • Zuletzt nehmen wir Llamas Antwort und senden sie an das TTS-Modell, um den Text wieder in Sprache umzuwandeln. Anschließend streamen wir das Audio zurück an den Client.

Lassen Sie uns eintauchen und mit der Entwicklung dieses hervorragenden KI-Assistenten beginnen!

Erste Schritte

Wir werden verschiedene Tools verwenden, um unseren Assistenten zu erstellen. Zum Aufbau unserer Client-Seite verwenden wir Next.js. Sie können jedoch das von Ihnen bevorzugte Framework wählen.

Um unsere OpenAI-Modelle zu verwenden, verwenden wir deren TypeScript/JavaScript SDK. Um diese API verwenden zu können, benötigen wir die folgende Umgebungsvariable: OPENAI_API_KEY –

Um diesen Schlüssel zu erhalten, müssen wir uns beim OpenAI-Dashboard anmelden und den Abschnitt „API-Schlüssel“ finden. Hier können wir einen neuen Schlüssel generieren.

Open AI dashboard inside the API keys section

Super. Um nun unser Llama 3.1-Modell zu verwenden, verwenden wir Ollama und das Vercel AI SDK und nutzen einen Anbieter namens ollama-ai-provider.

Ollama ermöglicht es uns, unser bevorzugtes Modell herunterzuladen (wir könnten sogar ein anderes verwenden, wie Phi) und es lokal auszuführen. Das Vercel SDK wird die Verwendung in unserem Next.js-Projekt erleichtern.

Um Ollama zu nutzen, müssen wir es nur herunterladen und unser bevorzugtes Modell auswählen. Für diesen Blogbeitrag wählen wir Llama 3.1 aus. Nach der Installation von Ollama können wir überprüfen, ob es funktioniert, indem wir unser Terminal öffnen und den folgenden Befehl schreiben:

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

Beachten Sie, dass ich „llama3.1“ geschrieben habe, weil das das von mir gewählte Modell ist, aber Sie sollten das heruntergeladene verwenden.

Der Auftakt geht los

Es ist Zeit, mit der Einrichtung unserer Next.js-App loszulegen. Beginnen wir mit diesem Befehl:

npx create-next-app@latest

Nachdem Sie den Befehl ausgeführt haben, werden einige Eingabeaufforderungen zum Festlegen der App-Details angezeigt. Gehen wir Schritt für Schritt vor:

  • Benennen Sie Ihrer App.
  • App-Router aktivieren.

Die anderen Schritte sind optional und liegen ganz bei Ihnen. In meinem Fall habe ich mich auch für die Verwendung von TypeScript und Tailwind CSS entschieden.

Sobald das erledigt ist, gehen wir in unser Projekt und installieren die Abhängigkeiten, die wir zum Ausführen unserer Modelle benötigen:

npx create-next-app@latest

Aufbau unserer Kundenlogik

Unser Ziel ist es nun, unsere Stimme aufzuzeichnen, sie an das Backend zu senden und dann eine Sprachantwort von diesem zu erhalten.

Um unser Audio aufzunehmen, müssen wir clientseitige Funktionen verwenden, was bedeutet, dass wir Client-Komponenten verwenden müssen. In unserem Fall möchten wir nicht unsere gesamte Seite umwandeln, um Client-Funktionen zu nutzen und den gesamten Baum im Client-Bundle zu haben; Stattdessen würden wir es vorziehen, Serverkomponenten zu verwenden und unsere Clientkomponenten zu importieren, um unsere Anwendung schrittweise zu verbessern.

Also erstellen wir eine separate Komponente, die die clientseitige Logik verwaltet.

In unserem App-Ordner erstellen wir einen Komponentenordner, und hier erstellen wir unsere Komponente:

npm i ai ollama-ai-provider openai

Lassen Sie uns fortfahren und unsere Komponente initialisieren. Ich habe einen Button mit einigen Stilen hinzugefügt:

app
 ↳components
  ↳audio-recorder.tsx

Und dann importieren Sie es in unsere Page Server-Komponente:

// 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>
    )
}

Wenn wir nun unsere App ausführen, sollten wir Folgendes sehen:

First look of the app, showing a centered blue button

Super! Nun, unsere Schaltfläche bewirkt nichts, aber unser Ziel ist es, unser Audio aufzunehmen und es irgendwohin zu senden; Lassen Sie uns dazu einen Hook erstellen, der unsere Logik enthält:

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

export default function Home() {
  return (
      <AudioRecorder />
  );
}

Wir werden zwei APIs verwenden, um unsere Stimme aufzuzeichnen: Navigator und MediaRecorder. Die Navigator-API liefert uns Informationen über die Mediengeräte des Benutzers, z. B. das Medienaudio des Benutzers, und der MediaRecorder hilft uns, das Audio davon aufzuzeichnen. So werden sie zusammen spielen:

app
 ↳hooks
  ↳useRecordVoice.ts

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

export function useRecordVoice() {
  return {}
}

Lassen Sie uns diesen Code Schritt für Schritt erklären. Zuerst erstellen wir zwei neue Staaten. Der erste dient dazu, den Überblick darüber zu behalten, wann wir aufnehmen, und der zweite speichert die Instanz unseres MediaRecorders.

// 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,
  }
}

Dann erstellen wir unsere erste Methode, startRecording. Hier haben wir die Logik, mit der Aufnahme unseres Audios zu beginnen.
Wir prüfen zunächst, ob der Benutzer über Mediengeräte verfügt, dank der Navigator-API, die uns Informationen über die Browserumgebung unseres Benutzers liefert:

Wenn wir keine Mediengeräte zum Aufzeichnen unserer Audiodaten haben, kehren wir einfach zurück. Wenn ja, dann lassen Sie uns mit ihrem Audio-Mediengerät einen Stream erstellen.

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

Zuletzt erstellen wir eine Instanz eines MediaRecorders, um dieses Audio aufzunehmen:

npx create-next-app@latest

Dann brauchen wir eine Methode, um unsere Aufnahme zu stoppen, nämlich unsere stopRecording. Hier stoppen wir einfach unsere Aufnahme, falls ein Medienrekorder vorhanden ist.

npm i ai ollama-ai-provider openai

Wir nehmen unser Audio auf, speichern es aber nirgendwo. Fügen wir einen neuen useEffect und ref hinzu, um dies zu erreichen.
Wir bräuchten eine neue Referenz, und hier werden unsere Audiodatenblöcke gespeichert.

app
 ↳components
  ↳audio-recorder.tsx

In unserem useEffect werden wir vor allem zwei Dinge tun: diese Chunks in unserem Ref speichern, und wenn er stoppt, erstellen wir einen neuen Blob vom Typ 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>
    )
}

Es ist Zeit, diesen Haken mit unserer AudioRecorder-Komponente zu verbinden:

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

export default function Home() {
  return (
      <AudioRecorder />
  );
}

Lassen Sie uns zur anderen Seite der Medaille übergehen, dem Backend!

Einrichten unserer Serverseite

Wir möchten unsere Modelle auf dem Server verwenden, um die Sicherheit zu gewährleisten und schneller zu laufen. Erstellen wir eine neue Route und fügen mithilfe der Routenhandler von Next.js einen Handler dafür hinzu. Erstellen wir in unserem App-Ordner einen „Api“-Ordner mit der folgenden Route darin:

Wir möchten unsere Modelle auf dem Server verwenden, um die Sicherheit zu gewährleisten und schneller zu laufen. Erstellen wir eine neue Route und fügen mithilfe der Routenhandler von Next.js einen Handler dafür hinzu. Erstellen wir in unserem App-Ordner einen „Api“-Ordner mit der folgenden Route darin:

app
 ↳hooks
  ↳useRecordVoice.ts

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

export function useRecordVoice() {
  return {}
}

Unsere Route heißt „Chat“. In der Datei route.ts richten wir unseren Handler ein. Beginnen wir mit der Einrichtung unseres OpenAI SDK.

// 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,
  }
}

Auf dieser Route senden wir das Audio vom Frontend als Base64-String. Dann empfangen wir es und wandeln es in ein Pufferobjekt um.

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

Es ist Zeit, unser erstes Modell zu verwenden. Wir möchten dieses Audio in Text umwandeln und das Whisper Speech-To-Text-Modell von OpenAI verwenden. Whisper benötigt zur Erstellung des Textes eine Audiodatei. Da wir einen Puffer anstelle einer Datei haben, verwenden wir ihre „toFile“-Methode, um unseren Audiopuffer wie folgt in eine Audiodatei umzuwandeln:

// 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 });

Beachten Sie, dass wir „mp3“ angegeben haben. Dies ist eine der vielen Erweiterungen, die das Whisper-Modell nutzen kann. Die vollständige Liste der unterstützten Erweiterungen finden Sie hier: https://platform.openai.com/docs/api-reference/audio/createTranscription#audio-createtranscription-file

Jetzt, da unsere Datei fertig ist, geben wir sie an Whisper weiter! Mit unserer OpenAI-Instanz rufen wir unser Modell folgendermaßen auf:

// 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)

Das ist es! Jetzt können wir mit dem nächsten Schritt fortfahren: Verwenden von Llama 3.1, um diesen Text zu interpretieren und uns eine Antwort zu geben. Wir verwenden hierfür zwei Methoden. Zuerst verwenden wir „ollama“ aus dem Paket „ollama-ai-provider“, wodurch wir dieses Modell mit unserem lokal ausgeführten Ollama verwenden können. Anschließend verwenden wir „generateText“ aus dem Vercel AI SDK, um den Text zu generieren.
Randnotiz: Damit unser Ollama lokal läuft, müssen wir den folgenden Befehl in das Terminal schreiben:

npx create-next-app@latest
npm i ai ollama-ai-provider openai

Endlich haben wir unser letztes Modell: TTS von OpenAI. Wir möchten unserem Benutzer mit Audio antworten, daher wird dieses Modell wirklich hilfreich sein. Dadurch wird unser Text in Sprache umgewandelt:

app
 ↳components
  ↳audio-recorder.tsx

Das TTS-Modell wandelt unsere Antwort in eine Audiodatei um. Wir möchten dieses Audio wie folgt an den Benutzer zurückstreamen:

// 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>
    )
}

Und das ist der gesamte Backend-Code! Nun zurück zum Frontend, um die Verkabelung abzuschließen.

Alles zusammenfügen

In unserem useRecordVoice.tsx-Hook erstellen wir eine neue Methode, die unseren API-Endpunkt aufruft. Diese Methode nimmt auch die Antwort zurück und spielt dem Benutzer das Audio ab, das wir vom Backend streamen.

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

export default function Home() {
  return (
      <AudioRecorder />
  );
}

Großartig! Da wir nun unsere gestreamte Antwort erhalten, müssen wir diese bearbeiten und dem Benutzer den Ton wiedergeben. Wir verwenden hierfür die AudioContext-API. Mit dieser API können wir das Audio speichern, dekodieren und dem Benutzer wiedergeben, sobald es fertig ist:

app
 ↳hooks
  ↳useRecordVoice.ts

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

export function useRecordVoice() {
  return {}
}

Und das ist es! Jetzt sollte der Benutzer die Audioantwort auf seinem Gerät hören. Zum Abschluss machen wir unsere App noch etwas schöner, indem wir eine kleine Ladeanzeige hinzufügen:

// 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,
  }
}

Fazit

In diesem Blogbeitrag haben wir gesehen, wie die Kombination mehrerer KI-Modelle uns helfen kann, unsere Ziele zu erreichen. Wir haben gelernt, KI-Modelle wie Llama 3.1 lokal auszuführen und in unserer Next.js-App zu verwenden. Wir haben auch herausgefunden, wie man Audio an diese Modelle sendet und eine Antwort zurückstreamt, indem man das Audio dem Benutzer wiedergibt.

Dies ist nur eine von vielen Möglichkeiten, wie Sie KI nutzen können – die Möglichkeiten sind endlos. KI-Modelle sind erstaunliche Werkzeuge, mit denen wir Dinge schaffen können, die früher in dieser Qualität nur schwer zu erreichen waren. Danke fürs Lesen; Jetzt sind Sie an der Reihe, mit KI etwas Erstaunliches zu schaffen!

Die vollständige Demo finden Sie auf GitHub: AI Assistant mit Whisper TTS und Ollama unter Verwendung von Next.js

Das obige ist der detaillierte Inhalt vonSo erstellen Sie einen KI-Assistenten mit OpenAI, Vercel AI SDK und Ollama mit Next.js. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn