Dans le paysage dynamique de la technologie, où l’innovation repousse sans cesse les limites du possible, l’intelligence artificielle (IA) ne cesse de captiver notre imagination.

L’IA fait référence à la simulation des processus de l’intelligence humaine par des systèmes informatiques. Ces processus comprennent des tâches telles que l’apprentissage, le raisonnement, la résolution de problèmes, la perception, la compréhension du langage et la prise de décision.

Aujourd’hui, des individus et des entreprises ont développé et formé plusieurs modèles d’IA pour qu’ils accomplissent certaines tâches mieux que les humains en temps réel. Parmi les innombrables applications de l’IA, la génération d’images par l’IA est un domaine particulièrement intéressant.

Ce que vous construisez

Ce guide explique comment créer une application React qui s’intègre de manière transparente à l’API OpenAI DALL-E via un backend Node.js et génère des images captivantes à partir d’invites textuelles.

Générateur d'images IA en action, produisant des images vivantes et créatives à l'aide de l'API DALL-E.
Générateur d’images IA en action, produisant des images vivantes et créatives à l’aide de l’API DALL-E.

Pré-requis

Pour suivre ce projet, vous devez avoir :

Qu’est-ce que l’API OpenAI DALL-E ?

OpenAI API est une plateforme basée sur le cloud qui donne aux développeurs l’accès aux modèles d’IA pré-entraînés d’OpenAI, tels que DALL-E et GPT-3 (nous avons utilisé ce modèle pour construire un clone de ChatGPT avec le code dans ce dépôt Git). Il permet aux développeurs d’ajouter à leurs programmes des fonctions d’IA telles que le résumé, la traduction, la génération d’images et la modification, sans avoir à développer et à entraîner leurs modèles.

Pour utiliser l’API OpenAI, créez un compte à l’aide de votre compte Google ou de votre adresse e-mail sur le site web OpenAI et obtenez une clé API. Pour générer une clé API, cliquez sur Personnel dans le coin supérieur droit du site web, puis sélectionnez Voir les clés API.

Le processus de création d'une clé secrète de l'API OpenAI.
Le processus de création d’une clé secrète de l’API OpenAI.

Cliquez sur le bouton Créer une nouvelle clé secrète et enregistrez la clé quelque part. Vous l’utiliserez dans cette application pour interagir avec l’API DALL-E de l’OpenAI.

Configuration de l’environnement de développement

Vous pouvez créer une application React à partir de zéro et développer votre propre interface, ou vous pouvez utiliser notre modèle de démarrage Git en suivant ces étapes :

  1. Visitez le dépôt GitHub de ce projet.
  2. Sélectionnez Utiliser ce modèle > Créer un nouveau dépôt pour copier le code de démarrage dans un dépôt de votre compte GitHub (cochez la case pour inclure toutes les branches).
  3. Téléchargez le dépôt sur votre ordinateur local et passez à la branche starter-files à l’aide de la commande : git checkout starter-files.
  4. Installez les dépendances nécessaires en exécutant la commande npm install.

Une fois l’installation terminée, vous pouvez lancer le projet sur votre ordinateur local en lançant la commande npm run start. Le projet est alors disponible à l’adresse http://localhost:3000/.

Interface utilisateur d'une application de génération d'images d'IA illustrant la puissance de l'intelligence artificielle dans la création d'images.
Interface utilisateur d’une application de génération d’images d’IA illustrant la puissance de l’intelligence artificielle dans la création d’images.

Comprendre les fichiers du projet

Dans ce projet, nous avons ajouté toutes les dépendances nécessaires à votre application React. Voici un aperçu de ce qui a été installé :

  • file-server : Cette bibliothèque utilitaire simplifie le processus de téléchargement des images générées. Elle est liée au bouton de téléchargement, ce qui garantit une expérience utilisateur fluide.
  • uuid : Cette bibliothèque attribue une identification unique à chaque image. Cela permet d’éviter que des images partagent le même nom de fichier par défaut et de maintenir l’ordre et la clarté.
  • react-icons : Intégrée au projet, cette bibliothèque incorpore sans effort des icônes, améliorant ainsi l’attrait visuel de votre application.

