How to Build a ChatBot Using OpenAI API: A Step-by-Step Guide

ABDERRAHIM BELCAID
9 min readMay 6, 2024

In this article, we will see how to create a custom chatbot using OpenAI Assistant API and Vercel AI SDK.

Introduction

AI chatbots are transforming how we interact with technology. These smart assistants understand our language, provide useful answers, and help with various tasks — from answering customer questions to automating routine jobs and improving digital experiences.

The launch of ChatGPT in 2022 simplifies chatbot creation by providing pre-trained models that understand and respond to human language, reducing the need for developers to build these capabilities from scratch.

This guide will show you how to build “BudgetBot MA,” a chatbot that offers insights into Moroccan finance law. Perfect for developers, business owners, or anyone interested in tech, this tutorial will help you tap into the latest AI advancements for practical uses.

https://budget-bot-ma.vercel.app

Prerequisites

Before we begin creating our chatbot, make sure you have the following:
1. Basic knowledge of Next.js, a framework for building full-stack applications.
2. Node.js version 18 or later.
3. An OpenAI account, which provides access to their API. This API empowers our chatbot with advanced AI features. Signing up is free and includes some credits to help you start experimenting.

Setting Up the OpenAI Assistant

After creating your OpenAI account, the first step is to obtain your API key, which enables communication with the OpenAI API.

Create a new API key

What is OpenAI Assistants API?

The Assistants API allows you to build AI assistants within your own applications.

An Assistant has instructions and can leverage models, tools, and files to respond to user queries. The Assistants API currently supports three types of tools: Code Interpreter, File Search, and Function calling. It’s designed to be flexible and powerful, allowing developers to build AI assistants that are tailored to specific use cases and workflows

Create a new OpenAI Assistant

1- Navigate to the Assistants tab: In the OpenAI web interface, there’s a dedicated tab for creating and managing assistants.
2- Create a new assistant: Click on the ‘Create’ button to start the process of Configure your assistant :

Name: Give your assistant a name that reflects its purpose in our case, it will be BudgetBot MA. not that an assistant key was automatically created “ asst_XXXXX”, save it cause we gonna use it later ;

Instructions: Define what your assistant is supposed to do. For example,

You are an AI assistant trained to analyze the finance law of Morocco from the years 2020 to 2024. Your capabilities include reading PDF documents, understanding complex financial legislation, and providing clear, concise answers to questions related to these documents..

When presented with a question, you will reference the specific finance law of Morocco document for the year in question, analyze the relevant sections, and provide an answer that directly addresses the user’s query. Your responses are based solely on the content of the documents from 2020 to 2024 and do not include personal opinions or external information.

Remember, your primary function is to assist users in understanding the finance law and to provide accurate information based on the documents from 2020 to 2024.
Do not engage in any conversation that isn’t related to the Morrocan finance law

Model: Choose a model like GPT-4 Turbo that suits your needs, keep in mind that each model has a specific price, which can be found here Pricing | OpenAI.

Tools: Enable tools such as ‘File search’ if your assistant needs to extract information from files, in our case we are going to choose code interpreter, this option allows us to run code, do the math, generate graphs…

Upload files: If your assistant requires specific files to work with, you can upload them during the creation process, in our case we will update those files :

Upload files

You can view the Assistant you’ve created in the Assistants Dashboard.

We can also create Assistants directly through the Assistants API (I will cover it in the next article ) like this :

import OpenAI from "openai";
const openai = new OpenAI();

async function main() {
const assistant = await openai.beta.assistants.create({
name: "Math Tutor",
instructions: "You are a personal math tutor. Write and run code to answer math questions.",
tools: [{ type: "code_interpreter" }],
model: "gpt-4-turbo"
});
}

main();

OpenAI Assistant Concepts

Assistant: An Assistant in the Assistants API is an entity configured to respond to user messages. It uses instructions, a chosen model, and tools to interact with functions and provide answers.

Thread: A Thread represents a conversation or dialogue in the Assistants API. It is created for each user interaction and can contain multiple Messages, serving as a container for the ongoing conversation.

Message: A Message is a unit of communication in a Thread. It contains text and is used to convey user queries or assistant responses within a Thread.

Run: A Run is an instance of the Assistant processing a Thread. It involves reading the Thread, deciding whether to call tools and generating responses based on the model’s interpretation of the Thread’s Messages.

How Assistants work

Testing our Assistant

To test the BudgetBot MA assistant we will use the OpenAI Playground which allows users to interact with the created assistant and test various AI models, It’s designed to facilitate learning, experimentation, and testing of AI functionalities without the need for advanced coding skills. Here’s what you can do with it:

1- Create a Thread: A Thread represents a conversation between a user and one or many Assistants. It’s created when a user starts a conversation with your Assistant.

2- Add Messages to the Thread: As the user interacts with the Assistant, their messages are added to the Thread. Each message can contain text and files.

3- Run the Assistant on the Thread: Once all user messages have been added, you can Run the Thread with the Assistant. This generates a response using the model and tools associated with the Assistant

4- Iterate and Experiment: Use the playground to quickly iterate and experiment with new ideas, refining your Assistant as needed

Integrating with Vercel AI SDK

Now we build and test our assistant, it’s time to build the chatbot project using Next.js and Vercel AI SDK.

The Vercel AI SDK is an open-source library designed to help developers build conversational streaming user interfaces.

It supports various frameworks and platforms, including React/Next.js, Svelte, and Vue.js offers hooks and APIs that further simplify integrations with various AI models and platforms, such as OpenAI, Azure OpenAI Service, LangChain, Mistral, LLamaCpp, and Google Gemini, allowing you to use these models in your frontend web applications

AI SDK Providers

Building the Frontend Application

