You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

实现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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 12:35:18