Tin nhắn tương tác
Tin nhắn tương tác cho phép bot của bạn tạo trải nghiệm tin nhắn phong phú, hấp dẫn với nhiều thành phần như nút bấm, trường nhập liệu, menu thả xuống và hơn thế nữa. Mezon SDK cung cấp hai builder chính để tạo tin nhắn tương tác: InteractiveBuilder cho tin nhắn dạng embed phong phú và ButtonBuilder cho nhóm nút đơn giản.
Tổng quan
Tin nhắn tương tác hỗ trợ nhiều loại thành phần:
- Nút bấm (Buttons) — Nút có thể nhấp với các kiểu khác nhau
- Trường nhập liệu (Input Fields) — Ô nhập văn bản và textarea
- Menu thả xuống (Select Dropdowns) — Menu dropdown với các tùy chọn
- Nút radio (Radio Buttons) — Lựa chọn đơn hoặc nhiều lựa chọn
- Bộ chọn ngày (Date Pickers) — Thành phần chọn ngày
- Hoạt ảnh (Animations) — Thành phần hình ảnh có hoạt ảnh
ButtonBuilder
Lớp ButtonBuilder cung cấp cách đơn giản để tạo thành phần nút cho tin nhắn.
Import
import { ButtonBuilder, EButtonMessageStyle } from "mezon-sdk";
Kiểu nút
enum EButtonMessageStyle {
PRIMARY = 1, // Blue primary button
SECONDARY = 2, // Gray secondary button
SUCCESS = 3, // Green success button
DANGER = 4, // Red danger button
LINK = 5, // Link-styled button
}
Cách dùng cơ bản
const buttonBuilder = new ButtonBuilder();
// Add buttons with different styles
buttonBuilder
.addButton("btn-primary", "Click Me", EButtonMessageStyle.PRIMARY)
.addButton("btn-danger", "Delete", EButtonMessageStyle.DANGER)
.addButton("btn-link", "Learn More", EButtonMessageStyle.LINK);
// Build the button components
const buttons = buttonBuilder.build();
// Send message with buttons
await channel.send({
t: "Choose an action:",
components: [{ components: buttons }],
});
Ví dụ: Nút hành động
async function sendActionButtons(channel: TextChannel) {
const buttons = new ButtonBuilder()
.addButton("confirm", "Confirm", EButtonMessageStyle.SUCCESS)
.addButton("cancel", "Cancel", EButtonMessageStyle.SECONDARY)
.addButton("delete", "Delete", EButtonMessageStyle.DANGER)
.build();
await channel.send({
t: "Please confirm your action:",
components: buttons,
});
}
Xử lý sự kiện nhấn nút
Lắng nghe sự kiện nhấn nút bằng sự kiện onMessageButtonClicked:
client.onMessageButtonClicked((event) => {
console.log("Button clicked:", event.id);
console.log("Channel:", event.channel_id);
console.log("User:", event.user_id);
// Handle specific button actions
switch (event.id) {
case "confirm":
// Handle confirm action
break;
case "cancel":
// Handle cancel action
break;
case "delete":
// Handle delete action
break;
}
});
InteractiveBuilder
Lớp InteractiveBuilder cho phép bạn tạo tin nhắn dạng embed phong phú với nhiều thành phần tương tác.
Import
import { InteractiveBuilder, EMessageComponentType } from "mezon-sdk";
Constructor
const interactive = new InteractiveBuilder(title?: string);
Tạo builder tin nhắn tương tác mới với tiêu đề tùy chọn. Mỗi tin nhắn tương tác tự động bao gồm:
- Màu ngẫu nhiên để phân biệt trực quan
- Dấu thời gian hiện tại
- Footer mặc định với thương hiệu Mezon
Thiết lập metadata tin nhắn
Đặt tác giả
setAuthor(name: string, icon_url?: string, url?: string): InteractiveBuilder
Đặt thông tin tác giả hiển thị ở đầu tin nhắn.
interactive.setAuthor(
"Bot Name",
"https://example.com/bot-icon.png",
"https://example.com/bot-profile",
);
Đặt mô tả
setDescription(description: string): InteractiveBuilder
Đặt nội dung mô tả chính cho tin nhắn tương tác.
interactive.setDescription(
"This is a detailed description of the form or information being presented.",
);
Đặt thumbnail
setThumbnail(url: string): InteractiveBuilder
Thêm ảnh thumbnail nhỏ vào tin nhắn.
interactive.setThumbnail("https://example.com/thumbnail.png");
Đặt ảnh
setImage(url: string, width?: string, height?: string): InteractiveBuilder
Thêm ảnh lớn hơn vào tin nhắn với kích thước tùy chọn.
interactive.setImage("https://example.com/banner.png", "800px", "400px");
Thêm trường
Thêm trường đơn giản
addField(name: string, value: string, inline: boolean = false): InteractiveBuilder
Thêm trường văn bản đơn giản vào tin nhắn.
interactive
.addField("Status", "Active", true)
.addField("Category", "General", true)
.addField("Description", "Full width field description", false);
Thành phần tương tác
Thêm trường nhập liệu
addInputField(
id: string,
name: string,
placeholder?: string,
options?: InputFieldOption,
description?: string
): InteractiveBuilder
Thêm trường nhập văn bản hoặc textarea.
Giao diện InputFieldOption:
interface InputFieldOption {
defaultValue?: string | number;
type?: string; // HTML input type: "text", "email", "password", etc.
textarea?: boolean; // Use textarea instead of input
disabled?: boolean;
}
Ví dụ:
// Simple text input
interactive.addInputField(
"username",
"Username",
"Enter your username",
{ type: "text" },
"Your preferred username",
);
// Email input
interactive.addInputField("email", "Email Address", "user@example.com", {
type: "email",
});
// Textarea
interactive.addInputField(
"bio",
"Biography",
"Tell us about yourself",
{
textarea: true,
defaultValue: "I am a developer...",
},
"Share your background and interests",
);
// Password input
interactive.addInputField("password", "Password", "Enter password", {
type: "password",
disabled: false,
});
Thêm trường select
addSelectField(
id: string,
name: string,
options: SelectFieldOption[],
valueSelected?: SelectFieldOption,
description?: string
): InteractiveBuilder
Thêm menu thả xuống select.
Giao diện SelectFieldOption:
interface SelectFieldOption {
label: string; // Display text
value: string; // Internal value
}
Ví dụ:
const countryOptions: SelectFieldOption[] = [
{ label: "United States", value: "us" },
{ label: "United Kingdom", value: "uk" },
{ label: "Canada", value: "ca" },
{ label: "Australia", value: "au" },
];
interactive.addSelectField(
"country",
"Country",
countryOptions,
{ label: "United States", value: "us" }, // Pre-selected
"Select your country",
);
Thêm trường radio
addRadioField(
id: string,
name: string,
options: RadioFieldOption[],
description?: string,
max_options?: number
): InteractiveBuilder
Thêm nút radio cho lựa chọn đơn hoặc nhiều lựa chọn.
Giao diện RadioFieldOption:
interface RadioFieldOption {
label: string;
value: string;
name?: string; // Used for multiple choice grouping
description?: string;
style?: EButtonMessageStyle;
disabled?: boolean;
}
Ví dụ:
// Single choice
const singleChoiceOptions: RadioFieldOption[] = [
{ label: "Option A", value: "a", description: "First option" },
{ label: "Option B", value: "b", description: "Second option" },
{ label: "Option C", value: "c", description: "Third option" },
];
interactive.addRadioField(
"choice",
"Choose One",
singleChoiceOptions,
"Select your preferred option",
);
// Multiple choice (with max_options)
const multiChoiceOptions: RadioFieldOption[] = [
{ label: "Feature A", value: "feature_a", name: "features" },
{ label: "Feature B", value: "feature_b", name: "features" },
{ label: "Feature C", value: "feature_c", name: "features" },
{ label: "Feature D", value: "feature_d", name: "features" },
];
interactive.addRadioField(
"features",
"Select Features",
multiChoiceOptions,
"Choose up to 2 features",
2, // Maximum 2 selections
);
Thêm trường chọn ngày
addDatePickerField(id: string, name: string, description?: string): InteractiveBuilder
Thêm thành phần chọn ngày.
Ví dụ:
interactive.addDatePickerField(
"appointment-date",
"Appointment Date",
"Select your preferred appointment date",
);
Thêm hoạt ảnh
addAnimation(
id: string,
config: AnimationConfig,
name?: string,
description?: string
): InteractiveBuilder
Thêm thành phần hình ảnh có hoạt ảnh vào tin nhắn.
Giao diện AnimationConfig:
interface AnimationConfig {
url_image: string; // Base image URL
url_position: string; // Position data URL
pool: string[]; // Array of animation frame URLs
repeat?: number; // Number of times to repeat (default: infinite)
duration?: number; // Duration in milliseconds
}
Ví dụ:
const animConfig: AnimationConfig = {
url_image: "https://example.com/base-image.png",
url_position: "https://example.com/positions.json",
pool: [
"https://example.com/frame1.png",
"https://example.com/frame2.png",
"https://example.com/frame3.png",
],
repeat: 3,
duration: 2000,
};
interactive.addAnimation(
"welcome-anim",
animConfig,
"Welcome Animation",
"Animated welcome banner",
);
Build và gửi
Build tin nhắn tương tác
build(): IInteractiveMessageProps
Build và trả về đối tượng tin nhắn tương tác hoàn chỉnh.
const interactiveMessage = interactive.build();
Gửi dưới dạng nội dung tin nhắn
// Send interactive message through a channel
await channel.send({
embed: [interactiveMessage],
});
// Send with text and interactive message
await channel.send({
t: "Please fill out this form:",
embed: [interactiveMessage],
});
// Send with buttons
await channel.send({
t: "Choose an option:",
components: buttonComponents,
});
// Send with both interactive message and buttons
await channel.send({
embed: [interactiveMessage],
components: buttonComponents,
});
// Send with additional options (mentions, attachments, etc.)
await channel.send(
{
t: "Form submission required",
embed: [interactiveMessage],
components: buttonComponents,
},
mentions, // Array<ApiMessageMention> - optional
attachments, // Array<ApiMessageAttachment> - optional
false, // mention_everyone - optional
false, // anonymous_message - optional
topic_id, // string - optional (for threads)
0, // code - optional (message type code)
);
Tham số channel.send():
async send(
content: ChannelMessageContent,
mentions?: Array<ApiMessageMention>,
attachments?: Array<ApiMessageAttachment>,
mention_everyone?: boolean,
anonymous_message?: boolean,
topic_id?: string,
code?: number
)
content: ChannelMessageContent (bắt buộc) — Đối tượng nội dung tin nhắn gồm:t?: Nội dung văn bảnembed?: Mảng tin nhắn tương tác (IInteractiveMessageProps[])components?: Thành phần nút hoặc action row
mentions?: Mảng mention người dùngattachments?: Mảng tệp đính kèmmention_everyone?: Có mention mọi người hay khônganonymous_message?: Có gửi ẩn danh hay khôngtopic_id?: Định danh topic/chủ đềcode?: Mã loại tin nhắn
Ví dụ đầy đủ
Ví dụ 1: Form đăng ký người dùng
import { InteractiveBuilder, TextChannel } from "mezon-sdk";
async function sendRegistrationForm(channel: TextChannel) {
const form = new InteractiveBuilder("User Registration")
.setDescription("Please fill out the registration form below")
.setThumbnail("https://example.com/logo.png")
// Username field
.addInputField(
"username",
"Username",
"Enter username",
{ type: "text" },
"Choose a unique username"
)
// Email field
.addInputField(
"email",
"Email Address",
"user@example.com",
{ type: "email" }
)
// Password field
.addInputField(
"password",
"Password",
"Enter password",
{ type: "password" },
"Must be at least 8 characters"
)
// Country selection
.addSelectField(
"country",
"Country",
[
{ label: "United States", value: "us" },
{ label: "United Kingdom", value: "uk" },
{ label: "Canada", value: "ca" },
]
)
// Terms acceptance
.addRadioField(
"terms",
"Terms & Conditions",
[
{ label: "I accept the terms and conditions", value: "accept" }
]
)
.build();
await channel.send({ embed: [form] });
}
Ví dụ 2: Khảo sát với nhiều thành phần
async function sendSurvey(channel: TextChannel) {
const survey = new InteractiveBuilder("Customer Satisfaction Survey")
.setAuthor("Survey Bot", "https://example.com/bot-icon.png")
.setDescription(
"Help us improve our service by completing this short survey",
)
.setImage("https://example.com/survey-banner.png")
// Name input
.addInputField("name", "Your Name", "Enter your name", { type: "text" })
// Satisfaction rating
.addRadioField("satisfaction", "How satisfied are you with our service?", [
{ label: "Very Satisfied", value: "5" },
{ label: "Satisfied", value: "4" },
{ label: "Neutral", value: "3" },
{ label: "Dissatisfied", value: "2" },
{ label: "Very Dissatisfied", value: "1" },
])
// Product categories
.addSelectField("category", "Which product did you use?", [
{ label: "Product A", value: "product-a" },
{ label: "Product B", value: "product-b" },
{ label: "Product C", value: "product-c" },
])
// Features used (multiple choice)
.addRadioField(
"features",
"Which features did you use?",
[
{ label: "Feature X", value: "feature-x", name: "features" },
{ label: "Feature Y", value: "feature-y", name: "features" },
{ label: "Feature Z", value: "feature-z", name: "features" },
],
"Select all that apply",
3,
)
// Feedback textarea
.addInputField(
"feedback",
"Additional Feedback",
"Share your thoughts...",
{ textarea: true },
"Optional: Tell us more about your experience",
)
.build();
await channel.send({ embed: [survey] });
}
Ví dụ 3: Kết hợp tin nhắn tương tác với nút bấm
import {
InteractiveBuilder,
ButtonBuilder,
EButtonMessageStyle,
} from "mezon-sdk";
async function sendFormWithButtons(channel: TextChannel) {
// Create the interactive form
const form = new InteractiveBuilder("Event Registration")
.setDescription("Register for our upcoming event")
.addInputField("name", "Full Name", "Enter your name")
.addInputField("email", "Email", "your@email.com", { type: "email" })
.addDatePickerField("date", "Preferred Date", "Select event date")
.build();
// Create action buttons
const buttons = new ButtonBuilder()
.addButton("submit", "Submit Registration", EButtonMessageStyle.PRIMARY)
.addButton("cancel", "Cancel", EButtonMessageStyle.SECONDARY)
.build();
// Send combined message
await channel.send({
embed: [form],
components: buttons,
});
}
Ví dụ 4: Form động với trường có điều kiện
async function sendDynamicForm(channel: TextChannel, userType: string) {
const form = new InteractiveBuilder("Profile Setup");
// Common fields for all users
form
.addInputField("username", "Username", "Enter username")
.addInputField("email", "Email", "your@email.com", { type: "email" });
// Conditional fields based on user type
if (userType === "developer") {
form
.addSelectField("experience", "Experience Level", [
{ label: "Junior (0-2 years)", value: "junior" },
{ label: "Mid-level (2-5 years)", value: "mid" },
{ label: "Senior (5+ years)", value: "senior" },
])
.addRadioField(
"languages",
"Programming Languages",
[
{ label: "JavaScript/TypeScript", value: "js", name: "langs" },
{ label: "Python", value: "python", name: "langs" },
{ label: "Java", value: "java", name: "langs" },
{ label: "Go", value: "go", name: "langs" },
],
"Select your primary languages",
3,
);
} else if (userType === "designer") {
form
.addSelectField("specialty", "Design Specialty", [
{ label: "UI/UX Design", value: "uiux" },
{ label: "Graphic Design", value: "graphic" },
{ label: "Motion Graphics", value: "motion" },
])
.addInputField("portfolio", "Portfolio URL", "https://", { type: "url" });
}
// Bio field for all
form.addInputField("bio", "Bio", "Tell us about yourself", {
textarea: true,
});
await channel.send({ embed: [form.build()] });
}
Xử lý sự kiện
Xử lý đầu vào của người dùng
Khi người dùng tương tác với tin nhắn tương tác của bạn, bạn sẽ nhận các sự kiện có thể xử lý:
// Button clicks
client.onMessageButtonClicked((event) => {
console.log("Button clicked:", event.id);
// Handle button action
});
// Dropdown selections
client.onDropdownBoxSelected((event) => {
console.log("Dropdown selected:", event.id, event.value);
// Handle selection
});
// Handle other interactive events as needed
Xử lý gửi form
client.onMessageButtonClicked(async (event) => {
if (event.id === "submit-form") {
// Collect form data from the message
// Process the submission
const channel = await client.channels.fetch(event.channel_id);
await channel.send({
t: `Thank you for submitting the form! ✅`,
});
}
});
Thực hành tốt nhất
1. Dùng đúng loại thành phần
- Trường nhập liệu: Cho nhập văn bản tự do
- Menu thả xuống: Cho 4–10 tùy chọn định sẵn
- Nút radio: Cho 2–5 lựa chọn loại trừ lẫn nhau
- Bộ chọn ngày: Cho chọn ngày/giờ
2. Cung cấp nhãn và mô tả rõ ràng
// Good
interactive.addInputField(
"email",
"Email Address",
"user@example.com",
{ type: "email" },
"We'll never share your email with anyone",
);
// Less clear
interactive.addInputField("email", "Email", "...");
3. Đặt giá trị mặc định hợp lý
interactive.addSelectField(
"country",
"Country",
countryOptions,
{ label: "United States", value: "us" }, // Default selection
"Select your country",
);
4. Xác thực đầu vào người dùng
Luôn xác thực và làm sạch đầu vào người dùng ở phía server khi xử lý gửi form.
5. Cung cấp phản hồi
Sau khi gửi form, hãy phản hồi rõ ràng cho người dùng:
client.onMessageButtonClicked(async (event) => {
if (event.id === "submit") {
try {
// Process form...
await channel.send({ t: "✅ Form submitted successfully!" });
} catch (error) {
await channel.send({ t: "❌ Error submitting form. Please try again." });
}
}
});
6. Giới hạn độ phức tạp của form
Giữ form tập trung, không quá dài. Chia form phức tạp thành nhiều bước nếu cần.
7. Dùng kiểu nhất quán
Dùng kiểu nút nhất quán trong toàn bộ bot:
- PRIMARY: Hành động chính (Gửi, Lưu, Xác nhận)
- SUCCESS: Hành động tích cực (Phê duyệt, Chấp nhận)
- DANGER: Hành động phá hủy (Xóa, Gỡ)
- SECONDARY: Hành động thay thế (Hủy, Bỏ qua)
- LINK: Điều hướng hoặc hành động ít nổi bật hơn
Tham chiếu loại thành phần
enum EMessageComponentType {
BUTTON = 1, // Clickable buttons
SELECT = 2, // Dropdown select menus
INPUT = 3, // Text inputs and textareas
DATEPICKER = 4, // Date selection components
RADIO = 5, // Radio buttons (single/multiple choice)
ANIMATION = 6, // Animated elements
GRID = 7, // Grid layouts
}
Khắc phục sự cố
Tin nhắn tương tác không hiển thị
Đảm bảo bạn build và gửi tin nhắn đúng cách:
const interactive = new InteractiveBuilder("Title")
.addField("Name", "Value")
.build(); // Don't forget to call build()!
await channel.send({ embed: [interactive] });
Nút không phản hồi
Hãy chắc chắn bạn đã đăng ký handler sự kiện nhấn nút:
client.onMessageButtonClicked((event) => {
// Handle button clicks
});
Không thu thập được dữ liệu form
Dữ liệu tin nhắn tương tác được gửi qua các sự kiện cụ thể. Hãy lắng nghe đúng sự kiện theo loại thành phần bạn dùng.