Learn ChatGPT: Build a Live Chat Application with HTML, CSS, and JavaScript
Build a simple live chat application and have a conversation with AI. Is it sentient? Who knows. 🤷
What if I said you could learn ChatGPT in 15 minutes using only HTML, CSS and JavaScript? Some may think I'm crazy. I say, don't overthink it! It's a simple-to-use API and you could be building your next great app idea in a matter of minutes, not days. There are no fancy libraries or frameworks used in this example. Just good old-fashioned VanillaJS using AJAX.
Getting Started
The very first thing you need is an API key to authenticate your application with the OpenAI API. Visit the OpenAI developer website and create a new account. Once you're logged in make your way to the "View API keys" option in the account drop-down:
Click on + Create new secret key
and follow the steps to set it up. After all that is complete, we can move on to the fun part. Be sure to copy your API key out to a safe place, like a password manager, or just temporarily store it in a txt file. OpenAI will not show you this key again.
Step 1 - HTML Form and Chat Bubbles
For this, we'll take advantage of w3schools (queue shuttering from half of the development community) pre-built templates. There is nothing wrong with using your resources and taking advantage of the heavy lifting that has already been done for you.
I grabbed the chat styling code from the Learn how to create a chat message with CSS and the chat form from the How TO - Form with Icons tutorials on w3schools.com and then tweaked them a bit. We'll just put the HTML in place for step one. Create a folder somewhere and then make a new index.html
file and paste in the following code:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="style.css">
<script type="text/javascript" src="chatgpt.js"></script>
</head>
<body>
<h2>ChatGPT Messages</h2>
<form action="javascript:void(0)">
<div class="input-container">
<i class="fa fa-user icon"></i>
<input id="chatMessage"
class="input-field"
type="text"
placeholder="Enter message..."
name="usrnm">
</div>
</div>
<button type="submit"
id="sendBtn"
class="btn">Send</button>
</form>
<div id="loadingContainer"
class="container darker d-none">
<p>AI is thinking...</p>
</div>
<div id="chatOutput"></div>
</body>
</html>
The HTML here just sets up some containers where we'll dump in dynamically generated chat bubbles as the conversation progresses. Notice that I am prepending, rather than appending the new bubbles since my form is on top.
Step 2 - Some CSS Styling
The CSS is fairly straightforward. Again mostly coming from the w3schools examples with some minor tweaking to hide an element or make things more uniform. In the same folder that you added your index.html
file create another file and name it style.css
. Keep in mind if you name any of these files something other than what I am suggesting just swap out that file name in the <head>
section of your HTML file.
body {
margin: 0 auto;
max-width: 600px;
padding: 0 20px;
}
.container {
border: 2px solid #dedede;
background-color: #f1f1f1;
border-radius: 5px;
padding: 10px;
margin: 10px 0;
}
.user-container
{
text-align: right;
}
.darker {
border-color: #ccc;
background-color: #ddd;
}
.container::after {
content: "";
clear: both;
display: table;
}
.container img {
float: left;
max-width: 60px;
width: 100%;
margin-right: 20px;
border-radius: 50%;
}
.container img.right {
float: right;
margin-left: 20px;
margin-right: 0;
}
.time-right {
float: right;
color: #aaa;
}
.time-left {
float: left;
color: #999;
}
.input-container {
display: -ms-flexbox;
/* IE10 */
display: flex;
width: 100%;
margin-bottom: 15px;
}
.input-field {
width: 100%;
padding: 10px;
outline: none;
}
.input-field:focus {
border: 2px solid dodgerblue;
}
/* Set a style for the submit button */
.btn {
background-color: dodgerblue;
color: white;
padding: 15px 20px;
border: none;
cursor: pointer;
width: 100%;
opacity: 0.9;
}
.btn:hover {
opacity: 1;
}
.d-none
{
display: none;
}
Step 3 - Add JavaScript to Tie It All Together
Next, we'll add the file that makes all the magic happen. It's fairly straightforward if not a little hard on the eyes to look at. This is VanillaJS after all. I'll explain some of the parts after you get a chance to look at the whole file. Just like before make a new file in your folder and name it chatgpt.js
:
window.onload = function () {
const CHATGPT_API_KEY = "YOUR_API_KEY";
const CHATGPT_API_URL = "https://api.openai.com/v1/chat/completions";
var sendBtnElem = document.getElementById("sendBtn");
var chatMessageElem = document.getElementById("chatMessage");
var chatOutputElem = document.getElementById("chatOutput");
var loadingContainerElem = document.getElementById("loadingContainer");
sendBtnElem.addEventListener("click", function () {
var message = chatMessageElem.value;
if (message != null && message != "") {
generateUserChatBubble(message);
loadingContainerElem.classList.remove("d-none");
sendChatGPTMessage(message, generateAIChatBubble);
chatMessageElem.value = "";
} else {
alert("Please enter a message.");
}
});
function generateUserChatBubble(message) {
// Create a new chat bubble wrapper.
var chatBubbleElem = document.createElement("div");
chatBubbleElem.classList.add("container");
chatBubbleElem.classList.add("user-container");
// Create the message container.
var chatMessageElem = document.createElement("p");
chatMessageElem.innerHTML = message;
chatBubbleElem.appendChild(chatMessageElem);
chatOutputElem.prepend(chatBubbleElem);
}
function generateAIChatBubble(message) {
// Create a new chat bubble wrapper.
var chatBubbleElem = document.createElement("div");
chatBubbleElem.classList.add("container");
chatBubbleElem.classList.add("darker");
// Create the message container.
var chatMessageElem = document.createElement("p");
chatMessageElem.innerHTML = message;
chatBubbleElem.appendChild(chatMessageElem);
chatOutputElem.prepend(chatBubbleElem);
loadingContainerElem.classList.add("d-none");
}
function sendChatGPTMessage(message, onSuccessCallback) {
var messageBody = {
"model": "gpt-3.5-turbo",
"messages": [{
"role": "user",
"content": message.trim()
}]
};
const xhttp = new XMLHttpRequest();
xhttp.onload = function () {
// Parse the response body into JSON object.
var responseBodyObj = JSON.parse(this.responseText);
// I'm cheating a little as I know which property I need. I recommend making this more robust.
// If you want to see the response object itself then log it to the console and learn!
onSuccessCallback(responseBodyObj.choices[0].message.content);
}
xhttp.open("POST", CHATGPT_API_URL, true);
// Some simple headers are required for this to work properly with their API.
xhttp.setRequestHeader("Content-Type", "application/json");
xhttp.setRequestHeader("Authorization", "Bearer " + CHATGPT_API_KEY);
xhttp.send(JSON.stringify(messageBody));
}
};
Some of the more important parts here have to do with adding your API key, setting up some request headers in your AJAX call and then handling the async operation of that AJAX response using a callback function.
API Constants
const CHATGPT_API_KEY = "YOUR_API_KEY";
const CHATGPT_API_URL = "https://api.openai.com/v1/chat/completions";
The only thing you need to replace in this section is your API key. This will be used as a Bearer token value while we are sending requests to the OpenAI API.
Form Submit Handler
Technically, I'm not even using a form-submit event, here. I bypass the form action trigger by setting javascript:void(0)
as the action of the form. This is a super old hack and I don't recommend actually doing this in any production-ready project. Google to your heart's content on that one, if you so choose.
var sendBtnElem = document.getElementById("sendBtn");
...
sendBtnElem.addEventListener("click", function () {
var message = chatMessageElem.value;
if (message != null && message != "") {
generateUserChatBubble(message);
loadingContainerElem.classList.remove("d-none");
sendChatGPTMessage(message, generateAIChatBubble);
chatMessageElem.value = "";
} else {
alert("Please enter a message.");
}
});
To handle the click event of the Send
button we'll add an event listener. One added benefit of using a submit button inside of a form element like this is that the button will also be clicked if a user hits the enter key after typing their message. Little things like that make using applications a much better experience.
After our submit button has been clicked a few things happen: First, we grab the input value (e.g. the message the user typed) check if it's null or an empty string and then use some error handling if it is. It's always good practice to add logic to your code like this to help users understand what's going on while they are using the app. Second, we generate a new chat bubble that contains the message the user typed out. Finally, we send off the async request to the OpenAI API and wait for a response.
Note the use of a callback as a parameter during the call to the API. This is very useful when working with async programming because you don't need to worry about timing when a request finishes. You can guarantee that you'll handle your response message at exactly the moment the async call completes its work. This isn't a tutorial on async programming and you can learn more about the topic in my JavaScript Promises: Why and How post, if you're feeling adventurous.
The AJAX HTTP Request and OpenAI API Message Body (Say that ten times, fast)
I feel like this post may be getting a little long-winded. I promised you a messaging app in fifteen minutes, so let's wrap up all of the technical jargon with this last section. Here is where the really important steps happen. We use the JavaScript XMLHttpRequest
object to send a request to the OpenAI API and pass along a couple of simple headers and our request body. You can find more information on the body and response objects by poking around the OpenAI Developer Docs.
function sendChatGPTMessage(message, onSuccessCallback) {
var messageBody = {
"model": "gpt-3.5-turbo",
"messages": [{
"role": "user",
"content": message.trim()
}]
};
const xhttp = new XMLHttpRequest();
xhttp.onload = function () {
// Parse the response body into JSON object.
var responseBodyObj = JSON.parse(this.responseText);
// I'm cheating a little as I know which property I need. I recommend making this more robust.
// If you want to see the response object itself then log it to the console and learn!
onSuccessCallback(responseBodyObj.choices[0].message.content);
}
xhttp.open("POST", CHATGPT_API_URL, true);
// Some simple headers are required for this to work properly with their API.
xhttp.setRequestHeader("Content-Type", "application/json");
xhttp.setRequestHeader("Authorization", "Bearer " + CHATGPT_API_KEY);
xhttp.send(JSON.stringify(messageBody));
}
After you have all of the files and code in place load up your new index.html
page by opening it in a browser window. It should look like the following:
If you've wired everything up correctly and added in your API key you should be able to start having a conversation with the AI! I'll use the ever-classic Hello world! message as my first example.
If you got that to work congratulations! 🥳 You're now actively participating in the robot overlord takeover. (Just kidding, or am I?)
Summary
ChatGPT now holds the record for the fastest growing user base in history. There is an entire world of possibilities and new businesses being created every day that are leveraging this cutting-edge technology (AI in general, not just ChatGPT). I hope that you learned at least one new thing with this tutorial. And if you make anything really cool I'd love to see it in the comments below. If you enjoyed this, please consider following my blog and leaving some sort of reaction to it. It's very much appreciated.
Happy coding!
P.S.
I'm sure more than one of you is going to call me out for this so I'll just beat you to the punch. It's important to call out the fact that we're not actually using the newest version of ChatGPT with this sample application. Notice in the message body of the request we made to the API that the model used was gpt-3.5-turbo
. The newest (and all-the-rage) model that made the world go nuts is the GPT-4
model. You can view the different data models by visiting the OpenAI Models Overview. I didn't use the newest model because it's in Limited beta
and I am not a level 10 OpenAI codemaster so I don't get access to it, yet.