首页 > web前端 > js教程 > 正文

LINE Bot 多消息类型回复:文本与贴图的组合发送指南

霞舞
发布: 2025-10-01 13:22:27
原创
385人浏览过

LINE Bot 多消息类型回复:文本与贴图的组合发送指南

本文旨在解决 LINE Bot 开发中,通过 Messaging API 组合发送文本消息和贴图时遇到的 400 Bad Request 错误。核心问题在于对同一 replyToken 进行多次 replyMessage 调用,而正确的做法是利用 API 支持在单次调用中发送一个消息数组,从而实现文本与贴图的无缝、原子性组合回复。

1. 问题背景与错误分析

在开发 line bot 时,常见需求是在接收到用户消息后,先通过外部 api(如 openai)生成回复文本,然后希望在文本之后再发送一个相关的贴图。初次尝试时,开发者可能倾向于分两步执行:首先调用 client.replymessage 发送文本,然后再次调用 client.replymessage 发送贴图。然而,这种做法通常会导致第二次 replymessage 调用失败,并返回 httperror: request failed with status code 400,错误信息中包含 bad request。

错误根源:replyToken 的一次性使用原则

LINE Messaging API 中的 replyToken 是一个非常关键的标识符,它代表了对特定用户事件的唯一回复机会。根据 LINE 的设计,每个 replyToken 只能被用于一次 replyMessage 调用。这意味着,一旦你使用 replyToken 发送了第一条消息(例如文本),该 replyToken 就会立即失效。随后的任何尝试使用同一个 replyToken 发送消息的请求都将被视为无效,从而导致 400 Bad Request 错误。

在原始的代码实现中,handleEvent 函数首先发送文本消息:

await client.replyMessage(event.replyToken, {
  type: 'text',
  text: reply
});
登录后复制

紧接着,它尝试发送贴图消息:

await sendStickerMessage(event.replyToken);
登录后复制

由于这两次调用使用了相同的 event.replyToken,第二次调用必然会失败。

2. 解决方案:一次性发送多条消息

LINE Messaging API 提供了在单次 replyMessage 调用中发送多条消息的能力。你只需要将所有要发送的消息(包括文本、贴图、图片、视频等)封装成一个数组,然后将这个数组作为 client.replyMessage 的第二个参数。

核心改动点:

文心大模型
文心大模型

百度飞桨-文心大模型 ERNIE 3.0 文本理解与创作

文心大模型 56
查看详情 文心大模型
  1. 合并消息发送逻辑: 将文本消息和贴图消息的构建与发送逻辑合并到一个函数中。
  2. 构建消息数组: 创建一个包含所有消息对象的数组。
  3. 单次 replyMessage 调用: 将消息数组传递给 client.replyMessage。

3. 实现步骤与代码示例

以下是基于原始问题和解决方案优化后的完整代码,展示了如何正确地在一次回复中发送文本和贴图。

'use strict';

// ########################################
//               初始化与配置
// ########################################

// 加载所需模块
const line = require('@line/bot-sdk');
const openai = require('openai');
const express = require('express');

const PORT = process.env.PORT || 3000;

// LINE Bot 配置
const config = {
    channelSecret: process.env.LINE_CHANNEL_SECRET || 'YOUR_CHANNEL_SECRET', // 建议从环境变量获取
    channelAccessToken: process.env.LINE_CHANNEL_ACCESS_TOKEN || 'YOUR_CHANNEL_ACCESS_TOKEN' // 建议从环境变量获取
};

// 创建 LINE Bot 客户端
const client = new line.Client(config);

// OpenAI GPT 配置
const gptConfig = new openai.Configuration({
    organization: process.env.OPENAI_ORGANIZATION_ID || "YOUR_ORGANIZATION_ID", // 建议从环境变量获取
    apiKey: process.env.OPENAI_API_KEY || 'YOUR_API_KEY', // 建议从环境变量获取
});
const gpt = new openai.OpenAIApi(gptConfig);

/**
 * 调用 OpenAI API 生成聊天回复
 * @param {Array<Object>} userMessages 用户消息数组,包含角色和内容
 * @returns {Promise<Object>} OpenAI API 的完成结果
 */
const makeCompletion = async (userMessages) => {
  const prompt = {
    role: 'system',
    content: '你是一位技艺精湛的鬼故事讲述者。请根据用户提供的关键词创作一个鬼故事。'
  };

  userMessages.unshift(prompt); // 将系统提示添加到消息列表的开头
  console.log('发送给 OpenAI 的消息:', userMessages);
  return await gpt.createChatCompletion({
    model: 'gpt-3.5-turbo',
    messages: userMessages,
    temperature: 0.2, // 降低温度以获得更稳定的故事
    n: 1
  });
};

/**
 * 处理 LINE 消息事件
 * @param {Object} event LINE Webhook 事件对象
 * @returns {Promise<null>}
 */
async function handleEvent(event) {
  // 忽略非文本消息类型
  if (event.type !== 'message' || event.message.type !== 'text') {
    return Promise.resolve(null);
  }

  const userMessage = [
    {
      role: 'user',
      content: event.message.text
    }
  ];

  try {
    // 调用 ChatGPT API 生成回复
    const completion = await makeCompletion(userMessage);
    const replyText = completion.data.choices[0].message.content;

    // 使用 sendCombinedMessages 函数发送文本和贴图
    return sendCombinedMessages(event.replyToken, replyText);
  } catch (error) {
    console.error('处理消息时发生错误:', error);
    // 可以在这里发送一个错误提示给用户
    return Promise.resolve(null);
  }
}

