À medida que o uso de chatbots e assistentes virtuais continua a crescer, muitas empresas e desenvolvedores estão procurando maneiras de criar seus próprios chatbots alimentados por inteligência artificial. O ChatGPT é um desses chatbots, criado pela OpenAI, capaz de se envolver em conversas humanas e responder a uma ampla variedade de perguntas.

Como construir um chatbot com React e OpenAI

Neste tutorial, você aprenderá como construir um aplicativo clone do ChatGPT usando React e a API da OpenAI. Se você quiser experimentar um projeto divertido e envolvente durante o fim de semana, esta é uma grande oportunidade para explorar o React e OpenAI.

Você também aprenderá como implantar diretamente do seu repositório GitHub na plataforma de Hospedagem de Aplicativos da Kinsta, que fornece um domínio .kinsta.app gratuito para fazer seu projeto entrar em funcionamento rapidamente. E com o teste gratuito e o Hobby Tier, você pode facilmente começar sem nenhum custo.

Aqui está uma demonstração do aplicativo clone do ChatGPT.

Aplicativo clone do ChatGPT
Aplicativo clone do ChatGPT

Se você gostaria de inspecionar este projeto mais de perto, você pode acessar seu repositório GitHub.

Alternativamente, usando este modelo de projeto inicial, você pode selecionar Use this template > Create a new repository – isso copiará o código inicial para um novo repositório. Este projeto inicial vem com elementos fundamentais, como estilos, link do Font Awesome CDN, pacote OpenAI e estrutura básica para ajudá-lo a começar.

Requisitos/Pré-requisitos

Este tutorial foi criado para que você possa acompanhar passo a passo. Por isso, é recomendável que você tenha o seguinte para poder codificar facilmente junto:

O que é OpenAI API?

O OpenAI API é uma plataforma baseada em nuvem que concede aos desenvolvedores acesso aos modelos de linguagem do OpenAI, como o GPT-3, através de uma API. Ela permite que os desenvolvedores adicionem recursos de processamento de linguagem natural, como conclusão de texto, análise de sentimentos, resumo e tradução aos seus aplicativos, sem desenvolver e treinar seus próprios modelos de IA.

Para usar a API da OpenAI, os desenvolvedores devem criar uma conta no site OpenAI e obter uma chave da API. A chave da API é usada para autenticar as solicitações da API e rastrear o uso.

Uma vez obtida a chave da API, os desenvolvedores podem usar a API para enviar texto para o modelo de linguagem e receber respostas.

Por que React?

React é uma popular biblioteca JavaScript para a construção de interfaces de usuário. De acordo com a pesquisa de desenvolvedores Stack Overflow 2022, ela é a segunda tecnologia web mais usada, com 42,62% de participação de mercado.

React permite que os desenvolvedores criem componentes declarativos representando diferentes partes da interface do usuário. Estes componentes são definidos usando uma sintaxe chamada JSX, que é uma combinação de JavaScript e HTML.

Graças ao seu grande ecossistema de bibliotecas de componentes e kits, os desenvolvedores podem facilmente trabalhar e integrar APIs como a API OpenAI, para construir interfaces de chat complexas e altamente personalizáveis, e isso é o que faz dela uma excelente escolha para a construção de um aplicativo clone do ChatGPT.

Como configurar o seu ambiente de desenvolvimento React

A melhor maneira de instalar o React ou criar um projeto React é instalá-lo com o create-react-app. Um pré-requisito é ter o Node.js instalado em sua máquina. Para confirmar que você tem o Node instalado, execute o seguinte comando em seu terminal.

node -v

Se ele traz uma versão, então ele existe. Para usar o npx, você precisará ter certeza de que sua versão do Node não é inferior à v14.0.0, e sua versão do NPM não é inferior à v5.6; caso contrário, você pode precisar atualizá-la executando npm update -g. Uma vez que você tenha descoberto o npm, você pode agora configurar um projeto React executando o comando abaixo:

npx create-react-app chatgpt-clone

Nota: “chatgpt-clone” é o nome do aplicativo que estamos criando, mas você pode mudá-lo para qualquer nome da sua escolha.

