Have you ever considered the concept of a Chatbot that not only enables interaction with Language Models (LLMs), but also offers the capability to integrate your own microservices for the most personalized experience imaginable?
This week, I came across an issue in ChatCraft that was asking for something similar.
In this post, I'll discuss how I was able to design and implement an initial version of this feature.
Table of Contents
1. Background 💭
1.1. Spin Off 🧐
2. Implementation 🧑🏻💻
3. Upcoming 🔮
Background 💭
I've been working on ChatCraft for a couple of months now and have already written many posts about it. It comes with many cool features apart from what a regular AI Chatbot offers, like ability to define custom ChatCraft Functions, in-built utility commands (use /commands
to get a list), text-to-speech, and many more.
This is related to /import
command (an existing feature) that allows you to make request to any URL and loads the text response as a system chat message.
Result:
Spin Off 🧐
The idea is to build something that extends this functionality.
Here's how it would work:
- We can allow the users to register various Web Handlers with a match pattern.
- If the message matches any of the registered web handlers, an HTTP request is sent to the Web Handlers's handler url based on the specified configuration.
- The received response is streamed into a new Chat Message in Markdown format.
This might sound a little confusing, so let's try to understand with an example.
Let's say you want the YouTube URLs to be handled in a certain way. You can write your own service or a serverless cloud function for processing. Then configure a ChatCraft Web Handler matching YouTube URL chat messages (use match pattern) that makes a request to your service for custom functionality.
This would allow you to plug and play any custom behaviour in ChatCraft that is not supported by default. And if that feature becomes popular, maybe we can add if by default in ChatCraft 😉
Implementation 🧑🏻💻
To implement an initial version of this concept, I started by designing a Web Handler class defining the model and behaviour of this new entity.
The model consists of 3 main properties - handlerUrl
, request method
and matchPattern
.
export class WebHandler {
handlerUrl: string;
method: HttpMethod;
matchPattern: RegExp;
constructor({
handlerUrl,
method,
matchPattern,
}: {
handlerUrl: string;
method: HttpMethod;
matchPattern: RegExp;
}) {
this.handlerUrl = handlerUrl;
this.method = method;
this.matchPattern = matchPattern;
}
...
...
...
}
export enum HttpMethod {
CONNECT = "CONNECT",
DELETE = "DELETE",
GET = "GET",
HEAD = "HEAD",
OPTIONS = "OPTIONS",
PATCH = "PATCH",
POST = "POST",
PUT = "PUT",
TRACE = "TRACE",
}
and some methods defining its behavior
export class WebHandler {
...
...
isMatchingHandler(message: string) {
return this.matchPattern.test(message);
}
async executeHandler(message: string): Promise<string> {
const requestUrl = new URL(this.handlerUrl);
const params = new URLSearchParams();
params.append("url", message);
requestUrl.search = params.toString();
const response = await fetch(requestUrl, {
method: this.method,
});
const content = (await response.text()).trim();
const resultHeader = `**Web Handler**: [${this.handlerUrl}](${this.handlerUrl})?url=[${message}](${message})`;
const text = `${resultHeader}\n\n` + content;
return text;
}
static getMatchingHandler(message: string): WebHandler | null {
return (
this.getRegisteredHandlers().find((handler) => handler.isMatchingHandler(message)) ?? null
);
}
static getRegisteredHandlers(): WebHandler[] {
// TODO: Fetch from localStorage
const supportedHandlers = [
new WebHandler({
handlerUrl: "https://taras-scrape2md.web.val.run/",
method: HttpMethod.GET,
matchPattern: /^https:\/\/\S+$/,
}),
];
return supportedHandlers;
}
This is a pretty simple model, and currently I just have a generic handler for all https
urls that redirects to a service written by Taras (the product owner) i.e. https://taras-scrape2md.web.val.run/.
Here's a detailed blog post for this tool
https://www.val.town/v/taras/scrape2md
With Web Handlers, we can now use the power of this tool in ChatCraft itself. Isn't that cool?
Upcoming 🔮
There's still a lot of potential in this idea that needs to be harnessed. I am thinking of introducing a custom UI for registering and configuring these web handlers, just like we currently do with ChatCraft Functions.
I am pretty sure, there are things I can do better and maybe a better direction I can take this in. This concept is still too young for ChatCraft and if you guys have any suggestions, let me know in comments.
I'll follow up with another post soon!
Top comments (0)