Table of contents
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.
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:
Form Section: This component includes a text area field and a button for users to interact with the chatbot.
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:
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.
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:
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.
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.
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.
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.
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:
Log in to or create your Kinsta account on the MyKinsta dashboard.
Click Applications on the left sidebar and then click Add service.
Select Application from the dropdown menu to deploy a React application to Kinsta.
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.
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 comment below.