O processo de instalação pode demorar alguns minutos. Uma vez bem-sucedido, você pode navegar até o diretório e instalar o pacote Node.js OpenAI, que fornece acesso conveniente à OpenAI API a partir do Node.js usando o comando abaixo:

npm install openai

Agora você pode executar npm start para ver seu aplicativo em tempo real no localhost:3000.

Quando um projeto React é criado usando o comando create-react-app, ele automaticamente gera uma estrutura de pastas. A pasta principal que lhe diz respeito é a pasta src, que é onde o desenvolvimento acontece. Esta pasta contém muitos arquivos por padrão, mas você só deve se preocupar com os arquivos App.js, index.js e index.css.

  1. App.js: O arquivo App.js é o componente principal em um aplicativo React. Normalmente, ele representa o componente de nível superior que renderiza todos os outros componentes no aplicativo.
  2. index.js: Este arquivo é o ponto de entrada do seu aplicativo React. É o primeiro arquivo carregado quando o aplicativo é aberto e é responsável por renderizar o componente App.js para o navegador.
  3. index.css: Este arquivo é responsável por definir o estilo geral e o layout do seu aplicativo React.

Como construir um clone do ChatGPT com React e OpenAI API

O aplicativo clone do ChatGPT consistirá de dois componentes para tornar o aplicativo mais fácil de entender e manter. Estes dois componentes são:

  1. Seção de Formulário: Este componente inclui um campo de área de texto e um botão para os usuários interagirem com o chatbot.
  2. Seção de Resposta: As perguntas e respostas correspondentes serão armazenadas em um array e exibidas nesta seção. Você irá percorrer o array cronologicamente, mostrando o mais recente primeiro.

Configurando o aplicativo clone do ChatGPT

Neste tutorial, começaremos por construir primeiro a interface do aplicativo e depois você pode implementar funcionalidades para que seu aplicativo interaja com a API da OpenAI. Comece criando os dois componentes que você irá usar neste tutorial. Para uma organização adequada, você criará uma pasta de componentes na pasta src onde todos os componentes serão armazenados.

O componente da seção de formulário

Esta é uma forma simples que consiste em um textarea e uma submissão button.

// components/FormSection.jsx

const FormSection = () => {

    return (
        <div className="form-section">
            <textarea
                rows="5"
                className="form-control"
                placeholder="Ask me anything..."
            ></textarea>
            <button className="btn">
                Generate Response 🤖
            </button>
        </div>
    )
}

export default FormSection;

Aqui está como o formulário deve parecer quando você o importa para o arquivo App.js.

Componente da seção de formulário
Componente da seção de formulário

O componente da seção de resposta

Esta seção é onde todas as perguntas e respostas serão exibidas. Isso é o que esta seção parecerá quando você também a importar para o seu arquivo App.js.

Componente da seção de resposta
Componente da seção de resposta

Você irá buscar essas perguntas e respostas de um array e loop para tornar seu código mais fácil de ler e manter.

// components/AnswerSection.jsx

const AnswerSection = () => {
    return (
        <>
            <hr className="hr-line" />
            <div className="answer-container">
                <div className="answer-section">
                    <p className="question">Who is the founder of OpenAi?</p>
                    <p className="answer">OpenAI was founded in December 2015 by Elon Musk, Sam Altman, Greg Brockman, Ilya Sutskever, Wojciech Zaremba, and John Schulman.</p>
                    <div className="copy-icon">
                        <i className="fa-solid fa-copy"></i>
                    </div>
                </div>
            </div>
        </>
    )
}

export default AnswerSection;

A página principal

Agora você tem os dois componentes criados, mas nada aparecerá quando você executar o seu aplicativo, pois você precisa importá-los para o seu arquivo App.js. Para este aplicativo, você não implementará nenhum tipo de roteamento, o que significa que o arquivo App.js será o componente/página inicial do seu aplicativo.

Você pode adicionar algum conteúdo, como o título e descrição do seu aplicativo, antes de importar os componentes.

// App.js

import FormSection from './components/FormSection';
import AnswerSection from './components/AnswerSection';

