DEV Community

Cover image for Another ChatGPT Post: How To Build and Deploy a ChatGPT Clone App With React and OpenAI API
Kinsta
Kinsta

Posted on • Originally published at kinsta.com

Another ChatGPT Post: How To Build and Deploy a ChatGPT Clone App With React and OpenAI API

Unless you’ve been living under a rock, you’re likely aware that AI-powered chatbots are popping up everywhere.

So why not build your own?

This guide will walk you through building a ChatGPT clone application using React and the OpenAI API.

Quick note: 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.

The 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.

Quick note: The free credit for using OpenAI’s API is limited to $18. If you’re testing this demo app and it stops working, it means the credit may have run out. To keep using the OpenAI API, you’ll need to upgrade your plan.

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:

  • Fundamental understanding of HTML, CSS, and JavaScript
  • Some familiarity with React
  • Node.js and npm (Node Package Manager) or yarn installed on your computer

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;
Enter fullscreen mode Exit fullscreen mode

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

Form section component

Quick note:
The focus of this tutorial is more on building and deploying your application. So you can copy the styles in the src/index.css file into your own project to get the same result/application.

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

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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

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;
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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 setNewQuestionvalues as arguments.

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

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;
Enter fullscreen mode Exit fullscreen mode

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.<br>

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;
Enter fullscreen mode Exit fullscreen mode

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…
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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: ["\"],
}
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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<br>

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

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
Enter fullscreen mode Exit fullscreen mode

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 masterpushes the code to the remote repository (origin) in the master branch.

Quick note:
You can replace “my first commit” with a brief message of your own describing the changes you made and “[repository URL]” with your GitHub repository’s URL. Once your code is pushed to GitHub, you can now deploy your repository to Kinsta.

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.

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.

And 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 comments below!

Top comments (0)