Create a Next.js App:

npx create-next-app@latest budget-bot-ma
cd budget-bot-ma
npm run dev

Install dependencies

Since we are using OpenAI API to create our chatbot, we need to use the OpenAI Provider,

npm install ai openai

Configuring Environment Variables

For the OpenAI API and Assistant keys, you’ll need to configure environment variables to keep your keys secure.

  • Create a .env.local file in your project root.
  • Add your OpenAI API Key and Assistant key:
OPENAI_API_KEY=xxxxxxxxx
ASSISTANT_ID=xxxxxxxxx

Create a Route Handler

Create a route handler, “app/api/assistant/route.ts”, and add the following code:

import { AssistantResponse } from "ai";
import OpenAI from "openai";

const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY || "",
});
export async function POST(req: Request) {
// Parse the request body
const input: {
threadId: string | null;
message: string;
} = await req.json();
// Create a thread if needed
const threadId = input.threadId ?? (await openai.beta.threads.create({})).id;
// Add a message to the thread
const createdMessage = await openai.beta.threads.messages.create(threadId, {
role: "user",
content: input.message,
});
return AssistantResponse(
{ threadId, messageId: createdMessage.id },
async ({ forwardStream, sendDataMessage }) => {
// Run the assistant on the thread
const runStream = openai.beta.threads.runs.stream(threadId, {
assistant_id:
process.env.ASSISTANT_ID ??
(() => {
throw new Error("ASSISTANT_ID is not set");
})(),
});
// forward run status would stream message deltas
await forwardStream(runStream);
}
);
}

First, we need to import the AssistantResponse class from the “ai” module and the OpenAI class from the “openai” module

The next step is to initialize an instance of the OpenAI class. It uses an API key (stored in the .env.local file) to authenticate with the OpenAI service.

in the POST Request, we parse the incoming request body and extract two properties: threadId (if provided) and message.

If a threadId is provided, we will use it. Otherwise, we create a new thread using openai.beta.threads.create()

we need to add the user message to the thread using, the role and the message openai.beta.threads.messages.create().

  • The AssistantResponse then we initiate the assistant by creating a stream using openai.beta.threads.runs.stream().
  • The assistant’s responses are streamed back to the user using forwardStream

Forwards the assistant response stream to the client. Returns the Run object after it completes, or when it requires an action.

to know more about why streaming check : Advanced: Why Streaming? | Compare top AI models side-by-side (vercel.ai)

Creating a chatbot UI interface

Now that we have created our route hander, let’s make the chatbot UI interface, We will be using Tailwind CSS and shadcn/ui

Let’s create the chat interface in “app/page.tsx” :

"use client";

import { Message, useAssistant } from "ai/react";
// The rest of the import statements

export default function Home() {
const { status, messages, input, submitMessage, handleInputChange } =
useAssistant({ api: "/api/assistant" });
return (
<div>
{messages.map((m: Message) => (
<div key={m.id} className="flex gap-3 mt-3">
<span className="relative flex shrink-0 overflow-hidden rounded-full w-9 h-9">
<Image
width={25}
height={25}
src={roleAvatarMap[m.role]}
alt={""}
/>
</span>
<p className="leading-relaxed ">
<span className="block font-bold text-gray-700">{m.role}</span>
{m.content}
</p>
</div>
))}

{/* Rest of the UI code gose here... */}

<form
onSubmit={submitMessage}
className="flex items-center justify-center w-full space-x-2"
>
<input
disabled={status !== "awaiting_message"}
className="flex h-10 w-full rounded-md border border-[#e5e7eb] px-3 py-2 text-sm placeholder-[#6b7280] focus:outline-none focus:ring-2 focus:ring-[#9ca3af] disabled:cursor-not-allowed disabled:opacity-50 text-[#030712] focus-visible:ring-offset-2"
placeholder="Type your message"
value={input}
onChange={handleInputChange}
/>
<Button
type="submit"
className="inline-flex items-center justify-center rounded-md text-sm font-medium text-[#f9fafb] disabled:pointer-events-none disabled:opacity-50 bg-black hover:bg-[#111827E6] h-10 px-4 py-2"
>
Send
</Button>
</form>
</div>
);
}

The `useAssistant` hook allows you to manage the client state when interacting with an OpenAI assistant API. This hook is useful for integrating assistant capabilities into your application, with the UI automatically updating as the assistant streams its execution.

It interacts with a backend API (specified by `/api/assistant`) to send and receive messages. This process may involve fetching the initial conversation context, posting user messages to the server, and receiving responses from the AI.

State Management: The hook manages several state variables, such as:
status that Tracks the status of the chat, such as
‘awaiting_message’ ,‘in_progress’ . This can be used to control UI elements (e.g., disabling the input field when a message is being sent).
messages: An array of message objects representing the conversation history. Each message object may contain details like the sender’s role, content, and possibly a unique ID.
input: Holds the current value of the chat input field, allowing the user to type and submit messages.

submitMessage: Triggered when a user submits a new message, handling the sending of the message to the API.
handleInputChange: Updates the input state as the user types.

To know more about the useAssistant check this: AI SDK UI: useAssistant (vercel.ai)

Conclusion

Congratulations! You’ve now mastered the use of the OpenAI API and Vercel AI SDK to create a custom chatbot.

It’s time to put this knowledge into practice with your own projects — happy coding!

You can view the code and try out the chatbot for yourself here :

GitHub repository

https://budget-bot-ma.vercel.app

If this guide was helpful, feel free to share it with others!

For any questions or further discussion, reach out to me on Twitter or LinkedIn.

Thank you for reading!

Resources :

AI SDK UI: useAssistant (vercel.ai)

https://platform.openai.com/docs/assistants/overview

--

--