const App = () => {
    return (
        <div>
            <div className="header-section">
                <h1>ChatGPT CLONE 🤖</h1>
                <p>
                    I am an automated question and answer system, designed to assist you
                    in finding relevant information. You are welcome to ask me any queries
                    you may have, and I will do my utmost to offer you a reliable
                    response. Kindly keep in mind that I am a machine and operate solely
                    based on programmed algorithms.
                </p>
            </div>

            <FormSection />
            <AnswerSection />
        </div>
    );
};

export default App;

No código acima, os dois componentes são importados e adicionados ao aplicativo. Quando você executar seu aplicativo, esta será a aparência:

Aplicativo clone do ChatGPT
Aplicativo clone do ChatGPT

Adicionando funcionalidade e integrando a API da OpenAI

Agora você tem a interface do usuário do seu aplicativo. O próximo passo é tornar o aplicativo funcional para que ela possa interagir com a API da OpenAI e obter respostas. Primeiro, você precisa obter o valor do seu formulário quando enviado, pois ele será usado para consultar a API da OpenAI.

Obtendo dados do formulário

Em React, a melhor maneira de armazenar e atualizar dados é usar os estados. Em componentes funcionais, o hook useState() é usado para trabalhar com estados. Você pode criar um estado, atribuir o valor do seu formulário ao estado e atualizá-lo sempre que o seu valor mudar. Começaremos importando o hook useState() para o componente FormSection.jsx e depois criar um estado para armazenar e atualizar newQuestions.

// components/FormSection.jsx

import { useState } from 'react';

const FormSection = ({ generateResponse }) => {
    const [newQuestion, setNewQuestion] = useState('');

    return (
        // Form to submit a new question
    )
}

export default FormSection;

Em seguida, você pode atribuir o valor do campo textarea ao estado e criar um evento onChange() para atualizar o estado sempre que o valor de entrada mudar:

<textarea
    rows="5"
    className="form-control"
    placeholder="Ask me anything..."
    value={newQuestion}
    onChange={(e) => setNewQuestion(e.target.value)}
></textarea>

Finalmente, você pode criar um evento onClick(), para carregar uma função sempre que o botão de envio for clicado. Este método será criado no arquivo App.js e será passado como um suporte no componente FormSection.jsx com os valores newQuestion e setNewQuestion como argumentos.

<button className="btn" onClick={() => generateResponse(newQuestion, setNewQuestion)}>
    Generate Response 🤖
</button>

Agora você criou um estado para armazenar e atualizar o valor do formulário, adicionou um método passado como uma propriedade do arquivo App.js e manipulou o evento de clique. É assim que o código final ficará:

// components/FormSection.jsx

import { useState } from 'react';

const FormSection = ({ generateResponse }) => {
    const [newQuestion, setNewQuestion] = useState('');

    return (
        <div className="form-section">
            <textarea
                rows="5"
                className="form-control"
                placeholder="Ask me anything..."
                value={newQuestion}
                onChange={(e) => setNewQuestion(e.target.value)}
            ></textarea>
            <button className="btn" onClick={() => generateResponse(newQuestion, setNewQuestion)}>
                Generate Response 🤖
            </button>
        </div>
    )
}

export default FormSection;

O próximo passo será criar um método no arquivo App.js para lidar com todo o processo de interação com a API da OpenAI.

Interagindo com a OpenAI API

Para interagir com o OpenAI API e obter chaves API em um aplicativo React, você deve criar uma conta OpenAI API. Você pode se inscrever em uma conta no site do OpenAI usando sua conta no Google ou e-mail. Para gerar uma chave API, clique em Personal no canto superior direito do site; algumas opções aparecerão; clique em View API keys.

Acesse as teclas API do OpenAI.
Acesse as teclas API do OpenAI.

Clique no botão Create new secret key, copie a chave em algum lugar como você a usaria neste aplicativo para interagir com o OpenAI. Agora você pode proceder para inicializar o OpenAI importando o pacote openAI (você já instalou) com o método de configuração. Então crie uma configuração com sua chave gerada e use-a para inicializar o OpenAI.

// src/App.js

import { Configuration, OpenAIApi } from 'openai';