Au cœur de votre application React se trouve le dossier src. C’est là que se trouve le code JavaScript essentiel pour Webpack. Comprenons les fichiers et les dossiers du dossier src:

  • assets : Dans ce répertoire, vous trouverez les images et le loader gif qui sont utilisés tout au long du projet.
  • data : Ce dossier contient un fichier index.js qui exporte un tableau de 30 invites. Ces invites peuvent être utilisées pour générer des images diverses et aléatoires. N’hésitez pas à le modifier.
  • index.css : C’est dans ce dossier que sont stockés les styles utilisés dans ce projet.

Comprendre le dossier Utils

Dans ce dossier, le fichier index.js définit deux fonctions réutilisables. La première fonction randomise la sélection des invites décrivant les différentes images qui peuvent être générées.

import { randomPrompts } from '../data';

export const getRandomPrompt = () => {
    const randomIndex = Math.floor(Math.random() * randomPrompts.length);
    const randomPrompt = randomPrompts[randomIndex];

    return randomPrompt;
}

La seconde fonction gère le téléchargement des images générées en tirant parti de la dépendance de file-saver. Ces deux fonctions ont été créées dans un souci de modularité et d’efficacité, et elles peuvent être importées dans des composants en cas de besoin.

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

Dans le code ci-dessus, la dépendance uuid donne à chaque fichier image généré un identifiant unique, afin qu’ils n’aient pas le même nom de fichier.

Comprendre les composants

Il s’agit de petits blocs de code séparés pour faciliter la maintenance et la compréhension de votre code. Pour ce projet, trois composants ont été créés : Header.jsx, Footer.jsx et Form.jsx. Le composant principal est le composant Form, dans lequel les données sont reçues et transmises au fichier App.jsx avec la fonction generateImage ajoutée en tant qu’évènement onClick au bouton Generate Image.

Dans le composant Form, un état est créé pour stocker et mettre à jour l’invite. En outre, une fonction vous permet de cliquer sur une icône aléatoire pour générer des invites aléatoires. Cela est possible grâce à la fonction handleRandomPrompt, qui utilise la fonction getRandomPrompt que vous avez déjà configurée. Lorsque vous cliquez sur l’icône, elle récupère une invite aléatoire et la met à jour dans l’état :

const handleRandomPrompt = () => {
    const randomPrompt = getRandomPrompt();
    setPrompt(randomPrompt)
}

Comprendre le fichier App.jsx

C’est dans ce fichier que réside la majeure partie du code. Tous les composants sont rassemblés ici. Il y a également une zone désignée pour afficher l’image générée. Si aucune image n’a encore été générée, une image de remplacement (image de prévisualisation) est affichée.

Dans ce fichier, deux états sont gérés :

  • isGenerating: Ceci permet de savoir si une image est en train d’être générée. Par défaut, il est défini sur false.
  • generatedImage: Cet état stocke des informations sur l’image qui a été générée.

En outre, la fonction utilitaire downloadImage est importée, ce qui vous permet de déclencher le téléchargement de l’image générée lorsque vous cliquez sur le bouton Download :

<button
    className="btn"
    onClick={() => downloadImage(generatedImage.photo)}
>

Maintenant que vous avez compris les fichiers de démarrage et que vous avez configuré votre projet. Commençons à gérer la logique de cette application.

Générer des images avec l’API DALL-E d’OpenAI

Pour exploiter les capacités de l’API DALL-E d’OpenAI, vous utiliserez Node.js pour établir un serveur. Au sein de ce serveur, vous créerez une route POST. Cette route sera chargée de recevoir le texte d’invite envoyé par votre application React et de l’utiliser pour générer une image.

Pour commencer, installez les dépendances nécessaires dans votre répertoire de projet en exécutant la commande suivante :

npm i express cors openai

De plus, installez les dépendances suivantes en tant que dépendances dev. Ces outils vous aideront à configurer votre serveur Node.js:

