As the use of chatbots and virtual assistants continues to grow, many businesses and developers are looking for ways to create their own AI-powered chatbots. ChatGPT is one such chatbot, created by OpenAI, that is capable of engaging in human-like conversations and answering a wide range of questions.

What You’re Going To Build

In this tutorial, you will learn how to build a ChatGPT clone application using React and the OpenAI API. If you want to try your hand at a fun and engaging project over the weekend, this is a great opportunity to dive into React and OpenAI.

You will also learn how to deploy directly from your GitHub repository to Kinsta’s Application Hosting platform, which provides a free .kinsta.app domain to make your project go live swiftly. And with Kinsta’s free trial and Hobby Tier, you can easily get started without any cost.

Here’s a live demo of the ChatGPT clone application.

ChatGPT clone application
ChatGPT clone application.

If you’d like to inspect this project more closely, you can access its GitHub repository.

Alternatively, using this starter project template, you can select Use this template > Create a new repository — this will copy the starter code into a new repository. This starter project comes with fundamental elements such as styles, Font Awesome CDN link, OpenAi package, and basic structure to assist you in getting started.

Requirements/Prerequisites

This tutorial is designed to be a “follow-along” experience. Therefore, it’s recommended that you have the following to code alongside with ease:

What’s OpenAI API?

The OpenAI API is a cloud-based platform that grants developers access to OpenAI’s language models, such as GPT-3, via an API. It allows developers to add natural language processing features like text completion, sentiment analysis, summarization, and translation to their applications without developing and training their models.

To use the OpenAI API, developers must create an account on the OpenAI website and obtain an API key. The API key is used to authenticate API requests and track usage.

Once the API key is obtained, developers can use the API to submit text to the language model and receive responses.

Why React?

React is a popular JavaScript library for building user interfaces. According to the 2022 Stack Overflow developer survey, it is the second most commonly used web technology, with 42.62% of the market share.

React allows developers to create declarative components representing different parts of the user interface. These components are defined using a syntax called JSX, which is a combination of JavaScript and HTML.

Thanks to its large ecosystem of component libraries and kits, developers can easily work with and integrate APIs such as the OpenAI API, to build complex chat interfaces and that’s what makes it an excellent choice for building a ChatGPT clone application.

How To Set Up Your React Development Environment

The best way to install React or create a React project is to install it with create-react-app. One prerequisite is to have Node.js installed on your machine. To confirm that you have Node installed, run the following command in your terminal.

node -v

If it brings up a version, then it exists. To use npx, you’ll need to make sure your Node version is not less than v14.0.0, and your NPM version is not less than v5.6; else, you could need to update it by running npm update -g. Once you’ve figured out npm, you can now set up a React project by running the command below:

npx create-react-app chatgpt-clone

Note: “chatgpt-clone” is the application name we are creating, but you can change it to any name of your choice.

The installation process may take a few minutes. Once successful, you can navigate to the directory and install the Node.js OpenAI package, which provides convenient access to the OpenAI API from Node.js using the command below:

npm install openai

You can now run npm start to see your application live on localhost:3000.

When a React project is created using the create-react-app command, it automatically scaffolds a folder structure. The major folder that concerns you is the src folder, which is where development takes place. This folder contains many files by default but you should only be concerned with the App.js, index.js and index.css files.

  1. App.js: The App.js file is the main component in a React application. It typically represents the top-level component that renders all other components in the application.
  2. index.js: This file is the entry point of your React application. It is the first file loaded when the app is opened and is responsible for rendering the App.js component to the browser.
  3. index.css: This file is responsible for defining the overall styling and layout of your React application.

How To Build a ChatGPT Clone With React and OpenAI API

The ChatGPT clone application will consist of two components to make the application easier to understand and maintain. These two components are:

  1. Form Section: This component includes a text area field and a button for users to interact with the chatbot.
  2. Answer Section: The questions and corresponding answers will be stored in an array and displayed in this section. You will loop through the array chronologically, showing the latest first.

Setting Up the ChatGPT Clone Application

In this tutorial, let us start by first building the application interface and then you can implement functionality so your application interacts with the OpenAI API. Start by creating the two components you will use in this tutorial. For proper organization, you will create a components folder in the src folder where all the components will be stored.

The Form Section Component

This is a simple form that consists of a textarea and a submit 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;

This is what the form is expected to look like when you import it into your App.js file:

Form section component for ChatGPT clone
Form section component.

The Answer Section Component

This section is where all questions and answers will be displayed. This is what this section will look like when you also import it into your App.js file.

Answer section component of the ChatGPT clone
Answer section component.

You will fetch these questions and answers from an array and loop to make your code easier to read and maintain.

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

The Home Page

You now have both components created, but nothing will appear when you run your application because you need to import them into your App.js file. For this application, you will not implement any form of routing, meaning the App.js file will serve as your application’s home component/page.

You can add some content, like the title and description of your application, before importing the components.

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

In the code above, the two components are imported and added to the application. When you run your application, this is what your application will look like:

Complete ChatGPT clone application
Complete ChatGPT clone application.

Adding Functionality and Integrating OpenAI API

You now have the user interface of your application. The next step is to make the application functional so it can interact with the OpenAI API and get responses. First, you need to get the value from your form when submitted because it will be used to query the OpenAI API.

Getting Data From Form

In React, the best way to store and update data is to use states. In functional components, the useState() hook is used to work with states. You can create a state, assign the value from your form to the state, and update it whenever its value changes. Let’s start by importing the useState() hook into the FormSection.jsx component and then creating a state to store and update 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;

Next, you can assign the value of the textarea field to the state and create an onChange() event to update the state whenever the input value changes:

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