import FormSection from './components/FormSection';
import AnswerSection from './components/AnswerSection';

const App = () => {
    const configuration = new Configuration({
        apiKey: process.env.REACT_APP_OPENAI_API_KEY,
    });

    const openai = new OpenAIApi(configuration);

    return (
        // Render FormSection and AnswerSection
    );
};

export default App;

No código acima, a chave API do OpenAI é armazenada como uma variável de ambiente no arquivo .env. Você pode criar um arquivo .env na pasta raiz do seu aplicativo e armazenar a chave para a variável REACT_APP_OPENAI_API_KEY.

// .env
REACT_APP_OPENAI_API_KEY = sk-xxxxxxxxxx…

Você pode agora proceder para criar o método generateResponse no arquivo App.js, e passar nos dois parâmetros esperados do formulário que você já criou para lidar com a solicitação e obter resposta da API.

// src/App.js

import FormSection from './components/FormSection';
import AnswerSection from './components/AnswerSection';

const App = () => {
    const generateResponse = (newQuestion, setNewQuestion) => {
        // Set up OpenAI API and handle response
    };

    return (
        // Render FormSection and AnswerSection
    );
};

export default App;

Agora você pode enviar uma solicitação para a API da OpenAI. A OpenAI API pode realizar muitas operações, como perguntas e respostas (Q&A), correção gramatical, tradução e muito mais. Para cada uma destas operações, as opções são diferentes. Por exemplo, o valor do mecanismo para perguntas e respostas é text-davinci-00, enquanto para a tradução SQL é code-davinci-002. Sinta-se livre para verificar a documentação de exemplo da OpenAI para os vários exemplos e suas opções.

Para este tutorial, estamos trabalhando apenas com as perguntas e respostas, esta é a opção:

{
  model: "text-davinci-003",
  prompt: "Who is Obama?",
  temperature: 0,
  max_tokens: 100,
  top_p: 1,
  frequency_penalty: 0.0,
  presence_penalty: 0.0,
  stop: [""],
}

Nota: Mudei o valor do prompt.

A prompt é a pergunta enviada pelo formulário. Isso significa que você precisará recebê-la a partir da entrada do formulário que está passando para o método generateResponse como um parâmetro. Para fazer isso, você definirá as opções e usará o operador spread para criar uma opção completa que inclua o prompt:

// src/App.js

import { Configuration, OpenAIApi } from 'openai';
import FormSection from './components/FormSection';
import AnswerSection from './components/AnswerSection';

const App = () => {
    const configuration = new Configuration({
        apiKey: process.env.REACT_APP_OPENAI_API_KEY,
    });

    const openai = new OpenAIApi(configuration);

    const generateResponse = async (newQuestion, setNewQuestion) => {
        let options = {
            model: 'text-davinci-003',
            temperature: 0,
            max_tokens: 100,
            top_p: 1,
            frequency_penalty: 0.0,
            presence_penalty: 0.0,
            stop: ['/'],
        };

        let completeOptions = {
            ...options,
            prompt: newQuestion,
        };

    };

    return (
         // Render FormSection and AnswerSection
    );
};

export default App;

Neste ponto, o que resta é enviar um pedido através do método createCompletion para a OpenAI para obter uma resposta.

// src/App.js

import { Configuration, OpenAIApi } from 'openai';
import FormSection from './components/FormSection';
import AnswerSection from './components/AnswerSection';

import { useState } from 'react';

const App = () => {
    const configuration = new Configuration({
        apiKey: process.env.REACT_APP_OPENAI_API_KEY,
    });

    const openai = new OpenAIApi(configuration);

    const [storedValues, setStoredValues] = useState([]);

    const generateResponse = async (newQuestion, setNewQuestion) => {
        let options = {
            model: 'text-davinci-003',
            temperature: 0,
            max_tokens: 100,
            top_p: 1,
            frequency_penalty: 0.0,
            presence_penalty: 0.0,
            stop: ['/'],
        };

        let completeOptions = {
            ...options,
            prompt: newQuestion,
        };

        const response = await openai.createCompletion(completeOptions);

        console.log(response.data.choices[0].text);
    };

    return (
        // Render FormSection and AnswerSection
    );
};

