In der dynamischen Technologielandschaft, in der Innovationen die Grenzen des Möglichen immer weiter verschieben, hört die künstliche Intelligenz (KI) nicht auf, unsere Fantasie zu beflügeln.
Unter KI versteht man die Simulation menschlicher Intelligenzprozesse durch Computersysteme. Zu diesen Prozessen gehören Aufgaben wie Lernen, Denken, Problemlösung, Wahrnehmung, Sprachverständnis und Entscheidungsfindung.
Heute haben Einzelpersonen und Unternehmen verschiedene KI-Modelle entwickelt und trainiert, um bestimmte Aufgaben besser als Menschen in Echtzeit zu erledigen. Unter den unzähligen Anwendungen von KI ist ein besonders faszinierender Bereich die KI-gestützte Bilderzeugung.
Was du bauen wirst
In diesem Leitfaden wird erklärt, wie du eine React-Anwendung erstellst, die sich über ein Node.js-Backend nahtlos in die OpenAI DALL-E API integriert und auf der Grundlage von Textaufforderungen fesselnde Bilder erzeugt.
Voraussetzungen
Um an diesem Projekt mitzuarbeiten, solltest du Folgendes mitbringen:
- Grundlegendes Verständnis von HTML, CSS und JavaScript
- Grundkenntnisse in React und Node.js
- Node.js und npm (Node Package Manager) oder yarn auf deinem Computer installiert haben
Was ist die OpenAI DALL-E API?
Die OpenAI API ist eine Cloud-basierte Plattform, die Entwicklern Zugang zu den vortrainierten KI-Modellen von OpenAI wie DALL-E und GPT-3 gewährt (wir haben dieses Modell verwendet, um einen ChatGPT-Klon mit dem Code in diesem Git-Repository zu erstellen). Damit können Entwickler KI-Funktionen wie Zusammenfassungen, Übersetzungen, Bilderzeugung und Modifikationen in ihre Programme einbauen, ohne ihre Modelle entwickeln und trainieren zu müssen.
Um die OpenAI API zu nutzen, musst du ein Konto mit deinem Google-Konto oder deiner E-Mail-Adresse auf der OpenAI-Website erstellen und einen API-Schlüssel anfordern. Um einen API-Schlüssel zu erhalten, klickst du oben rechts auf der Website auf Personal und wählst dann API-Schlüssel anzeigen.
Klicke auf die Schaltfläche Neuen geheimen Schlüssel erstellen und speichere den Schlüssel irgendwo. Du wirst ihn in dieser Anwendung verwenden, um mit der DALL-E API von OpenAI zu interagieren.
Einrichten der Entwicklungsumgebung
Du kannst eine React-Anwendung von Grund auf neu erstellen und deine eigene Schnittstelle entwickeln oder du kannst dir unsere Git-Starter-Vorlage schnappen, indem du diese Schritte befolgst:
- Besuche das GitHub-Repository für dieses Projekt.
- Wähle Diese Vorlage verwenden > Neues Repository erstellen, um den Startcode in ein Repository in deinem GitHub-Konto zu kopieren (aktiviere das Kontrollkästchen, um alle Zweige einzuschließen).
- Ziehe das Repository auf deinen lokalen Computer und wechsle mit dem Befehl in den starter-files-Zweig:
git checkout starter-files
.
- Installiere die notwendigen Abhängigkeiten, indem du den Befehl
npm install
ausführst.
Sobald die Installation abgeschlossen ist, kannst du das Projekt auf deinem lokalen Computer mit npm run start
starten. Dadurch wird das Projekt unter http://localhost:3000/ verfügbar.
Das Verständnis der Projektdateien
In diesem Projekt haben wir alle notwendigen Abhängigkeiten für deine React-Anwendung hinzugefügt. Hier ist eine Übersicht über die installierten Dateien:
- file-server: Diese Hilfsbibliothek vereinfacht das Herunterladen der erzeugten Bilder. Sie ist mit dem Download-Button verknüpft und sorgt für ein reibungsloses Nutzererlebnis.
- uuid: Diese Bibliothek weist jedem Bild eine eindeutige Kennung zu. Dadurch wird verhindert, dass Bilder denselben Standard-Dateinamen haben, und die Ordnung und Übersichtlichkeit bleibt erhalten.
- react-icons: Diese Bibliothek ist in das Projekt integriert und bindet mühelos Icons ein, um die visuelle Attraktivität deiner Anwendung zu verbessern.
Das Herzstück deiner React-Anwendung ist der Ordner src. Hier befindet sich der wesentliche JavaScript-Code für Webpack. Wir wollen die Dateien und Ordner im src-Ordner kennenlernen:
- assets: In diesem Verzeichnis findest du die Bilder und das Loader-GIF, die im gesamten Projekt verwendet werden.
- data: Dieser Ordner enthält eine index.js-Datei, die eine Reihe von 30 Prompts exportiert. Diese Prompts können verwendet werden, um verschiedene und zufällige Bilder zu erzeugen. Du kannst sie gerne bearbeiten.
- index.css: Hier werden die Stile, die in diesem Projekt verwendet werden, gespeichert.
Den Utils-Ordner verstehen
In diesem Ordner definiert die Datei index.js zwei wiederverwendbare Funktionen. Die erste Funktion wählt nach dem Zufallsprinzip die Prompts aus, die verschiedene Bilder beschreiben, die erzeugt werden können.
import { randomPrompts } from '../data';
export const getRandomPrompt = () => {
const randomIndex = Math.floor(Math.random() * randomPrompts.length);
const randomPrompt = randomPrompts[randomIndex];
return randomPrompt;
}
Die zweite Funktion kümmert sich um den Download der erzeugten Bilder, indem sie die Abhängigkeit von file-saver nutzt. Beide Funktionen sind modular und effizient aufgebaut und können bei Bedarf bequem in Komponenten importiert werden.
import FileSaver from 'file-saver';
import { v4 as uuidv4 } from 'uuid';
export async function downloadImage(photo) {
const _id = uuidv4();
FileSaver.saveAs(photo, `download-${_id}.jpg`);
}
Im obigen Code gibt die uuid-Abhängigkeit jeder erzeugten Bilddatei eine eindeutige ID, damit sie nicht denselben Dateinamen haben.
Zum Verständnis der Komponenten
Das sind kleine Codeblöcke, die voneinander getrennt sind, damit dein Code einfach zu pflegen und zu verstehen ist. Für dieses Projekt wurden drei Komponenten erstellt: Header.jsx, Footer.jsx und Form.jsx. Die Hauptkomponente ist die Komponente Form, in der die Eingaben empfangen und an die Datei App.jsx weitergegeben werden. Die Funktion generateImage
wurde als onClick
-Ereignis zur Schaltfläche Generate Image hinzugefügt.
In der Formularkomponente wird ein Status erstellt, um die Eingabeaufforderung zu speichern und zu aktualisieren. Außerdem gibt es eine Funktion, mit der du auf ein zufälliges Symbol klicken kannst, um die zufälligen Prompts zu generieren. Dies ist mit der Funktion handleRandomPrompt
möglich, die die Funktion getRandomPrompt
verwendet, die du bereits eingerichtet hast. Wenn du auf das Symbol klickst, wird ein zufälliger Prompt abgerufen und der Status damit aktualisiert:
const handleRandomPrompt = () => {
const randomPrompt = getRandomPrompt();
setPrompt(randomPrompt)
}
Die Datei App.jsx verstehen
Hier befindet sich der größte Teil des Codes. Alle Komponenten werden hier zusammengeführt. Es gibt auch einen Bereich, in dem das erzeugte Bild angezeigt wird. Wenn noch kein Bild erstellt wurde, wird ein Platzhalterbild (Vorschaubild) angezeigt.
In dieser Datei werden zwei Zustände verwaltet:
isGenerating
: Hier wird festgehalten, ob gerade ein Bild erstellt wird. In der Standardeinstellung ist er auf false gesetzt.generatedImage
: Dieser Status speichert Informationen über das Bild, das erstellt wurde.
Außerdem wird die Funktion downloadImage
importiert, mit der du den Download des erzeugten Bildes auslösen kannst, wenn du auf die Schaltfläche Download klickst:
<button
className="btn"
onClick={() => downloadImage(generatedImage.photo)}
>
Jetzt, wo du die Startdateien verstanden und dein Projekt eingerichtet hast, kannst du mit der Logik der Anwendung beginnen. Beginnen wir nun mit der Logik dieser Anwendung.
Bilder mit der DALL-E API von OpenAI generieren
Um die Möglichkeiten von OpenAIs DALL-E API zu nutzen, musst du mit Node.js einen Server einrichten. Innerhalb dieses Servers erstellst du eine POST-Route. Diese Route ist dafür zuständig, den von deiner React-Anwendung gesendeten Prompt-Text zu empfangen und daraus ein Bild zu erzeugen.
Um loszulegen, installierst du die notwendigen Abhängigkeiten in deinem Projektverzeichnis, indem du den folgenden Befehl ausführst:
npm i express cors openai
Installiere außerdem die folgenden Abhängigkeiten als Dev-Abhängigkeiten. Diese Tools helfen dir beim Einrichten deines Node.js-Servers:
npm i -D dotenv nodemon
Die installierten Abhängigkeiten werden im Folgenden erklärt:
- express: Diese Bibliothek hilft beim Erstellen eines Servers in Node.js.
- cors: CORS ermöglicht eine sichere Kommunikation zwischen verschiedenen Domains.
- openai: Diese Abhängigkeit ermöglicht dir den Zugriff auf die DALL-E API von OpenAI.
- dotenv: dotenv hilft dir bei der Verwaltung von Umgebungsvariablen.
- nodemon: nodemon ist ein Entwicklungswerkzeug, das Änderungen an deinen Dateien überwacht und den Server automatisch neu startet.
Wenn die Installation erfolgreich war, erstelle eine server.js-Datei im Stammverzeichnis deines Projekts. Hier wird dein gesamter Servercode gespeichert.
Importiere in der Datei server.js die Bibliotheken, die du gerade installiert hast, und instanziere sie:
// Import the necessary libraries
const express = require('express');
const cors = require('cors');
require('dotenv').config();
const OpenAI = require('openai');
// Create an instance of the Express application
const app = express();
// Enable Cross-Origin Resource Sharing (CORS)
app.use(cors());
// Configure Express to parse JSON data and set a data limit
app.use(express.json({ limit: '50mb' }));
// Create an instance of the OpenAI class and provide your API key
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});
// Define a function to start the server
const startServer = async () => {
app.listen(8080, () => console.log('Server started on port 8080'));
};
// Call the startServer function to begin listening on the specified port
startServer();
Im obigen Code importierst du die notwendigen Bibliotheken. Dann richtest du mit const app = express();
eine Instanz der Express-Anwendung ein. Danach aktivierst du CORS. Als Nächstes wird Express so konfiguriert, dass es eingehende JSON-Daten verarbeitet, wobei eine Datengrößenbeschränkung von 50mb
festgelegt wird.
Anschließend wird eine Instanz der OpenAI-Klasse unter Verwendung deines OpenAI-API-Schlüssels erstellt. Erstelle eine .env-Datei im Stammverzeichnis deines Projekts und füge deinen API-Schlüssel über die Variable OPENAI_API_KEY
hinzu. Schließlich definierst du eine asynchrone startServer
Funktion und rufst sie auf, um den Server in Gang zu setzen.
Jetzt hast du deine server.js-Datei konfiguriert. Erstellen wir nun eine POST-Route, die du in deiner React-Anwendung verwenden kannst, um mit diesem Server zu interagieren:
app.post('/api', async (req, res) => {
try {
const { prompt } = req.body;
const response = await openai.images.generate({
prompt,
n: 1,
size: '1024x1024',
response_format: 'b64_json',
});
const image = response.data[0].b64_json;
res.status(200).json({ photo: image });
} catch (error) {
console.error(error);
}
});
In diesem Code ist die Route auf /api
eingestellt und soll eingehende POST-Anfragen bearbeiten. In der Callback-Funktion der Route erhältst du die von deiner React-Anwendung gesendeten Daten über req.body
– genauer gesagt über den Wert prompt
.
Anschließend wird die Methode images.generate
der OpenAI-Bibliothek aufgerufen. Diese Methode nimmt die angegebene Eingabeaufforderung entgegen und erzeugt als Antwort ein Bild. Parameter wie n
bestimmen die Anzahl der zu erzeugenden Bilder (hier nur eines), size
gibt die Abmessungen des Bildes an und response_format
gibt das Format an, in dem die Antwort geliefert werden soll (in diesem Fallb64_json
).
Nachdem du das Bild erzeugt hast, extrahierst du die Bilddaten aus der Antwort und speicherst sie in der Variablen image
. Dann schickst du eine JSON-Antwort mit den erzeugten Bilddaten zurück an die React-Anwendung und setzt den HTTP-Status mit res.status(200).json({ photo: image })
auf 200
(was einen Erfolg anzeigt).
Wenn während dieses Prozesses ein Fehler auftritt, wird der Code im catch
Block ausgeführt und der Fehler zum Debuggen auf der Konsole protokolliert.
Jetzt ist der Server bereit! Legen wir den Befehl, mit dem unser Server ausgeführt werden soll, in der Datei package.json scripts
Objekt fest:
"scripts": {
"dev:frontend": "react-scripts start",
"dev:backend": "nodemon server.js",
"build": "react-scripts build",
},
Wenn du npm run dev:backend
aufrufst, wird dein Server auf http://localhost:8080/ gestartet, und wenn du npm run dev:frontend
aufrufst, wird deine React-Anwendung auf http://localhost:3000/ gestartet. Stelle sicher, dass beide in verschiedenen Terminals laufen.
HTTP-Anfragen von React an den Node.js Server stellen
In der Datei App.jsx erstellst du eine Funktion generateImage
, die ausgelöst wird, wenn du in der Komponente Form.jsx auf die Schaltfläche Bild generieren klickst. Diese Funktion nimmt zwei Parameter entgegen: prompt
und setPrompt
aus der Komponente Form.jsx.
In der Funktion generateImage
stellst du eine HTTP-POST-Anfrage an den Node.js-Server:
const generateImage = async (prompt, setPrompt) => {
if (prompt) {
try {
setIsGenerating(true);
const response = await fetch(
'http://localhost:8080/api',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
prompt,
}),
}
);
const data = await response.json();
setGeneratedImage({
photo: `data:image/jpeg;base64,${data.photo}`,
altText: prompt,
});
} catch (err) {
alert(err);
} finally {
setPrompt('');
setIsGenerating(false);
}
} else {
alert('Please provide proper prompt');
}
};
Im obigen Code überprüfst du, ob der Parameter prompt
einen Wert hat, und setzt dann den Status von isGenerating
auf true
, da der Vorgang gestartet wird. Dadurch wird der Lader auf dem Bildschirm angezeigt, denn in der Datei App.jsx haben wir diesen Code, der die Anzeige des Laders steuert:
{isGenerating && (
<div> className="loader-comp">
<img src={Loader} alt="" className='loader-img' />
</div>
)}
Als Nächstes verwenden wir die Methode fetch()
, um mit http://localhost:8080/api eine POST-Anfrage an den Server zu stellen – aus diesem Grund haben wir CORS installiert, da wir mit einer API auf einer anderen URL interagieren. Wir verwenden die Eingabeaufforderung als Text der Nachricht. Dann extrahierst du die vom Node.js-Server zurückgegebene Antwort und setzt sie in den Zustand generatedImage
.
Sobald der Status generatedImage
einen Wert hat, wird das Bild angezeigt:
{generatedImage.photo ? (
<img
src={generatedImage.photo}
alt={generatedImage.altText}
className="imgg ai-img"
/>
) : (
<img
src={preview}
alt="preview"
className="imgg preview-img"
/>
)}
So sieht deine vollständige App.jsx-Datei aus:
import { Form, Footer, Header } from './components';
import preview from './assets/preview.png';
import Loader from './assets/loader-3.gif'
import { downloadImage } from './utils';
import { useState } from 'react';
const App = () => {
const [isGenerating, setIsGenerating] = useState(false);
const [generatedImage, setGeneratedImage] = useState({
photo: null,
altText: null,
});
const generateImage = async (prompt, setPrompt) => {
if (prompt) {
try {
setIsGenerating(true);
const response = await fetch(
'http://localhost:8080/api',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
prompt,
}),
}
);
const data = await response.json();
setGeneratedImage({
photo: `data:image/jpeg;base64,${data.photo}`,
altText: prompt,
});
} catch (err) {
alert(err);
} finally {
setPrompt('');
setIsGenerating(false);
}
} else {
alert('Please provide proper prompt');
}
};
return (
<div className='container'>
<Header />
<main className="flex-container">
<Form generateImage={generateImage} prompt={prompt} />
<div className="image-container">
{generatedImage.photo ? (
<img
src={generatedImage.photo}
alt={generatedImage.altText}
className="imgg ai-img"
/>
) : (
<img
src={preview}
alt="preview"
className="imgg preview-img"
/>
)}
{isGenerating && (
<div className="loader-comp">
<img src={Loader} alt="" className='loader-img' />
</div>
)}
<button
className="btn"
onClick={() => downloadImage(generatedImage.photo)}
>
Download
</button>
</div>
</main>
<Footer />
</div>
);
};
export default App;
Bereitstellen deiner Full-Stack-Anwendung auf Kinsta
Bis jetzt hast du erfolgreich eine React-Anwendung erstellt, die mit Node.js interagiert und somit eine Full-Stack-Anwendung ist. Jetzt können wir diese Anwendung auf Kinsta bereitstellen.
Konfiguriere den Server zunächst so, dass er die statischen Dateien bereitstellt, die während des Build-Prozesses der React-Anwendung erzeugt wurden. Dazu importierst du das Modul path
und verwendest es zum Bereitstellen der statischen Dateien:
const path = require('path');
app.use(express.static(path.resolve(__dirname, './build')));
Wenn du den Befehl npm run build && npm run dev:backend
ausführst, wird deine Full-Stack-React-Anwendung unter http://localhost:8080/ geladen. Das liegt daran, dass die React-Anwendung im Build-Ordner in statische Dateien kompiliert wird. Diese Dateien werden dann als statisches Verzeichnis in deinen Node.js-Server eingebunden. Wenn du deinen Node.js-Server startest, ist die Anwendung also zugänglich.
Bevor du deinen Code bei dem von dir gewählten Git-Anbieter (Bitbucket, GitHub oder GitLab) bereitstellst, musst du die HTTP-Request-URL in deiner App.jsx-Datei ändern. Ändere http://localhost:8080/api
in /api
, da die URL vorangestellt werden soll.
Schließlich fügst du in deiner package.json-Datei einen Skriptbefehl für den Node.js-Server hinzu, der für die Bereitstellung verwendet werden soll:
"scripts": {
// …
"start": "node server.js",
},
Als Nächstes pusht du deinen Code zu deinem bevorzugten Git-Provider und stellst dein Repository auf Kinsta bereit, indem du diese Schritte befolgst:
- Melde dich in deinem Kinsta-Konto auf dem MyKinsta-Dashboard an.
- Wähle in der linken Seitenleiste Anwendung aus und klicke auf die Schaltfläche Anwendung hinzufügen.
- Wähle in dem daraufhin angezeigten Modal das Repository aus, das du bereitstellen möchtest. Wenn du mehrere Zweige hast, kannst du den gewünschten Zweig auswählen und einen Namen für deine Anwendung vergeben.
- Wähle einen der verfügbaren Rechenzentrumsstandorte.
- Füge die
OPENAI_API_KEY
als Umgebungsvariable hinzu. Kinsta wird automatisch ein Dockerfile für dich einrichten. - Zum Schluss fügst du im Feld für den Startbefehl
npm run build && npm run start
hinzu. Kinsta installiert die Abhängigkeiten deiner Anwendung aus der package.json und baut sie dann auf und stellt sie bereit.
Zusammenfassung
In dieser Anleitung hast du gelernt, wie du die DALL-E API von OpenAI für die Bilderzeugung nutzen kannst. Außerdem hast du gelernt, wie du mit React und Node.js arbeitest, um eine einfache Full-Stack-Anwendung zu erstellen.
Die Möglichkeiten von KI sind endlos, da täglich neue Modelle eingeführt werden und du erstaunliche Projekte erstellen kannst, die auf dem Anwendungs-Hosting von Kinsta bereitgestellt werden können.
Welches Modell würdest du gerne erforschen und über welches Projekt würden wir gerne als nächstes schreiben? Teile es uns in den Kommentaren unten mit.
Schreibe einen Kommentar