Finally, you can create an onClick() event, to load a function whenever the submit button is clicked. This method will be created in the App.js file and passed as a props into the FormSection.jsx component with the newQuestion and setNewQuestion values as arguments.

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

You have now created a state to store and update the form value, added a method which is passed as a props from the App.js file and handled click event. This is what the final code will look like:

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

The next step will be to create a method in the App.js file to handle the entire process of interacting with OpenAI API.

Interacting With OpenAI API

To interact with OpenAI API and obtain API keys in a React application, you must create an OpenAI API account. You can sign up for an account on the OpenAI website using your google account or email. To generate an API key, click Personal at the top-right corner of the website; some options will appear; click View API keys.

Access OpenAI API Keys
Access OpenAI API Keys.

Click the Create new secret key button, copy the key somewhere as you would use it in this application to interact with OpenAI. You can now proceed to initialize OpenAI by importing the openai package (you already installed) along with the configuration method. Then create a configuration with your generated key and use it to initialize 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;

In the code above, the OpenAI API key is stored as an environment variable in the .env file. You can create a .env file in the root folder of your application and store the key to the variable REACT_APP_OPENAI_API_KEY.

// .env
REACT_APP_OPENAI_API_KEY = sk-xxxxxxxxxx…

You can now proceed to create the generateResponse method in the App.js file, and pass in the two parameters expected from the form you already created to handle the request and get response from the 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;

You can now send a request to the OpenAI API. The OpenAI API can perform many operations, such as question and answer (Q&A), Grammar correction, translation and lots more. For each of these operations, the options are different. For example, the engine value for Q&A is text-davinci-00, while for SQL translate is code-davinci-002. Feel free to check the OpenAI example documentation for the various examples and their options.

For this tutorial, we are working only with the Q&A, this is what the option looks like:

{
  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: ["\"],
}

Note: I changed the prompt value.

The prompt is the question that is sent from the form. This means you will need to receive it from the form input you are passing into the generateResponse method as a parameter. To do this, you will define the options and then use the spread operator to create a complete option that includes the 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;

At this point, what is left is to send a request via the createCompletion method to OpenAI to get a response.

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

In the code above, the answer’s text will be displayed on your console. Feel free to test your application by asking any question. The final step would be to create a state that will hold the array of questions and answers and then send this array as a prop into the AnswerSection component. This is what the App.js final code will look like:

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

You can now edit the AnswerSection component, so it receives the props value from App.js and use the JavaScript Map() method to look through the storedValues array:

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

When you run your application and test it by asking questions, the answer will display below. But you will notice the copy button doesn’t work. You will need to add an onClick() event to the button, so it triggers a method to handle the functionality. You can use the navigator.clipboard.writeText() method to handle the functionality. This is what the AnswerSection component will now look like:

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

When you run your application, your ChatGPT clone application will work perfectly. You can now deploy your application to access it online and share it with friends.

How To Deploy Your React Application to Kinsta

It’s not enough to build this application and leave it on your local computers. You’ll want to share it online, so others can access it. Let’s see how to do this using GitHub and Kinsta.

Push Your Code to GitHub

To push your code to GitHub, you can use Git commands, which is a reliable and efficient way to manage code changes, collaborate on projects, and maintain version history.

The first step to push your codes will be to create a new repository by logging in to your GitHub account, clicking on the + button in the top right corner of the screen, and selecting New repository from the dropdown menu.

Create a new repository on GitHub
Create a new repository on GitHub.

Give your repository a name, add a description (optional), and choose whether you want it to be public or private. Click Create repository to create it.

Once your repository is created, ensure you obtain the repository URL from the main page of your repository, which you will need to push your code to GitHub.

Access your repository’s URL
Access your repository’s URL.

Open your terminal or command prompt and navigate to the directory that contains your project. Run the following commands one by one to push your code to your GitHub repository:

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

git init initializes a local Git repository, git add . adds all files in the current directory and its subdirectories to the new Git repository. git commit -m "my first commit" commits the changes to the repository with a brief message. git remote add origin [repository URL] sets the repository URL as the remote repository and git push -u origin master pushes the code to the remote repository (origin) in the master branch.

Deploy Your ChatGPT Clone React Application to Kinsta

To deploy your repository to Kinsta, follow these steps:

  1. Log in to or create your Kinsta account on the MyKinsta dashboard.
  2. Click Applications on the left sidebar and then click Add service.
  3. Select Application from the dropdown menu to deploy a React application to Kinsta.
  4. Select the repository you wish to deploy from the modal that appears. If you have multiple branches, you can choose the one you want to deploy and assign a name to the application. Select a data center location among the 25 available, and Kinsta will automatically detect a start command.
  5. Finally, it’s not safe to push out API keys to public hosts like GitHub, it was added as an environment variable locally. When hosting, you can also add it as an environment variable using the same variable name and the key as its value.
Deploying ChatGPT clone to Kinsta
Deploying ChatGPT clone to Kinsta.

Your application will start deploying, and within a few minutes, a link will be provided to access the deployed version of your application. In this case, this is https://chatgpt-clone-g9q10.kinsta.app/

Note: You can enable automatic deployment, so Kinsta will re-deploy your application whenever you change your codebase and push it to GitHub.


Summary

The OpenAI API can be used to build a wide range of potential applications, from customer support and personal assistants to language translation and content creation.

In this tutorial, you have learned how to build a ChatGPT clone application with React and OpenAI. You can integrate this application/feature into other applications to provide human-like conversational experiences to users.

There is more to what can be done with OpenAI API and how to improve this clone application. For example, you can implement local storage so that previous questions and answers do not disappear even after you refresh your browser.

With Kinsta’s free trial and Hobby Tier, you can easily get started without any cost on our Application Hosting. So why not give it a try and see what you can create?

Share your project and experiences in the comment below.

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.