/**
 * 发送组合消息(文本和贴图)
 * @param {string} replyToken 用于回复的令牌
 * @param {string} text 要发送的文本内容
 * @returns {Promise<Object>} LINE API 的回复结果
 */
async function sendCombinedMessages(replyToken, text) {
  try {
    const textMessage = {
      type: 'text',
      text: text
    };

    const stickerMessage = {
      type: 'sticker',
      packageId: '446', // 替换为你的贴图包 ID
      stickerId: '2027' // 替换为你的贴图 ID
    };

    // 将文本消息和贴图消息放入一个数组中,一次性发送
    return client.replyMessage(replyToken, [textMessage, stickerMessage]);
  } catch (error) {
    console.error('发送组合消息时发生错误:', error.message);
    if (error.response) {
      console.error('LINE API 错误详情:', error.response.data);
    }
    // 可以在这里根据错误类型进行更细致的处理
  }
}

// ########################################
//               Express 服务器设置
// ########################################

const app = express();

// 根路径 GET 请求,用于健康检查或简单提示
app.get('/', (req, res) => res.send('Hello LINE BOT! (HTTP GET)'));

// Webhook POST 请求处理
app.post('/webhook', line.middleware(config), (req, res) => {
  if (req.body.events.length === 0) {
    res.send('Hello LINE BOT! (HTTP POST)');
    console.log('收到验证事件!');
    return;
  } else {
    console.log('收到事件:', req.body.events);
  }

  // 并行处理所有事件
  Promise.all(
    req.body.events.map((event) => {
      if (event.type === 'message' && event.message.type === 'text') {
        return handleEvent(event);
      }
      // 如果需要处理其他消息类型(如贴图消息),可以在这里添加逻辑
      // else if (event.type === 'message' && event.message.type === 'sticker') {
      //   return handleMessageEvent(event); // 假设有处理贴图消息的函数
      // }
      else {
        return null;
      }
    })
  ).then((result) => res.json(result));
});

// 启动 Express 服务器
app.listen(PORT, () => {
  console.log(`Express 服务器正在端口 ${PORT} 上运行...`);
});
登录后复制

4. 关键代码变更与解释

  1. handleEvent 函数中的调用方式变更: 原始代码:

    await client.replyMessage(event.replyToken, { type: 'text', text: reply });
    await sendStickerMessage(event.replyToken);
    登录后复制

    修改后:

    return sendCombinedMessages(event.replyToken, replyText);
    登录后复制

    现在,handleEvent 不再直接发送消息,而是调用一个新的辅助函数 sendCombinedMessages,并将 replyText 传递过去,确保所有消息在一次 replyMessage 调用中完成。

  2. 新增 sendCombinedMessages 函数: 这个新函数负责构建一个消息数组,然后使用 client.replyMessage 一次性发送。

    async function sendCombinedMessages(replyToken, text) {
      try {
        const textMessage = {
          type: 'text',
          text: text
        };
    
        const stickerMessage = {
          type: 'sticker',
          packageId: '446', // 贴图包 ID
          stickerId: '2027' // 贴图 ID
        };
    
        // 将多个消息对象放入一个数组中
        return client.replyMessage(replyToken, [textMessage, stickerMessage]);
      } catch (error) {
        console.error('发送组合消息时发生错误:', error.message);
        if (error.response) {
          console.error('LINE API 错误详情:', error.response.data);
        }
      }
    }
    登录后复制

    这里 [textMessage, stickerMessage] 就是一个消息数组,它包含了两种不同类型的消息。LINE API 会按数组顺序发送这些消息。

  3. 环境变量的使用: 为了提高安全性和可维护性,建议将敏感信息(如 channelSecret, channelAccessToken, OPENAI_API_KEY 等)存储在环境变量中,而不是硬编码在代码里。示例代码已更新为从 process.env 读取配置,并在未设置时提供默认占位符。

5. 注意事项

  • packageId 和 stickerId: 贴图的 packageId 和 stickerId 必须是有效的。你可以在 LINE Messaging API 文档的贴图列表页面(https://developers.line.biz/ja/docs/messaging-api/sticker-list/)找到可用的 ID。
  • 消息数量限制: replyMessage 调用一次最多可以发送 5 条消息。如果需要发送更多,你可能需要考虑使用 pushMessage 或其他策略。
  • 错误处理: 在实际生产环境中,需要更健壮的错误处理机制。当 LINE API 调用失败时,应捕获错误并记录详细信息,以便进行调试。error.response.data 通常包含 LINE API 返回的具体错误信息,这对于排查问题非常有帮助。
  • 异步操作: 确保所有异步操作都使用 await 或 .then() 正确处理,以避免未处理的 Promise 拒绝。
  • 代码组织: 随着 Bot 功能的增加,可以考虑将不同类型的消息处理逻辑或 API 调用封装成独立的模块,以提高代码的可读性和可维护性。

通过上述修改,你的 LINE Bot 将能够稳定地在一次回复中同时发送文本消息和贴图,提升用户体验,并避免因 replyToken 重复使用而导致的 400 错误。

以上就是LINE Bot 多消息类型回复:文本与贴图的组合发送指南的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号