No cenário dinâmico da tecnologia, em que a inovação molda continuamente os limites do que é possível, a inteligência artificial (IA) nunca deixa de cativar nossa imaginação.
IA se refere à simulação de processos de inteligência humana em sistemas de computador. Esses processos incluem tarefas como aprendizado, raciocínio, solução de problemas, percepção, compreensão de linguagem e tomada de decisão.
Atualmente, indivíduos e empresas desenvolveram e treinaram vários modelos de IA para executar determinadas tarefas melhor do que os humanos em tempo real. Entre os inúmeros aplicativos de IA, uma área particularmente intrigante é a geração de imagens.
O que você está construindo
Este guia explica como criar um aplicativo React que se integra perfeitamente à API OpenAI DALL-E por meio de um backend Node.js e gera imagens cativantes com base em solicitações textuais.
Pré-requisitos
Para acompanhar este projeto, você deve ter:
- Conhecimento fundamental de HTML, CSS e JavaScript
- Conhecimento básico de React e Node.js
- Node.js e npm (Gerenciador de Pacotes do Node) ou yarn instalados em seu computador
O que é API OpenAI DALL-E?
A API da OpenAI é uma plataforma baseada em nuvem que concede aos desenvolvedores acesso aos modelos de IA pré-treinados da OpenAI, como o DALL-E e o GPT-3 (usamos esse modelo para criar um clone do ChatGPT com o código neste repositório Git). Ele permite que os desenvolvedores adicionem recursos de IA, como resumo, tradução, geração de imagens e modificação em seus programas sem precisar desenvolver e treinar seus próprios modelos.
Para usar a API da OpenAI, crie uma conta usando sua conta do Google ou e-mail no site da OpenAI e obtenha uma chave de API. Para gerar uma chave de API, clique em Personal (Pessoal) no canto superior direito do site e selecione View API keys (Exibir chaves de API).
Clique no botão Create new secret key (Criar nova chave secreta) e salve a chave em algum lugar. Você a usará neste aplicativo para interagir com a API DALL-E da OpenAI.
Configurando o ambiente de desenvolvimento
Você pode criar um aplicativo React do zero e desenvolver sua própria interface, ou pode pegar nosso template inicial do Git seguindo estas etapas:
- Visite o repositório do GitHub deste projeto.
- Selecione Use this template > Create a new repository para copiar o código inicial em um repositório dentro da sua conta GitHub. Marque a caixa para incluir todas as branches (include all branches).
- Puxe o repositório para o seu computador local e mude para o branch starter-files usando o comando:
git checkout starter-files
. - Instale as dependências necessárias executando o comando
npm install
.
Após a conclusão da instalação, você pode iniciar o projeto em seu computador local com npm run start
. Isso torna o projeto disponível em http://localhost:3000/.
Entendendo os arquivos de projeto
Neste projeto, adicionamos todas as dependências necessárias para o seu aplicativo React. Aqui está uma visão geral do que foi instalado:
- file-server: Essa biblioteca utilitária simplifica o processo de download das imagens geradas. Está vinculada ao botão de download, garantindo uma experiência de usuário tranquila.
- uuid: Essa biblioteca atribui uma identificação exclusiva a cada imagem. Isso evita qualquer possibilidade de as imagens compartilharem o mesmo nome de arquivo padrão, mantendo a ordem e a clareza.
- react-icons: Integrada ao projeto, essa biblioteca incorpora ícones sem esforço, aprimorando o apelo visual do seu aplicativo.
No centro do seu aplicativo React está a pasta src. É nela que o código JavaScript essencial para o Webpack está hospedado. Vamos entender os arquivos e as pastas dentro da pasta src:
- assets: Nesse diretório, você encontrará as imagens e o gif do carregador utilizados em todo o projeto.
- data: Essa pasta contém um arquivo index.js que exporta um array de 30 prompts. Esses prompts podem ser usados para gerar imagens diversas e aleatórias. Você pode editá-lo à vontade.
- index.css: É onde estão armazenados os estilos usados neste projeto.
Entendendo a pasta Utils
Dentro dessa pasta, o arquivo index.js define duas funções reutilizáveis. A primeira função randomiza a seleção de prompts que descrevem várias imagens que podem ser geradas.
import { randomPrompts } from '../data';
export const getRandomPrompt = () => {
const randomIndex = Math.floor(Math.random() * randomPrompts.length);
const randomPrompt = randomPrompts[randomIndex];
return randomPrompt;
}
A segunda função lida com o download das imagens geradas, aproveitando a dependência file-saver (salvador de arquivos). Ambas as funções foram criadas para oferecer modularidade e eficiência, e podem ser convenientemente importadas para os componentes quando necessário.
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`);
}
No código acima, a dependência uuid dá a cada arquivo de imagem gerado um ID exclusivo, para que eles não tenham o mesmo nome de arquivo.
Entendendo os componentes
Esses são pequenos blocos de código separados para facilitar a manutenção e a compreensão do código. Para este projeto, foram criados três componentes: Header.jsx, Footer.jsx e Form.jsx. O componente principal é o componente Form, no qual a entrada é recebida e passada para o arquivo App.jsx com a função generateImage
adicionada como um evento onClick
ao botão Generate Image.
No componente Form, é criado um estado para armazenar e atualizar o prompt. Além disso, um recurso permite que você clique em um ícone aleatório para gerar os prompts aleatórios. Isso é possível com a função handleRandomPrompt
, que usa a função getRandomPrompt
que você já configurou. Quando você clica no ícone, ela obtém um prompt aleatório e atualiza o estado com ele:
const handleRandomPrompt = () => {
const randomPrompt = getRandomPrompt();
setPrompt(randomPrompt)
}
Entendendo o arquivo App.jsx
É aqui que reside a maior parte do código. Todos os componentes são reunidos aqui. Há também uma área designada para exibir a imagem gerada. Se nenhuma imagem tiver sido gerada ainda, será exibida uma imagem de espaço reservado (Preview image).
Dentro desse arquivo, dois estados são gerenciados:
isGenerating
: Mantém o controle sobre se uma imagem está sendo gerada no momento. Por padrão, ele é definido como falso.generatedImage
: Esse estado armazena informações sobre a imagem que foi gerada.
Além disso, a função do utilitário downloadImage
é importada, permitindo que você acione o download da imagem gerada quando clicar no botão Download:
<button
className="btn"
onClick={() => downloadImage(generatedImage.photo)}
>
Agora que você entendeu os arquivos iniciais e configurou o projeto, vamos começar a lidar com a lógica desse aplicativo.
Geração de imagens com a API DALL-E da OpenAI
Para aproveitar os recursos da API DALL-E da OpenAI, você usará o Node.js para estabelecer um servidor. Você criará uma rota POST dentro desse servidor. Essa rota será responsável por receber o texto do prompt enviado pelo seu aplicativo React e, em seguida, utilizá-lo para gerar uma imagem.
Para começar, instale as dependências necessárias no diretório do seu projeto executando o seguinte comando:
npm i express cors openai
Além disso, instale as seguintes dependências como dependências de desenvolvimento. Essas ferramentas ajudarão você a configurar seu servidor Node.js:
npm i -D dotenv nodemon
As dependências instaladas são explicadas a seguir:
- express: Essa biblioteca ajuda a criar um servidor no Node.js.
- cors: O CORS facilita a comunicação segura entre domínios diferentes.
- openai: Essa dependência concede a você acesso à API DALL-E da OpenAI.
- dotenv: O dotenv o ajuda a gerenciar variáveis de ambiente.
- nodemon: É uma ferramenta de desenvolvimento que monitora as alterações em seus arquivos e reinicia automaticamente o servidor.
Quando as instalações forem bem-sucedidas, crie um arquivo server.js na raiz do seu projeto. É nele que todo o código do servidor será armazenado.
No arquivo server.js, importe as bibliotecas que você acabou de instalar e as instancie:
// 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();
No código acima, você importa as bibliotecas necessárias. Em seguida, estabelece uma instância do aplicativo Express usando const app = express();
. Depois disso, habilite o CORS. Em seguida, o Express é configurado para processar dados JSON de entrada, especificando um limite de tamanho de dados de 50mb
.
Depois disso, uma instância da classe OpenAI é criada utilizando sua chave de API OpenAI. Crie um arquivo .env na raiz do seu projeto e adicione sua chave de API usando a variável OPENAI_API_KEY
. Por fim, você define uma função assíncrona startServer
e a chama para colocar o servidor em movimento.
Agora você configurou o arquivo server.js. Vamos criar uma rota POST que você pode usar em seu aplicativo React para interagir com esse servidor:
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);
}
});
Neste código, a rota está definida como /api
e foi projetada para lidar com solicitações POST de entrada. Dentro da função de callback da rota, você recebe os dados enviados do seu aplicativo React usando req.body
— especificamente o valor prompt
.
Em seguida, o método images.generate
da biblioteca OpenAI é chamado. Esse método recebe o prompt fornecido e gera uma imagem em resposta. Parâmetros como n
determinam o número de imagens a serem geradas (aqui, apenas uma), size
especifica as dimensões da imagem e response_format
indica o formato no qual a resposta deve ser fornecida (b64_json
, neste caso).
Após gerar a imagem, você extrai os dados da imagem da resposta e os armazena na variável image
. Em seguida, você envia uma resposta JSON de volta ao aplicativo React com os dados da imagem gerada, definindo o status HTTP como 200
(indicando sucesso) usando res.status(200).json({ photo: image })
.
Em caso de erros durante esse processo, o código no bloco catch
é executado, registrando o erro no console para depuração.
Agora o servidor está pronto! Vamos especificar o comando que será usado para executar nosso servidor no objeto scripts
do arquivo package.json:
"scripts": {
"dev:frontend": "react-scripts start",
"dev:backend": "nodemon server.js",
"build": "react-scripts build",
},
Agora, quando você executar npm run dev:backend
, seu servidor será iniciado em http://localhost:8080/, ao passo que, se você executar npm run dev:frontend
, seu aplicativo React será iniciado em http://localhost:3000/. Certifique-se de que ambos estejam sendo executados em terminais diferentes.
Fazer solicitações HTTP do React para o servidor Node.js
No arquivo App.jsx, você criará uma função generateImage
que é acionada quando o botão Generate Image é clicado no componente Form.jsx. Essa função aceita dois parâmetros: prompt
e setPrompt
do componente Form.jsx.
Na função generateImage
, você fará uma solicitação HTTP POST para o servidor 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');
}
};
No código acima, você verifica se o parâmetro prompt
tem um valor e, em seguida, define o estado isGenerating
como true
, pois a operação está sendo iniciada. Isso fará com que o loader seja exibido na tela porque, no arquivo App.jsx, temos este código que controla a exibição do loader:
{isGenerating && (
<div> className="loader-comp">
<img src={Loader} alt="" className='loader-img' />
</div>
)}
Em seguida, use o método fetch()
para fazer uma solicitação POST ao servidor usando http://localhost:8080/api — é por isso que instalamos o CORS, pois estamos interagindo com uma API em outra URL. Usamos o prompt como o corpo da mensagem. Em seguida, extraia a resposta retornada do servidor Node.js e defina-a como o estado generatedImage
.
Quando o estado generatedImage
tiver um valor, a imagem será exibida:
{generatedImage.photo ? (
<img
src={generatedImage.photo}
alt={generatedImage.altText}
className="imgg ai-img"
/>
) : (
<img
src={preview}
alt="preview"
className="imgg preview-img"
/>
)}
É assim que você verá o arquivo App.jsx completo:
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;
Implantar seu aplicativo full-stack na Kinsta
Até agora, você criou com sucesso um aplicativo React que interage com o Node.js, o que o torna um aplicativo full-stack. Agora vamos implantar esse aplicativo na Kinsta.
Primeiro, configure o servidor para servir os arquivos estáticos gerados durante o processo de build do aplicativo React. Para isso, você deve importar o módulo path
e usá-lo para servir os arquivos estáticos:
const path = require('path');
app.use(express.static(path.resolve(__dirname, './build')));
Quando você executar o comando npm run build && npm run dev:backend
, seu aplicativo React de full-stack será carregado em http://localhost:8080/. Isso ocorre porque o aplicativo React é compilado em arquivos estáticos dentro da pasta build. Esses arquivos são então incorporados ao seu servidor Node.js como um diretório estático. Consequentemente, quando você executar o servidor Node, o aplicativo estará acessível.
Antes de implementar o código no provedor Git que você escolheu (Bitbucket, GitHub ou GitLab), lembre-se de modificar a URL de solicitação HTTP no arquivo App.jsx. Altere http://localhost:8080/api
para /api
, pois a URL será anexada.
Por fim, no seu arquivo package.json, adicione um comando de script para o servidor Node.js que seria usado para a implantação:
"scripts": {
// …
"start": "node server.js",
},
Em seguida envie seu código para o provedor Git de sua preferência e implantar seu repositório na Kinsta seguindo estas etapas:
- Faça login em sua conta Kinsta no painel MyKinsta.
- Selecione Aplicativo na barra lateral esquerda e clique no botão Adicionar aplicativo.
- No modal que aparece, escolha o repositório que você deseja implantar. Se você tiver vários branches, poderá selecionar o branch desejado e dar um nome ao seu aplicativo.
- Selecione um dos locais de centros de dados disponíveis.
- Adicione o endereço
OPENAI_API_KEY
como uma variável de ambiente. A Kinsta configurará um Dockerfile automaticamente para você. - Por fim, no campo de comando start, adicione
npm run build && npm run start
. A Kinsta instalará as dependências do seu aplicativo a partir do package.json e, em seguida, criará e implantará seu aplicativo.
Resumo
Neste guia você aprendeu a aproveitar o poder da API DALL-E da OpenAI para geração de imagens. Também aprendeu a trabalhar com React e Node.js para criar um aplicativo full-stack básico.
As possibilidades são infinitas com a IA, pois novos modelos são introduzidos diariamente, e você pode criar projetos incríveis que podem ser implementados na hospedagem de aplicativos da Kinsta.
Que modelo você gostaria de explorar e sobre qual projeto gostaria que escrevêssemos a seguir? Compartilhe nos comentários abaixo.
Deixe um comentário