npm i -D dotenv nodemon

Les dépendances installées sont expliquées comme ci-dessous :

  • express : Cette bibliothèque permet de créer un serveur en Node.js.
  • cors : CORS facilite la communication sécurisée entre différents domaines.
  • openai : Cette dépendance vous donne accès à l’API DALL-E d’OpenAI.
  • dotenv : dotenv vous aide à gérer les variables d’environnement.
  • nodemon : nodemon est un outil de développement qui surveille les modifications apportées à vos fichiers et redémarre automatiquement le serveur.

Une fois les installations réussies, créez un fichier server.js à la racine de votre projet. C’est là que sera stocké tout le code de votre serveur.

Dans le fichier server.js, importez les bibliothèques que vous venez d’installer et instanciez-les :

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

Dans le code ci-dessus, vous importez les bibliothèques nécessaires. Ensuite, créez une instance de l’application Express à l’aide de const app = express();. Ensuite, activez CORS. Ensuite, Express est configuré pour traiter les données JSON entrantes, en spécifiant une limite de taille de données de 50mb.

Ensuite, une instance de la classe OpenAI est créée en utilisant votre clé API OpenAI. Créez un fichier .env à la racine de votre projet et ajoutez votre clé API en utilisant la variable OPENAI_API_KEY. Enfin, vous définissez une fonction asynchrone startServer et l’appelez pour mettre le serveur en mouvement.

Vous avez maintenant configuré votre fichier server.js. Créons une route POST que vous pouvez utiliser dans votre application React pour interagir avec ce serveur :

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

Dans ce code, la route est définie sur /api, et elle est conçue pour gérer les requêtes POST entrantes. Dans la fonction de rappel de la route, vous recevez les données envoyées par votre application React à l’aide de req.body – en particulier la valeur prompt.

Ensuite, la méthode images.generate de la bibliothèque OpenAI est invoquée. Cette méthode prend l’invite fournie et génère une image en réponse. Des paramètres tels que n déterminent le nombre d’images à générer (ici, une seule), size spécifie les dimensions de l’image et response_format indique le format dans lequel la réponse doit être fournie (b64_json dans ce cas).

Après avoir généré l’image, vous extrayez les données de l’image de la réponse et les stockez dans la variable image. Ensuite, vous renvoyez une réponse JSON à l’application React avec les données de l’image générée, en définissant le statut HTTP à 200 (indiquant le succès) à l’aide de res.status(200).json({ photo: image }).

En cas d’erreur au cours de ce processus, le code contenu dans le bloc catch est exécuté, en enregistrant l’erreur dans la console pour le débogage.

Le serveur est maintenant prêt ! Spécifions la commande qui sera utilisée pour exécuter notre serveur dans le fichier package.json de l’objet scripts:

"scripts": {
  "dev:frontend": "react-scripts start",
  "dev:backend": "nodemon server.js",
  "build": "react-scripts build",
},

Maintenant, lorsque vous lancez npm run dev:backend, votre serveur démarrera sur http://localhost:8080/, tandis que si vous lancez npm run dev:frontend, votre application React démarrera sur http://localhost:3000/. Assurez-vous que les deux s’exécutent dans des terminaux différents.

Effectuer des requêtes HTTP depuis React vers le serveur Node.js

Dans le fichier App.jsx, vous allez créer une fonction generateImage qui est déclenchée lorsque le bouton Generate Image est cliqué dans le composant Form.jsx. Cette fonction accepte deux paramètres : prompt et setPrompt du composant Form.jsx.

Dans la fonction generateImage, envoyez une requête HTTP POST au serveur Node.js :

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

Dans le code ci-dessus, vous vérifiez si le paramètre prompt a une valeur, puis vous définissez l’état isGenerating à true puisque l’opération commence. Cela fera apparaître le chargeur à l’écran car dans le fichier App.jsx, nous avons ce code qui contrôle l’affichage du chargeur :

{isGenerating && (
    <div> className="loader-comp">
        <img src={Loader} alt="" className='loader-img' />
    </div>
)}

