Tutorial: Chatbot in AstroJS with CloudFlare Workers AI (Part 3) - Creating the Chatbot Component in AstroJS
Chat with an AI
Finally, let’s build the chatbot client component using AstroJS to talk to our endpoint. This page also shows off the final result. You can find a chat bubble icon like this at the bottom of the page to start chatting:
Setting up the Component
First, create a new file named ChatBot.astro
in the src/components
directory.
The HTML code will be very simple (you can add complexity depending on your needs):
As you can see, the HTML is pretty basic, using just three elements:
- A header to add a title to the chat (optional).
- An unordered list to show the message history. We’ll fill this with JavaScript later.
- A form with an input field and a submit button. Type your message in the input field and hit submit to send it to the AI.
Note that adding autocomplete="off"
to the input field can prevent the browser from suggesting messages.
The real magic happens in the JavaScript code.
To keep things organized, I have created a separate file called chatbot_utils.ts
in the src/lib
directory for the logic.
This file will export two functions: initChat()
to set up the chatbot and sendMessage()
to send messages to the server.
Let’s import these functions into our Astro component and use them like this:
Understanding chatbot_utils.ts
Let’s dive into the chatbot_utils.ts
file in the src/lib
directory where the core chatbot logic resides.
The initChat()
Function
First up, we’ll explore the initChat()
function, which sets everything up when the page loads.
Improved Text:
This function starts by loading the previous conversation from session storage using the retrieveMessages()
function (we’ll cover that here).
It then clears the message history display and either adds a welcome message if there’s no saved conversation or repopulates the chat with the loaded messages.
The sendMessage()
function
The sendMessage()
function is the heart of the chatbot’s communication.
It’s responsible for taking the user’s input, formatting it into a suitable request, and sending it to the backend endpoint.
Upon receiving a response, the function parses the data, creates appropriate HTML elements representing the AI’s response and the user’s message, and appends them to the message history.
First, we handle the user input.
We grab the input field, chat history element, and load the message history from session storage.
We create a RoleScopedChatInput
object using the input value and add it to the message history.
Then, we create an HTML list item for the user’s message using createChatMessageElement()
(we’ll see that later) and append it to the chat history.
Finally, we clear the input field.
Next, let’s see how to generate and display the assistant’s response:
We create the assistant message following the type RoleScopedChatInput
as before and we append it to the chat history.
Note that the content field is empty, we are going to fill it later with the response from the AI model.
The createChatMessageElement()
also return the text element in this case to be able to append the response to the message.
We use the $messages.scrollTop = $messages.scrollHeight;
line to scroll to the latest message everytime the chat is updated.
Following this, the function sends a fetch request to the /api/chatbot
endpoint, including the current message history.
As the endpoint yields a stream of response data, the function processes each chunk by appending it to the assistant’s message and converting any Markdown formatting using the marked library.
Once the full response is received, the completed assistant message element is added to the chat history, and the updated message history is stored in session storage.
Utility functions
We’ve used three helper functions so far: retrieveMessages()
, storeMessages()
, and createChatMessageElement()
.
Let’s break down the first two, which are pretty straightforward. They handle storing and retrieving the conversation history in session storage.
To store the messages, we convert the list of RoleScopedChatInput
objects into a string using JSON.stringify()
.
For retrieval, we parse the stored string back into a list of objects using JSON.parse()
:
The last piece of the puzzle is the createChatMessageElement()
function.
This function takes a RoleScopedChatInput
object as input and creates an HTML list item (li
) element to represent the message.
Inside the list item, it creates a text element (div
) to hold the actual message content.
This function is crucial for building the visual representation of the chat conversation.
Improved Text:
The createChatMessageElement()
function determines whether the message is from the user or the assistant and applies appropriate classes and header text accordingly.
For assistant messages, an optional loading indicator (span
with the class loader
) can be added to display while the response is being processed.
You can style this loader
to show a loading animation.
To display timestamps, a Date
object is created, and its timestamp is extracted.
his timestamp is then included in the message header. You can see an example of this in the chat on this page.
Using the chatbot component in Astro
Finally, to use your chatbot in your AstroJS project, import it into your Astro page and initialize it:
Conclusion
This tutorial has guided you through building a basic chatbot component using AstroJS. The complete code can be found in the GitHub repository.
While you acknowledge there’s room for improvement in the code, it serves as a solid foundation for understanding chatbot development in AstroJS using CloudFlare AI models. Feel free to leave comments with feedback or suggestions for further improvement. Additionally, the discussion section is open for any questions you may have about specific parts of the tutorial.
I hope you found this tutorial helpful!