export default App;

No código acima, o texto da resposta será exibido no seu console. Sinta-se à vontade para testar seu aplicativo fazendo qualquer pergunta. O passo final seria criar um estado que irá armazenar a array de perguntas e respostas e então enviar essa array como uma propriedade para o componente AnswerSection. É assim que o código final do App.js ficará:

// src/App.js
import { Configuration, OpenAIApi } from 'openai';

import FormSection from './components/FormSection';
import AnswerSection from './components/AnswerSection';

import { useState } from 'react';

const App = () => {
    const configuration = new Configuration({
        apiKey: process.env.REACT_APP_OPENAI_API_KEY,
    });

    const openai = new OpenAIApi(configuration);

    const [storedValues, setStoredValues] = useState([]);

    const generateResponse = async (newQuestion, setNewQuestion) => {
        let options = {
            model: 'text-davinci-003',
            temperature: 0,
            max_tokens: 100,
            top_p: 1,
            frequency_penalty: 0.0,
            presence_penalty: 0.0,
            stop: ['/'],
        };

        let completeOptions = {
            ...options,
            prompt: newQuestion,
        };

        const response = await openai.createCompletion(completeOptions);

        if (response.data.choices) {
            setStoredValues([
                {
                    question: newQuestion,
                    answer: response.data.choices[0].text,
                },
                ...storedValues,
            ]);
            setNewQuestion('');
        }
    };

    return (
        <div>
            <div className="header-section">
                <h1>ChatGPT CLONE 🤖</h1>
                    <p>
                        I am an automated question and answer system, designed to assist you
                        in finding relevant information. You are welcome to ask me any
                        queries you may have, and I will do my utmost to offer you a
                        reliable response. Kindly keep in mind that I am a machine and
                        operate solely based on programmed algorithms.
                    </p>
            </div>

            <FormSection generateResponse={generateResponse} />

            <AnswerSection storedValues={storedValues} />
        </div>
    );
};

export default App;

Agora você pode editar o componente AnswerSection, para que ele recebe o valor das propriedades do App.js e utilize o método JavaScript Map() para procurar no array storedValues:

// components/AnswerSection.jsx

const AnswerSection = ({ storedValues }) => {
    return (
        <>
            <hr className="hr-line" />
            <div className="answer-container">
                {storedValues.map((value, index) => {
                    return (
                        <div className="answer-section" key={index}>
                            <p className="question">{value.question}</p>
                            <p className="answer">{value.answer}</p>
                            <div className="copy-icon">
                                <i className="fa-solid fa-copy"></i>
                            </div>
                        </div>
                    );
                })}
            </div>
        </>
    )
}

export default AnswerSection;

Quando você executar seu aplicativo e testá-la fazendo perguntas, a resposta será exibida abaixo. Mas você notará que o botão de cópia não funciona. Você precisará adicionar um evento onClick() ao botão, então ele aciona um método para lidar com a funcionalidade. Você pode usar o método navigator.clipboard.writeText() para lidar com a funcionalidade. É assim que o componente AnswerSection ficará:

// components/AnswerSection.jsx

const AnswerSection = ({ storedValues }) => {
    const copyText = (text) => {
        navigator.clipboard.writeText(text);
    };

    return (
        <>
            <hr className="hr-line" />
            <div className="answer-container">
                {storedValues.map((value, index) => {
                    return (
                        <div className="answer-section" key={index}>
                            <p className="question">{value.question}</p>
                            <p className="answer">{value.answer}</p>
                            <div
                                className="copy-icon"
                                onClick={() => copyText(value.answer)}
                            >
                                <i className="fa-solid fa-copy"></i>
                            </div>
                        </div>
                    );
                })}
            </div>
        </>
    )
}

export default AnswerSection;

Quando você executar seu aplicativo, seu aplicativo clone do ChatGPT funcionará perfeitamente. Agora você pode implantar seu aplicativo para acessá-la on-line e compartilhá-lo com seus amigos.

Como implementar seu aplicativo React na Kinsta