Ensuite, utilisez la méthode fetch() pour faire une requête POST au serveur en utilisant http://localhost:8080/api – c’est la raison pour laquelle nous avons installé CORS car nous interagissons avec une API sur une autre URL. Nous utilisons l’invite comme corps du message. Extrayez ensuite la réponse renvoyée par le serveur Node.js et mettez-la à l’état generatedImage.

Une fois que l’état generatedImage a une valeur, l’image est affichée :

{generatedImage.photo ? (
    <img
        src={generatedImage.photo}
        alt={generatedImage.altText}
        className="imgg ai-img"
    />
) : (
    <img
        src={preview}
        alt="preview"
        className="imgg preview-img"
    />
)}

Voici à quoi ressemblera votre fichier App.jsx complet :

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;

Déployez votre application complète sur Kinsta

Jusqu’à présent, vous avez réussi à construire une application React qui interagit avec Node.js, ce qui en fait une application complète. Déployons maintenant cette application sur Kinsta.

Tout d’abord, configurez le serveur pour qu’il serve les fichiers statiques générés pendant le processus de construction de l’application React. Pour cela, importez le module path et utilisez-le pour servir les fichiers statiques :

const path = require('path');

app.use(express.static(path.resolve(__dirname, './build')));

Lorsque vous exécutez la commande npm run build && npm run dev:backend, votre application React complète se chargera à l’adresse http://localhost:8080/. C’est parce que l’application React est compilée dans des fichiers statiques dans le dossier build. Ces fichiers sont ensuite incorporés dans votre serveur Node.js en tant que répertoire statique. Par conséquent, lorsque vous exécutez votre serveur Node, l’application sera accessible.

Avant de déployer votre code sur le fournisseur Git que vous avez choisi (Bitbucket, GitHub ou GitLab), n’oubliez pas de modifier l’URL de requête HTTP dans votre fichier App.jsx. Remplacez http://localhost:8080/api par /api, car l’URL sera précédée d’un astérisque.

Enfin, dans votre fichier package.json, ajoutez une commande de script pour le serveur Node.js qui sera utilisé pour le déploiement :

"scripts": {
  // …
  "start": "node server.js",
},

Ensuite, poussez votre code vers votre fournisseur Git préféré et déployez votre dépôt sur Kinsta en suivant les étapes suivantes :

  1. Connectez-vous à votre compte Kinsta sur le tableau de bord MyKinsta.
  2. Sélectionnez Application dans la colonne latérale de gauche et cliquez sur le bouton Ajouter une application.
  3. Dans la fenêtre modale qui s’affiche, choisissez le dépôt que vous souhaitez déployer. Si vous avez plusieurs branches, vous pouvez sélectionner la branche souhaitée et donner un nom à votre application.
  4. Sélectionnez l’un des emplacements de centre de données disponibles.
  5. Ajoutez le site OPENAI_API_KEY comme variable d’environnement. Kinsta configurera automatiquement un fichier Docker pour vous.
  6. Enfin, dans le champ de commande de démarrage, ajoutez npm run build && npm run start. Kinsta installera les dépendances de votre application à partir de package.json, puis construira et déploiera votre application.

Résumé

Dans ce guide, vous avez appris à exploiter la puissance de l’API DALL-E d’OpenAI pour la génération d’images. Vous avez également appris à travailler avec React et Node.js pour construire une application full-stack de base.

Les possibilités sont infinies avec l’IA, car de nouveaux modèles sont introduits quotidiennement, et vous pouvez créer des projets étonnants qui peuvent être déployés sur l ‘hébergement d’applications de Kinsta.

Quel modèle aimeriez-vous explorer et sur quel projet aimeriez-vous que nous écrivions ? Partagez-les dans les commentaires ci-dessous.

Joel Olawanle Kinsta

Joel is a Frontend developer working at Kinsta as a Technical Editor. He is a passionate teacher with love for open source and has written over 200 technical articles majorly around JavaScript and it's frameworks.