RX-Bot is an innovative framework for building bots using React inspired by Next.js. It combines the power of React's component-based architecture with the flexibility of Bot API, allowing developers to create interactive and dynamic bot interfaces with ease.
npm install @rx-lab/core @rx-lab/storage @rx-lab/common @rx-lab/telegram-adapter
app
in the src directory of your project.page.tsx
file inside the app
folder with the following content:
export default function Page() {
return <div>Hello, World!</div>;
}
Create an adapter.ts
file in the src
directory with the following content:
import { MemoryStorage } from "@rx-lab/storage/memory";
import { TelegramAdapter } from "@rx-lab/telegram-adapter";
const adapter = new TelegramAdapter({
token: apiKey,
} as any);
const storage = new MemoryStorage();
export { adapter, storage };
Create a web Server(if using callback) and start the bot:
import path from "path";
import { Core } from "@rx-lab/core";
import { FileStorage } from "@rx-lab/file-storage";
import { TelegramAdapter } from "@rx-lab/telegram-adapter";
import Fastify from "fastify";
const adapter = new TelegramAdapter({
token: apiKey,
});
const storage = new FileStorage();
const app = Fastify();
let core: Core<any>;
app.post("/webhook", async (req, res) => {
const { body } = req;
try {
await core.handleMessageUpdate(body as any);
return {
status: "ok",
};
} catch (error) {
console.error(error);
return {
status: "error",
};
}
});
(async () => {
try {
core = await Core.Compile({
adapter,
storage,
rootDir: path.join(__dirname, "src"),
destinationDir: path.join(__dirname, ".rx-lab"),
});
console.log("Bot is running");
await app.listen({
port: 3000,
});
} catch (error) {
console.error(error);
process.exit(1);
}
})();
Rx-Bot support both React Client Component and React Server Component. Here are some examples what you can do with Rx-Bot
Note: Key is required for storing and restore state from server.
"use client";
import {useState} from "@rx-lab/storage";
import React from "react";
export default function Page() {
// first argument is the key, second argument is the initial value
// this is a little bit different from React's useState hook
// because, we need to store the state on the server using the key.
const [state, setState] = useState("counter", 0);
return (
<div>
<h1>Welcome to the Telegram Bot!</h1>
<hr/>
<p>Choose an option</p>
<hr/>
<p>Current state: {state}</p>
<menu>
<div>
<button
key={"button1"}
onClick={() => {
setState(state + 1);
}}
>
+1
</button>
<button
key={"button2"}
onClick={() => {
setState(state - 1);
}}
>
-1
</button>
</div>
<div>
<button
key={"button3"}
onClick={() => {
setState(0);
}}
>
Reset
</button>
</div>
</menu>
</div>
);
}
This example uses ai
sdk from vercel to create a simple chatbot powered by ChatGPT.
Note: This example is a demonstration on how server component can be used in a chatbot.
import {openai} from "@ai-sdk/openai";
import {PageProps, RouteMetadata} from "@rx-lab/common";
import {generateText} from "ai";
export const metadata: RouteMetadata = {
title: "AI",
description: "Chat with AI",
includeInMenu: true,
};
const model = openai.chat("gpt-4o-2024-08-06");
export default async function Page({text}: PageProps) {
if (!text) {
return <div>Hi! How can I help you?</div>;
}
const {text: assistantResponse} = await generateText({
model,
prompt: text,
});
return <div>{assistantResponse}</div>;
}
You can use our Command
component to navigate between different pages.
export default async function Page(props: PageProps) {
const page = parseInt((props.searchQuery.page as any) ?? "1");
const {posts, count, pageCount} = await fetchPosts(page);
return (
<div>
<h1>Posts</h1>
<p>There are {count} posts</p>
<menu>
{posts.map((post, index) => (
<div key={index}>
<CommandButton command={`/post/${post.id}`} renderNewMessage={true}>
{post.id + " - " + post.title}
</CommandButton>
</div>
))}
<div key={"actions"}>
{page > 1 && (
<CommandButton command={`/post?page=${page - 1}`}>
Previous Page
</CommandButton>
)}
{page < pageCount && (
<CommandButton command={`/post?page=${page + 1}`}>
Next Page
</CommandButton>
)}
</div>
</menu>
</div>
);
}