logo
/
Slack-ChatGPT-cn
Get a copy
176
5 分钟用 JavaScript 开发 Slack ChatGPT 机器人(含全部源码,免费托管,手把手教程)
  • readme.md
    arrow

    用 JavaScript 开发 Slack ChatGPT 机器人(含全部源码,免费托管,手把手教程)

    本文帮助你快速实现一个 Slack 对话机器人,并在其中接入 ChatGPT 的能力。可以直接问它问题,也可以在群聊天中 at 它,返回 ChatGPT 的回答。(以下为效果截图)

    通过本文你将学会

    1. 创建 Slack 机器人,并配置机器人所需的事件和权限
    2. 使用 AirCode 的「一键 Copy 代码」功能,实现机器人的聊天能力
    3. 将机器人接入 ChatGPT 能力

    第一步:创建 Slack 机器人

    1. 进入 Slack API 平台,创建一个 Slack App。

    1. 配置 Slack App 的权限,并设置相应的权限范围 Scope
    • app_mentions:read
    • chat:write
    • im:history

    1. 安装 Slack App 并获取到机器人的 Token

    第二步:创建 AirCode 应用

    1. 通过当前页面或 Slack ChatGPT Bot 源码链接中右上角的「Get a copy」按钮快速生成一个自己的 AirCode Node.js 应用。 注意不要直接复制代码,如果是直接复制纯代码粘贴过去,需要再手工安装 NPM 依赖包。 如果没有登录,需先登录 AirCode。

    1. 将前面在 Slack API 平台中获取到机器人 Token,粘贴到刚创建的 AirCode 应用的环境变量(Environments)中,在 SlackBotToken 中填入粘贴过来的 Bot User OAuth Token 的值。

    1. 配置好环境变量(Environments)后,点击页面上方的「Deploy 按钮」部署整个应用,使所有配置生效。

    第三步:配置 Slack 机器人的事件

    1. AirCode 应用部署成功后,选择调用文件 chat.js,你就能看到当前服务的调用 URL。将它复制,填到 Slack API 平台对应 App 的事件 Request URL 中。

    1. 给 Slack 机器人添加事件
    • app_mention
    • message.im

    1. 配置支持直接给 Slack 机器人发送消息

    第四步:测试聊天机器人

    1. 可在聊天窗口中与机器人私聊,或者将机器人加入到群中 at 机器人聊天,此时机器人可以对话。由于还没有配置 ChatGPT 能力,所以机器人会直接将你的消息返回,这时表示机器人已经配置成功。

    1. 可以在 AirCode 中查看完整的请求数据,并且使用「Mock by online requests」直接使用线上数据调试代码。

    第五步:接入 ChatGPT 能力

    1. OpenAI 的控制台中,点「Create new secret key」生成并且复制这个新生成的 Key,粘贴到刚创建的 AirCode 应用的环境变量(Environments)中。粘贴到 OpenAISecret 的 value 中。如果没有 OpenAI 账号,可以到网络中搜索一下获取方式,提前购买准备好。

    1. 再次点击 Deploy 部署服务后测试,就支持 ChatGPT 的回复了。目前 ChatGPT 服务比较慢,尤其是模型版本越高级、问题越复杂,ChatGPT 服务的返回时间会越长。

    问题反馈

    更多阅读

  • chat.js
    arrow
    1// 引入 AirCode.io 的依赖,其中包括数据库及文件存储的方法
    2const aircode = require('aircode');
    3
    4// 引入 axios,用来发起 http request
    5const axios = require('axios');
    6
    7// 引入 OpenAI 的 SDK
    8const openai = require("openai");
    9
    10// 引入 Slack 的 SDK,相关文档 https://slack.dev/node-slack-sdk/
    11const { WebClient } = require('@slack/web-api');
    12
    13// 从环境变量中获取 Slack 机器人的 Token
    14const slackBotToken = process.env.SlackBotToken;
    15if (!slackBotToken) return { error: '请根据教程配置 Slack 机器人的 Token。' };
    16const slackClient = new WebClient(slackBotToken);
    17
    18// 从环境变量中获取 OpenAI 的 Secret
    19const OpenAISecret = process.env.OpenAISecret;
    20let chatGPT = null;
    21if (OpenAISecret) {
    22  const configuration = new openai.Configuration({ apiKey: OpenAISecret });
    23  const client = new openai.OpenAIApi(configuration);
    24
    25  // 与 ChatGTP 聊天的方法,传入字符串即可
    26  chatGPT = async (content) => {
    27    return await client.createChatCompletion({
    28      // 使用当前 OpenAI 开放的最新 3.5 模型,如果后续 4 发布,则修改此处参数即可
    29      // OpenAI models 参数列表 https://platform.openai.com/docs/models
    30      model: 'gpt-3.5-turbo',
    31      // 让 ChatGPT 充当的角色为 assistant
    32      messages: [{ role: 'assistant', content }],
    33    });
    34  };
    35}
    36
    37// Slack ChatGPT 机器人的入口函数
    38module.exports = async function(params, context) {
    39
    40  // 所有调用当前函数的参数都可以直接从 params 中获取
    41  // 用来做 Slack 事件 Request 校验,要求有 challenge 参数时需直接返回
    42  if (params.challenge) return { challenge: params.challenge };
    43  
    44  // Slack 机器人每条用户消息都会有 client_msg_id
    45  const msgId = params.event.client_msg_id;
    46
    47  // 可以使用数据库极其简单地写入数据到数据表中
    48  // 实例化一个名字叫做 contents 的表
    49  const contentsTable = aircode.db.table('contents');
    50  
    51  // 搜索 contents 表中是否有 msgId 与当前这次一致的
    52  const contentObj = await contentsTable.where({ msgId }).findOne();
    53
    54  // 如果 contentObj 有值,则代表这条 event 出现过
    55  // 由于 ChatGPT 返回时间较长,这种情况可能是 Slack 的重试,直接 return 掉,防止重复调用
    56  // 当当前环境为 DEBUG 环境时,这条不生效,方便调试
    57  if (contentObj && context.trigger !== 'DEBUG') return;
    58  
    59  // 获取用户发送给机器人的信息内容,去掉 at 字符部分
    60  const message = params.event.text.replace(/<@.*?>\s*/,'');
    61
    62  // 获取发送消息的人信息
    63  const senderId = params.event.user;
    64
    65  // 返回给用户的消息
    66  let replyContent = '';
    67
    68  // 判断是否有其他类型文件(如:图片),目前 ChatGPT 仅支持文本内容
    69  if (!params.event.files) {
    70
    71    // 默认将用户发送的内容回复给用户,仅是一个直接返回对话的机器人
    72    replyContent = message;    
    73
    74    // 将消息体信息储存到数据库中,以备后续查询历史或做上下文支持使用
    75    await contentsTable.save({ msgId, senderId, message });
    76
    77    // 如果配置了 OpenAI Key 则让 ChatGPT 回复
    78    if (OpenAISecret) {
    79      
    80      // 将用户具体消息发送给 ChatGPT
    81			try {
    82	      const result = await chatGPT(content);
    83
    84				// 将获取到的 ChatGPT 回复给用户
    85	      replyContent = `${result.data.choices[0].message.content.trim()}`;
    86			} catch (err) {
    87				err = err.toJSON();
    88				if (err.status === 401) return {
    89					error: 'OpenAI ChatGPT 返回 401 错误,应该是你配置错了 OpenAI 平台的 Secret Token,请重新配置。' };
    90				if (err.status === 429) return {
    91					error: 'OpenAI ChatGPT 的 API 返回 429 错误,可能是你的额度已耗尽,你需要去 OpenAI 付费充值你的 API 配额。付费购买的 ChatGPT Plus 仅是网页版,API 需要另外充值。' };
    92				return err.message;
    93			}      
    94    }
    95
    96  } else {
    97    replyContent = '不好意思,暂时不支持其他类型的文件。';
    98  }
    99  
    100  // 将处理后的消息通过 Slack 机器人发送给用户
    101  await slackClient.chat.postMessage({
    102    channel: params.event.channel,
    103    text: `<@${senderId}> ${replyContent}`,
    104    thread_ts: params.event.ts,
    105    reply_broadcast: true,
    106  });
    107
    108  // 整个函数调用结束,需要有返回
    109  return null;
    110};
    111
  • Runtime
    arrow
    • Node.js versionnode/v16
    • Function execution timeout60 s
  • Dependencies
    arrow
    • @slack/web-api6.8.1
    • aircode0.3.0
    • axios1.3.5
    • openai3.2.1
  • Environments
    arrow
    arrow
    • SlackBotToken
    • OpenAISecret