How to Create Your Own AI Chatbot with OpenAI's API

Follow along with the video here:


Introduction

Are you curious about how to build your own chatbot? In this post, I’ll teach you how to use the same language models that ChatGPT uses to build your own AI Chatbot. I’ll go through the process on how to create your own app with the ChatGPT API as well as give you an app I already coded up where you just have to replace a value with your API key. Code is included.

Sign Up for OpenAI

The first thing you need to do is sign up for OpenAI. If you have used ChatGPT before, I’m assuming you already have an account. If not, go to openai.com and sign up. Once you have an account, we can start using the API. Let’s go through OpenAI’s quickstart example to see how we can hook everything up.

Quickstart Example

In this example, we will be using the completions endpoint of the OpenAI API. This endpoint accepts a text input and returns a response based on your input.

Example API Request & Response:

Prompt Completion
Write a tagline for an ice cream shop. We serve up smiles with every scoop!

Building the Quickstart Application

Assuming you have Node.JS installed, let’s copy OpenAI’s quickstart repo from Github.

git clone https://github.com/openai/openai-quickstart-node.git

Create a copy of the env file

cd openai-quickstart-node
cp .env.example .env

Generate an API key

alt text

Paste the API key into the .env file you created

alt text

Run the app

npm install
npm run dev

Open http://localhost:3000 in your browser and you should see this:

alt text

Putting in any animals should give you names for them. Now that you have familiarized yourself with using the API and have created an API key, let’s create our own chatbot.

Creating Your Own Chatbot

Setup

The first thing we need to do is setup our app. Our stack will be Node.JS as well as vanilla HTML/CSS/Javascript for simplicity.

Create the folder and Node app:

mkdir openaichatbot
npm init

Use the default for all the npm settings EXCEPT for the entry point. Change this to app.js.

alt text

Let’s create all of our files. Create a file structure that looks like this:

├── public
│   ├── js
│   │   ├── script.js
│   ├── index.html
├── app.js
├── package.json
├── package-lock.json 
└── .gitignore

Interface

The next thing we want to do is create the interface. In other words, let’s create all of the text-boxes and stuff we need for our app. I’ll be using Bootstrap 5.2 for this.

To start, our index.html file will look like this:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My Chatbot</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet"
        integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
</head>

<body>
    <div class="container mt-5 w-50">
        <h1 class="text-center">My Chatbot</h1>
        <div class="card">
            <div class="card-header">
                Chat History
            </div>
            <ul id="chat-history" class="list-group list-group-flush">
            </ul>

        </div>
        <div class="input-group">
            <span class="input-group-text">
                <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"
                    fill="currentColor" class="bi bi-person-circle" viewBox="0 0 16 16">
                    <path d="M11 6a3 3 0 1 1-6 0 3 3 0 0 1 6 0z" />
                    <path fill-rule="evenodd"
                        d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm8-7a7 7 0 0 0-5.468 11.37C3.242 11.226 4.805 10 8 10s4.757 1.225 5.468 2.37A7 7 0 0 0 8 1z" />
                </svg>&nbspYou
            </span>
            <textarea id="user-input" class="form-control" aria-label="With textarea"></textarea>
        </div>
        <div class="text-center">
            <button id="submit" type="button" class="btn btn-primary mt-2" >Submit Prompt</button>
            <div id="spinner" class="spinner-grow text-primary visually-hidden mt-2" role="status">
            </div>
        </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"
        integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous">
    </script>
    <script src="js/script.js"></script>
</body>

</html>

This will give us a simple text box and a button that looks like this: alt text

Backend

Let’s hook up the backend so we can make calls using the OpenAI API. First, we want to install our npm packages:

npm install openai
npm install express
npm install dotenv

In the previous quickstart example, we created a .env file. Copy this file over to our new chatbot directory and add a variable OPENAI_ORG. This is going to be your organization string which you can get from your organization settings.

Your .env file should look like this: alt text

Our app.js should look like this:

const openai = require('openai');
require('dotenv').config();
const express = require('express');
const path = require('path');
const app = express();
const port = 8080 || process.env.PORT;

app.use(express.json());
app.use(express.static('public'));
app.use(express.urlencoded({ extended: true }));

//Configure OpenAI
const configuration = new openai.Configuration({
    organization: process.env.OPENAI_ORG,
    apiKey: process.env.OPENAI_API_KEY,
});

const openaiapi = new openai.OpenAIApi(configuration);


app.get('/', (req, res) => {
    res.sendFile(path.join(__dirname, '/index.html'));
});

app.post('/chat', async (req, res) => {
    const messages = req.body.messages;
    const model = req.body.model;
    const temp = req.body.temp;

    const completion = await openaiapi.createChatCompletion({
        model: model,
        messages: messages,
        temperature: temp,
    });
    res.status(200).json({ result: completion.data.choices });
});

app.listen(port, () => {
    console.log(`Example app listening on port ${port}`);
});

Our script.js file will look like this:

//Get reference to our submit button and chatbot field
const submit = document.getElementById("submit");
const responseField = document.getElementById("response");
const userInput = document.getElementById("user-input");
const chatHistory = document.getElementById("chat-history");
const loading = document.getElementById("spinner");

let promptResponses = [];

//Our call to the API
const generateResponse = async () => {
    //Get the user input field value
    //Set loading spinner
    loading.classList.remove("visually-hidden");
    submit.classList.add("visually-hidden");
    const input = userInput.value;
    const response = await fetch('/chat', {
        method: 'POST',
        body: JSON.stringify({
            model: "gpt-3.5-turbo",
            messages: [{"role": "user", "content": input}],
            temp: 0.6
        }), 
        headers: {
            'Content-Type': 'application/json'
        }
    });

    const responseData = await response.json();
    const message = responseData.result[0].message.content;
    console.log(message);

    //Store our previous messages
    promptResponses.push({question: input, response: message});
    //Clear both fields
    userInput.value = "";

    const historyElement = document.createElement('div');
    historyElement.innerHTML = `<li class="list-group-item">Prompt: ${input}</li>
    <li class="list-group-item"> Response: ${message}</li>`;
    chatHistory.append(historyElement);

    //Stop loading spinner
    loading.classList.add("visually-hidden");
    submit.classList.remove("visually-hidden");

}

//Assign onclick method
submit.onclick = generateResponse;

Now that we have all of our files, all you have to do is start your node server:

node app.js

Visit http://localhost:8080/ in your browser and see our app at work :)

Here’s what it looks like: alt text

See if you can add a slider for temperature and a switcher to change models.

Get all of the code on Github here.

Ads

Written by

Daniel K.

Just me :)