Building a SQL Expert Bot: A Step-by-Step Guide with Vercel AI SDK and OpenAI API
Tags: ai, openai, chatgpt, vercel
Published: 2024-03-06 06:22:12

OpenAI has brought the revolution in the AI field by creating the ChatGPT and now we can say the actual AI era has started and everyone from individuals to businesses using AI.

OpenAI has even created an API to build custom AI solutions like chatbots, assistants, and more. We can access the APIs using SDKs provided by OpenAI for different programming languages. There are also wrappers built on top of the API to help you build the interface easily.

Vercel has built an AI SDK for constructing the streaming user interface with TypeScript and JavaScript. The best part is that it is open-source and has support for Vercel Edge runtime.

In this article, we will build a SQL Expert ChatBot using the OpenAI API and Vercel AI SDK. We will discuss streaming responses, custom prompts, and much more.

## Setup OpenAI Account

First, we will need to create an account on OpenAI and get an API key. You can sign up for a free account on OpenAI's website. Once you're logged in, go to the `API keys` section in the menu on the left side of the screen. From there, you can create a new API key. I have created one and named it `vercel-ai-sdk`, but you can choose any name you like.

![openai-api-keys](https://cdn.hashnode.com/res/hashnode/image/upload/v1709435521070/3455d296-ea6a-4f8c-b800-095285be818f.png)

Okay, now that we have the OpenAI API key, let's move on to the next section where we will talk about the Vercel AI SDK and how to set it up on your computer.

## Setup Vercel AI SDK

The [Vercel AI SDK](https://sdk.vercel.ai/docs) is built for OpenAI APIs and includes a range of tools for utilizing OpenAI APIs.

To begin, let's create a Next.js application and install the dependencies `ai` for the Vercel AI SDK and `openai` for the OpenAI API client.

```bash
pnpm dlx create-next-app ai-sql-expert
cd ai-sql-expert
pnpm install ai openai
```

Make sure to have the same configuration as shown in the image below

![nextjs-config](https://cdn.hashnode.com/res/hashnode/image/upload/v1709397853508/8cd2f4ad-619f-4b80-8ad6-ccf0145b398b.png)

Create a `.env` file in your project root and add your OpenAI API Key

```bash
OPENAI_API_KEY=xxxxxxxxx
```

Great, now that we have set up the OpenAI and Vercel AI SDKs, let's proceed to create API routes and a user interface for our SQL Expert Bot.

## Create API Routes

We will set up an API route to manage user message requests. When a user sends a message, the OpenAI API will process it and send a response back to Next.js.

Create a file named `route.ts` inside the `api/chat` folder in your project's `src/app` directory. Then, add the following code snippet

```typescript
# app/api/chat/route.ts

import OpenAI from 'openai';
import { OpenAIStream, StreamingTextResponse } from 'ai';

const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
});

export const runtime = 'edge';

export async function POST(req: Request) {
  const { messages } = await req.json();

  const response = await openai.chat.completions.create({
    model: 'gpt-3.5-turbo',
    stream: true,
    messages,
  });

  const stream = OpenAIStream(response);
  return new StreamingTextResponse(stream);
}
```

This section is for setting up the OpenAI instance by providing the API key.

```typescript
const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
});
```

By adding this line, we are instructing Next.js to utilize edge runtime for processing the API requests.

```typescript
export const runtime = 'edge';
```

The `POST` function extracts the `messages` field from the JSON payload sent in the request.

It then uses the `openai.chat.completions.create` method to send these messages to OpenAI's `GPT-3.5-turbo` model for processing. This method creates completions (responses) based on the provided messages.

The `stream` parameter is set to `true`, indicating that the responses should be streamed back to the client in real time.

After receiving the response from OpenAI, the code converts it into a friendly text stream using a function called `OpenAIStream`.

Finally, the function constructs a response using the `StreamingTextResponse` class and returns it. This response contains the streamed text generated by OpenAI in response to the user's messages.

```typescript
export async function POST(req: Request) {
  const { messages } = await req.json();

  const response = await openai.chat.completions.create({
    model: 'gpt-3.5-turbo',
    stream: true,
    messages,
  });

  const stream = OpenAIStream(response);
  return new StreamingTextResponse(stream);
}
```

Okay, we have created the API route to handle user requests and process messages with the OpenAI API. Next, we will move on to creating the user interface for our SQL Expert Bot.

## Create The User Interface

Before adding code for the user interface we will add the contants for initial chat messages which we will be using as custom prompt for our bot to set it's behaviour.

Create `constant/chat.constants.ts` in the project's `src/app` directory. Then, add the following code snippet

```typescript
import { Message } from 'ai/react';

export const INITIAL_MESSAGES: Message[] = [
  {
    id: '',
    role: 'system',
    content: `You are an SQL expert. you can write generate SQL queries for any given problem statement.
        Make sure to return the query with proper formatting and indentation.
        Make sure to return the query with proper explanation and comments.
        If you are not able to solve the problem, you can ask for more details.
        If user is not able to understand the query, you can explain the query in simple words.
        If user is providing wrong prompt, you can ask for correct prompt.
        `,
  },
];
```

We are providing instructions to the system on how to behave in various scenarios, determining the appropriate responses, and specifying how these responses should be delivered.

Next, add the following code snippet in `src/app/pages.tsx`.

```typescript
'use client';

import { useChat } from 'ai/react';
import Markdown from 'react-markdown';
import { INITIAL_MESSAGES } from './constant/chat.constants';

export default function Chat() {
  const { messages, input, handleInputChange, handleSubmit } = useChat({
    initialMessages: INITIAL_MESSAGES,
  });
  return (
    <div>
      <div className="text-center py-8">
        <h2 className="text-center text-2xl font-bold mb-2">SQL Expert</h2>
        <p>
          Welcome to the SQL Expert. You can ask any SQL related questions and
          expert will help you out.
        </p>
      </div>

      <div className="flex flex-col w-full max-w-2xl pb-24 mx-auto stretch gap-4">
        {messages
          .filter((m) => m.role !== 'system')
          .map((m) => (
            <div
              key={m.id}
              className="bg-gray-100 p-4 rounded flex gap-2 flex-col"
            >
              <span className="font-medium">
                {m.role === 'user' ? 'You' : 'Expert'}
              </span>
              <Markdown>{m.content}</Markdown>
            </div>
          ))}

        <form
          className="flex gap-4 fixed bottom-0 w-full mb-8"
          onSubmit={handleSubmit}
        >
          <input
            autoFocus
            className="p-2 border border-gray-300 rounded shadow-xl outline-purple-500 focus:outline-none focus:ring-2 focus:ring-purple-500 flex-grow max-w-xl"
            value={input}
            placeholder="Ask your SQL related question.."
            onChange={handleInputChange}
          />

          <button
            className="border p-2 px-4 rounded shadow-xl border-gray-300 bg-purple-500 text-white"
            type="submit"
          >
            Send
          </button>
        </form>
      </div>
    </div>
  );
}
```

We will use a client component to display messages and a form for users to send their messages.

```typescript
'use client';
```

Since the API will return the response with markdown content, we will utilize `react-markdown` to parse the markdown content.

```typescript
import Markdown from 'react-markdown';
```

The `useChat` hook helps you create a chat interface for your chatbot app. It makes it simple to show messages from your AI provider, handle chat input, and update the UI when new messages come in. It accepts a bunch of options, and for our case, we are using the `initialMessages` option to set the system's behavior.

```typescript
import { useChat } from 'ai/react';

const { messages, input, handleInputChange, handleSubmit } = useChat({
    initialMessages: INITIAL_MESSAGES,
  });
```

This part is for displaying the messages we receive from the API. We have set a custom prompt for the `system`, so we will filter it out and only show the `user` and `expert` messages.

```xml
<div className="flex flex-col w-full max-w-2xl pb-24 mx-auto stretch gap-4">
        {messages
          .filter((m) => m.role !== 'system')
          .map((m) => (
            <div
              key={m.id}
              className="bg-gray-100 p-4 rounded flex gap-2 flex-col"
            >
              <span className="font-medium">
                {m.role === 'user' ? 'You' : 'Expert'}
              </span>
              <Markdown>{m.content}</Markdown>
            </div>
          ))}
...
</div>
```

Finally, we have the form for users to send their messages. We are using the `handleSubmit` function provided by the `useChat` hook to listen for the form submit event.

For the input field, we are using `handleInputChange` and `input` to control the input value.

Then, we have a button for submitting the form.

```xml
<div className="flex flex-col w-full max-w-2xl pb-24 mx-auto stretch gap-4">
        ...
        <form
          className="flex gap-4 fixed bottom-0 w-full mb-8"
          onSubmit={handleSubmit}
        >
          <input
            autoFocus
            className="p-2 border border-gray-300 rounded shadow-xl outline-purple-500 focus:outline-none focus:ring-2 focus:ring-purple-500 flex-grow max-w-xl"
            value={input}
            placeholder="Ask your SQL related question.."
            onChange={handleInputChange}
          />

          <button
            className="border p-2 px-4 rounded shadow-xl border-gray-300 bg-purple-500 text-white"
            type="submit"
          >
            Send
          </button>
        </form>
</div>
```

Thanks to Vercel AI SDK for providing a hook like `useChat` that takes care of everything from displaying messages to managing user input.

Great! We have built the user interface for our SQL Expert bot. Now, in the next section, we will start the development server and test it out.

## Test The Bot

To start the development server, run the following command in your terminal

```bash
pnpm run dev

OR

yarn run dev

OR

npm run dev
```

Visit [http://localhost:3000](http://localhost:3000) in your browser to view the application.

![sql-expert-bot](https://cdn.hashnode.com/res/hashnode/image/upload/v1709435456702/4b4ec4a8-4c2c-4153-afb6-2f5c5cc493a7.png)

You can try out the bot with the provided sample prompts below

```bash
1. "Create a SQL query to find the total number of orders placed by each customer in the past year, ordered by the highest number of orders."

2. "Write a SQL query to identify customers who have spent more than $1000 in total on purchases within the last 3 months."

3. "Design a SQL query to calculate the average time it takes for an order to be fulfilled from the moment it's placed, considering the timestamps of order placement and fulfillment."

4. "Develop a SQL query to list the products with the highest profit margin, considering both the cost price and the selling price."

5. "Construct a SQL query to find the monthly revenue trend for the past year, broken down by month."

6. "Create a SQL query to identify customers who have not made a purchase in the last 6 months."

7. "Write a SQL query to find the top 5 categories with the highest number of products sold in the last quarter."

8. "Design a SQL query to identify orders with items that are out of stock at the time of purchase."

9. "Develop a SQL query to calculate the total revenue generated from repeat customers versus new customers in the last month."

10. "Construct a SQL query to identify any anomalies or irregularities in order quantities compared to historical averages for each product."
```

Let's see the demo with the prompt provided below

```plaintext
Imagine you're tasked with optimizing the database performance of a large e-commerce platform. Write a SQL query to identify the top 10 selling products by revenue over the past month, considering both quantity sold and unit price.
```

{% embed https://youtu.be/oyeBhh5wR_M %} 

## Conclusion

Awesome! Now that we have a functioning SQL Expert Bot, feel free to experiment with it and customize it to suit your requirements. That's all for this topic. Thank you for reading! If you found this article helpful, please consider liking, commenting, and sharing it with others.

## Resources

* [SQL Expert GitHub Repository](https://github.com/Sachin-chaurasiya/ai-sql-expert)
    
* [Vercel AI SDK Docs](https://sdk.vercel.ai/docs)
    
* [useChat Hook Docs](https://sdk.vercel.ai/docs/api-reference/use-chat)