Não é suficiente construir este aplicativo e deixá-lo apenas em seus computadores locais. É importante que você o compartilhe on-line, para outras pessoas poderem acessá-lo. Para isso, mostraremos como utilizar o GitHub e Kinsta.

Enviando seu código para o GitHub

Para enviar seu código para o GitHub, você pode usar os comandos Git, uma maneira confiável e eficiente de gerenciar alterações de código, colaborar em projetos e manter o histórico de versões.

O primeiro passo para enviar seus códigos será criar um novo repositório fazendo login na sua conta GitHub, clicando no botão + no canto superior direito da tela, e selecionando New Repository no menu suspenso.

Criando um novo repositório no GitHub
Criando um novo repositório no GitHub

Dê um nome ao seu repositório, adicione uma descrição (opcional) e escolha se você quer que ele seja público ou privado. Clique em Create repository para criá-lo.

Assim que seu repositório estiver criado, certifique-se de obter a URL do repositório na página principal do seu repositório, pois você precisará dela para enviar seu código para o GitHub.

Acesse a URL do seu repositório
Acesse a URL do seu repositório

Abra seu terminal ou prompt de comando e navegue até o diretório que contém o seu projeto. Execute os seguintes comandos um a um para enviar seu código para o seu repositório GitHub:

git init
git add .
git commit -m "my first commit"
git remote add origin [repository URL]
git push -u origin master

git init inicializa um repositório Git local, git add . adiciona todos os arquivos no diretório atual e seus subdiretórios ao novo repositório Git. git commit -m "my first commit" submete as alterações ao repositório com uma breve mensagem. git remote add origin [repository URL] define a URL do repositório como o repositório remoto e git push -u origin master envia o código para o repositório remoto (origem) no branch master.

Implante seu aplicativo clone do ChatGPT React na Kinsta

Para implantar seu repositório na Kinsta, siga estes passos:

  1. Acesse ou crie sua conta Kinsta no painel MyKinsta.
  2. Clique em Aplicativos na barra lateral esquerda e depois clique em Adicionar serviço.
  3. Selecione Aplicativo no menu suspenso para implantar um aplicativo React na Kinsta.
  4. Selecione o repositório que você deseja implantar a partir do modal que aparece. Se você tiver várias branches, você pode escolher aquela que você deseja implantar e atribuir um nome para o aplicativo. Selecione um local do centro de dados entre os 25 disponíveis, e Kinsta detectará automaticamente um comando start.
  5. Finalmente, não é seguro enviar as chaves API para hosts públicos como o GitHub, ele foi adicionado como uma variável de ambiente localmente. Ao hospedar, você também pode adicioná-la como uma variável de ambiente usando o mesmo nome de variável e a chave como seu valor.
Implantando o clone do ChatGPT na Kinsta.
Implantando o clone do ChatGPT na Kinsta.

Seu aplicativo começará a ser implantado, e dentro de alguns minutos, um link será fornecido para acessar a versão implantada do seu aplicativo. Neste caso, será https://chatgpt-clone-g9q10.kinsta.app/

Note: Você pode habilitar a implantação automática, então Kinsta irá re-implantar seu aplicativo sempre que você mudar sua base de código e enviá-la para o GitHub.

Resumo

OpenAI API pode ser usado para construir uma ampla gama de aplicativos potenciais, desde suporte ao cliente e assistentes pessoais até tradução de idiomas e criação de conteúdo.

Neste tutorial, você aprendeu como construir um aplicativo clone do ChatGPT com React e OpenAI. Você pode integrar este aplicativo/funcionalidade em outros aplicativos para fornecer experiências de conversação de tipo humano aos usuários.

Existem outras possibilidades sobre o que pode ser feito com o OpenAI API e como melhorar este aplicativo clone. Por exemplo, você pode implementar armazenamento local para que as perguntas e respostas anteriores não desapareçam mesmo após atualizar o seu navegador.

Com o teste gratuito e o plano Hobby Tier da Kinsta, você pode começar a hospedar seu aplicativo sem custo algum. Então, por que não experimentar e ver o que você pode criar?

Compartilhe seu projeto e experiências nos comentários abaixo.

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.