实现Telegram机器人动态ReplyKeyboard:从数据库加载品牌与车型
Telegram机器人ReplyKeyboard生成与显示问题解决方案
一、明确Telegram ReplyKeyboard结构要求
Telegram Bot API要求ReplyKeyboardMarkup的keyboard字段是二维数组,每个子数组代表一行按钮,数组元素是包含text属性的KeyboardButton对象。示例结构:
{ reply_markup: { resize_keyboard: true, // 适配手机屏幕 keyboard: [ [{ text: "丰田" }], [{ text: "本田" }], [{ text: "大众" }] ] } }
二、将数据库查询结果转化为键盘
假设你的driver.js已实现getAllBrands()(获取所有品牌)和getModelsByBrand(brand)(根据品牌获取车型)方法,先确保这两个方法返回纯字符串数组(而非数据库原始结果对象):
1. 完善driver.js的数据提取(若需要)
// driver.js 示例 async function getAllBrands() { const connection = await getConnection(); const [rows] = await connection.query('SELECT DISTINCT brand_name FROM cars'); connection.release(); // 提取品牌名称,返回字符串数组 return rows.map(row => row.brand_name); } async function getModelsByBrand(brand) { const connection = await getConnection(); const [rows] = await connection.query('SELECT model_name FROM cars WHERE brand_name = ?', [brand]); connection.release(); // 提取车型名称,返回字符串数组 return rows.map(row => row.model_name); }
2. 生成品牌列表键盘
在index.js中编写键盘生成函数,并在/start命令触发时发送:
// index.js 示例(假设使用node-telegram-bot-api库) const TelegramBot = require('node-telegram-bot-api'); const driver = require('./driver'); const bot = new TelegramBot(process.env.TELEGRAM_BOT_TOKEN, { polling: true }); // 生成品牌键盘的函数 function createBrandKeyboard(brands) { // 每个品牌占一行按钮 const keyboardRows = brands.map(brand => [{ text: brand }]); return { reply_markup: { resize_keyboard: true, keyboard: keyboardRows } }; } // 处理/start命令,发送品牌选择键盘 bot.onText(/\/start/, async (msg) => { const chatId = msg.chat.id; // 异步获取品牌列表 const brands = await driver.getAllBrands(); const keyboardOptions = createBrandKeyboard(brands); bot.sendMessage(chatId, "请选择汽车品牌:", keyboardOptions); });
3. 处理品牌点击,生成车型键盘
监听用户的文本消息,判断是否为品牌名称,若为真则生成对应车型键盘:
// 处理用户消息(品牌选择、返回操作) bot.on('message', async (msg) => { const chatId = msg.chat.id; const userInput = msg.text.trim(); // 跳过/start命令的重复处理 if (userInput === '/start') return; // 判断输入是否为品牌(可通过数据库查询验证) const brands = await driver.getAllBrands(); if (brands.includes(userInput)) { // 获取该品牌下的车型 const models = await driver.getModelsByBrand(userInput); // 生成车型键盘,添加返回按钮 const modelRows = models.map(model => [{ text: model }]); modelRows.push([{ text: "返回品牌列表" }]); const modelKeyboardOptions = { reply_markup: { resize_keyboard: true, keyboard: modelRows } }; bot.sendMessage(chatId, "请选择车型:", modelKeyboardOptions); } else if (userInput === "返回品牌列表") { // 返回品牌选择界面 const brands = await driver.getAllBrands(); const keyboardOptions = createBrandKeyboard(brands); bot.sendMessage(chatId, "请选择汽车品牌:", keyboardOptions); } });
三、常见问题排查
- 异步方法未加await:若直接调用
driver.getAllBrands()而不加await,会得到Promise对象而非数组,导致键盘生成失败。 - 键盘结构错误:必须是二维数组,不能直接传一维数组(如
[{text: "a"}, {text: "b"}]是一行两个按钮,[[{text: "a"}], [{text: "b"}]]是两行各一个按钮)。 - reply_markup格式错误:确保将键盘放在
reply_markup对象下,而非直接作为参数传入bot.sendMessage。 - 数据库查询结果未提取:若
driver方法返回的是数据库原始对象数组(如[{brand_name: "丰田"}]),必须通过map提取出纯字符串数组。
内容的提问来源于stack exchange,提问作者Francisco
相关产品推荐
相关产品推荐

