Building a Web Component-Based Chatbot with GPT-3.5-turbo
Tags: chatbot, webcomponents, openai, gpt35turbo
Published: 2023-09-02 21:46:00

---
title: Building a Web Component-Based Chatbot with GPT-3.5-turbo
published: true
description: "This tutorial provides a step-by-step guide on crafting a chatbot interface leveraging the might of OpenAI's GPT-3.5-turbo. From defining SVG icons to building the ChatBot class, and registering the web component, readers will acquire a holistic understanding of chatbot development using web components. This approach ensures a chatbot solution that's both scalable and easily integrable into web applications."

tags: ["Chatbot", "WebComponents", "OpenAI", "GPT35turbo"]
published_at: 2023-09-02 21:46 +0000
---

Creating a custom chatbot interface using web components allows for modular and reusable design. In this tutorial, I'll guide you through building a chatbot leveraging OpenAI's powerful GPT-3.5-turbo model. All of the code for this blog post is available [here](https://github.com/stephenc222/example-web-chatbot).

## Prerequisites

- Familiarity with JavaScript and the Shadow DOM
- Basic knowledge of OpenAI's API

## Overview

We'll start by defining SVG icons, setting up token limitations, and building the main `ChatBot` class. The ChatBot class will have helper methods and event listeners to manage chat operations.

## 1. Defining SVG Icons

Before diving into the main component, we first define SVG elements for our chat and close icons. These icons enhance user interaction:

```javascript
const chatIcon = `...`
const closeIcon = `...`
```

## 2. Setting Up Token Limitations

Next, for effective management of tokens and API calls, we'll define some constants:

```javascript
const TOKEN_LIMIT = 1000
const SPECIAL_TOKEN_BUFFER = 10
```

- `TOKEN_LIMIT`: The maximum number of tokens we want to handle.
- `SPECIAL_TOKEN_BUFFER`: A small buffer to account for any special tokens.

## 3. Building the ChatBot Class

Our main component is the `ChatBot` class. It manages the chat's state, UI, and interactions:

```javascript
class ChatBot extends HTMLElement {
    ...
}
```

### 3.1. Initializing Component State

Inside the constructor, we initialize our chatbot's state. This includes the chat window's visibility (`isOpen`), the chat messages (`messages`), the chatbot's thinking status, and more.

```javascript
constructor() { ... }
```

### 3.2. Styling the Component

The `get styles()` method returns a template literal containing the CSS to style our chatbot:

```javascript
get styles() { ... }
```

### 3.3. Estimating Tokens

We use a simple method to estimate the number of tokens a message might consume:

```javascript
estimateTokens(message) { ... }
```

By using a rough estimation instead of a precise token count, this ChatBot becomes more flexible to integrate with a wider variety of LLMs, since all LLMs' token creation is directly positively correlated to the number of words in a message passed to the given LLM.

### 3.4. Component Lifecycle Callbacks

`connectedCallback` and `disconnectedCallback` handle rendering and cleanup operations when the component gets attached or detached from the DOM:

```javascript
connectedCallback() { ... }
disconnectedCallback() { ... }
```

### 3.5. Chat Operations

Several methods manage chat operations, from toggling the chat window to sending messages and rendering the UI:

- `toggleChat()`: Opens or closes the chat window.
- `sendMessage(message)`: Sends a message and handles the API response.
- `render()`: Updates the component's UI.

### 3.6. Event Handlers

Event listeners and corresponding handlers ensure the chatbot responds to user interactions:

- `handleToggleChatClick()`: Toggles the chat window.
- `handleCloseButtonClick()`: Closes the chat.
- `handleSendButtonClick()`: Handles the send button click.
- `handleInputKeydown()`: Sends a message when the Enter key is pressed.

## 4. Registering the Web Component

Finally, we define and register our web component:

```javascript
if (!customElements.get("chat-bot")) {
  customElements.define("chat-bot", ChatBot)
}
```

### Example Integration

With our ChatBot defined, here's a simple HTML file demonstrating how to use it, assuming `ChatBot.js` is located next to this html file, inside the public folder:

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Chat Bot Example</title>
  </head>
  <body>
    <chat-bot></chat-bot>
    <script type="module">
      import "./ChatBot.js"
    </script>
  </body>
</html>
```

And a simple Express server to illustrate what a backend could look like:

```typescript
import express, { Request, Response } from "express"
import OpenAI from "openai"
import dotenv from "dotenv"
dotenv.config() // Load environment variables from .env file

const app = express()
app.use(express.json())

const OPENAI_API_KEY = process.env.OPENAI_API_KEY

const openai = new OpenAI({
  apiKey: OPENAI_API_KEY,
})

app.use(express.static("public"))

app.post("/api/chat", async (req: Request, res: Response) => {
  try {
    const gptResponse = await openai.chat.completions.create({
      // OpenAI offers more models, and choosing a different model is as easy as
      // changing this string specifier
      model: "gpt-3.5-turbo",
      messages: req.body.messages,
      // example number of tokens, you can play with this number for your needs.
      max_tokens: 150,
    })

    if (gptResponse && gptResponse.choices && gptResponse.choices.length > 0) {
      res.status(200).json({ content: gptResponse.choices[0].message.content })
    } else {
      res
        .status(500)
        .json({ content: "Failed to get a response from the model." })
    }
  } catch (error) {
    console.error("Error calling OpenAI:", error)
    res.status(500).json({ content: "Internal server error." })
  }
})

const PORT = process.env.PORT || 3000
app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`)
})
```

## Conclusion

With this structure, we've built a modular chatbot component using web components. This chatbot is easily integrated into any web application and offers a customizable interface to interact with the GPT-3.5-turbo model or any LLM you have available through an API. The full code of this blog post is available at [my github repository](https://github.com/stephenc222/example-web-chatbot).