最近很火ChatGPT能够说已经满大街可见了,处处都有各种各样的体会地址,有收费的也有免费的,总之是形形色色、花里胡哨。

所以呢,最近我就在研究怎样才干方便快捷的体会到ChatGPT的强壮功能,其中一个就是:把ChatGPT接入大众号。毕竟大众号是一种十分流行的交际媒体渠道,能够用来供给服务、推广产品等。经过我的一番折腾,最终终于成功经过 Laf 完成了这个需求。

国内服务器 3 分钟将 ChatGPT 接入微信公众号(超详细)

本文将详细介绍如何运用 Laf 云渠道将 ChatGPT 接入微信大众号,完成智能问答、谈天机器人等功能。

1. 准备工作

首要需求注册一个 Laf 渠道账号:laf.run

注册登录之后,点击新建,树立一个应用:

国内服务器 3 分钟将 ChatGPT 接入微信公众号(超详细)

点击开发,进入应用开发界面:

国内服务器 3 分钟将 ChatGPT 接入微信公众号(超详细)

然后输入 chatgpt 并回车进行搜索,选择第一个搜索结果,保存并重启:

国内服务器 3 分钟将 ChatGPT 接入微信公众号(超详细)

重启之后,自定义依赖项中便呈现了 chatgpt。

国内服务器 3 分钟将 ChatGPT 接入微信公众号(超详细)

新建云函数

然后咱们点击函数,函数列表右侧的加号,新增一个能够接入微信大众号的 ChatGPT 云函数:

国内服务器 3 分钟将 ChatGPT 接入微信公众号(超详细)

云函数完好代码如下:

// 引进crypto和cloud模块
import * as crypto from 'crypto';
import cloud from '@lafjs/cloud';
const WAIT_MESSAGE = `处理中 ... \n\n请稍等3秒后发送【1】查看回复`
const NO_MESSAGE = `暂无内容,请稍后回复【1】再试`
const CLEAR_MESSAGE = `✅ 回忆已铲除`
const HELP_MESSAGE = `ChatGPT 指令运用指南
   |    关键字  |   功能         |
   |      1    | 上一次问题的回复 |
   |   /clear  |    铲除上下文   |
   |   /help   |   获取更多协助  |
  `
// 不支撑的音讯类型
const UNSUPPORTED_MESSAGE_TYPES = {
  image: '暂不支撑图片音讯',
  voice: '暂不支撑语音音讯',
  video: '暂不支撑视频音讯',
  music: '暂不支撑音乐音讯',
  news: '暂不支撑图文音讯',
}
// 定义休眠函数
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
// 创立数据库衔接并获取Message集合
const db = cloud.database();
const Message = db.collection('messages')
// 处理接收到的微信大众号音讯
export async function main(event) {
  const { signature, timestamp, nonce, echostr } = event.query;
  const token = '123456';
  // 验证音讯是否合法,若不合规律回来错误信息
  if (!verifySignature(signature, timestamp, nonce, token)) {
    return 'Invalid signature';
  }
  // 假如是初次验证,则回来 echostr 给微信服务器
  if (echostr) {
    return echostr;
  }
  // 处理接收到的音讯
  const payload = event.body.xml;
  // console.log("payload",payload)
  // 文本音讯
  if (payload.msgtype[0] === 'text') {
    const newMessage = {
      msgid: payload.msgid[0],
      question: payload.content[0].trim(),
      username: payload.fromusername[0],
      sessionId: payload.fromusername[0],
      createdAt: Date.now()
    }
    // 修复恳求响应超时问题:假如 5 秒内 AI 没有回复,则回来等候音讯
    const responseText = await Promise.race([
      replyText(newMessage),
      sleep(4000.0).then(() => WAIT_MESSAGE),
    ]);
    return toXML(payload, responseText);
  }
  // 大众号事情
  if (payload.msgtype[0] === 'event') {
    // 大众号订阅
    if (payload.event[0] === 'subscribe') {
      return toXML(payload, HELP_MESSAGE);
    }
  }
  // 暂不支撑的音讯类型
  if (payload.MsgType in UNSUPPORTED_MESSAGE_TYPES) {
    const responseText = UNSUPPORTED_MESSAGE_TYPES[payload.MsgType];
    return toXML(payload, responseText);
  }
  return 'success'
}
// 处理文本回复音讯
async function replyText(message) {
  const { question, sessionId } = message;
  console.log("replyText 执行了")
  // 查看是否是重试操作,假如是重试操作,回来上一次的回复
  if (question === '1') {
    const lastMessage = await Message.where({
      sessionId
    }).orderBy("createdAt", "desc").get();
    if (lastMessage.data[0]) {
      return `${lastMessage.data[0].question}\n------------\n${lastMessage.data[0].answer}`;
    }
    return NO_MESSAGE;
  }
  // 获取上下文 id
  const res = await Message.where({
    sessionId
  }).orderBy("createdAt", "desc").getOne();
  const parentId = res?.data?.parentMessageId
  const conId = res?.data?.conversationId
  // 发送指令
  if (question.startsWith('/')) {
    return await processCommandText(message);
  }
  // 获取 OpenAI 回复内容
  const { error, answer, parentMessageId, conversationId } = await getOpenAIReply(question, parentId, conId);
  if (error) {
    console.error(`sessionId: ${sessionId}; question: ${question}; error: ${error}`);
    return error;
  }
  // 将音讯保存到数据库中
  const token = question.length + answer.length;
  const result = await Message.add({ token, answer, parentMessageId, conversationId, ...message });
  console.debug(`[save message] result: ${result}`);
  return answer;
}
// 获取 OpenAI API 的回复
async function getOpenAIReply(question, parentId, conId) {
  console.log("getOpenAIReply 执行了")
  // 引进 ChatGPTUnofficialProxyAPI 模块
  const { ChatGPTUnofficialProxyAPI } = await import('chatgpt')
  // 创立 ChatGPTUnofficialProxyAPI 实例
  const api = new ChatGPTUnofficialProxyAPI({
    accessToken: cloud.env.ACCESSTOKEN,
    apiReverseProxyUrl: "https://bypass.churchless.tech/api/conversation"
  })
  try {
    // 假如有上下文 id,就带上
    let res;
    if (parentId && conId) {
      res = await api.sendMessage(question, { conversationId: conId, parentMessageId: parentId })
    } else {
      res = await api.sendMessage(question)
    }
    // 回来 OpenAI 回复的内容及上下文 id
    return { answer: res.text.replace("\n\n", ""), parentMessageId: res.parentMessageId, conversationId: res.conversationId }
  } catch (e) {
    console.log(e)
    return {
      error: "问题太难了 出错了. (uu〃).",
    }
  }
}
// 校验微信服务器发送的音讯是否合法
function verifySignature(signature, timestamp, nonce, token) {
  const arr = [token, timestamp, nonce].sort();
  const str = arr.join('');
  const sha1 = crypto.createHash('sha1');
  sha1.update(str);
  return sha1.digest('hex') === signature;
}
// 回来组装 xml
function toXML(payload, content) {
  const timestamp = Date.now();
  const { tousername: fromUserName, fromusername: toUserName } = payload;
  return `
  <xml>
    <ToUserName><![CDATA[${toUserName}]]></ToUserName>
    <FromUserName><![CDATA[${fromUserName}]]></FromUserName>
    <CreateTime>${timestamp}</CreateTime>
    <MsgType><![CDATA[text]]></MsgType>
    <Content><![CDATA[${content}]]></Content>
  </xml>
  `
}
async function processCommandText({ sessionId, question }) {
  // 清理前史会话
  if (question === '/clear') {
    const res = await Message.where({ sessionId }).remove({ multi: true })
    return CLEAR_MESSAGE;
  } else {
    return HELP_MESSAGE;
  }
}

由于 OpenAI 的 API Key 需求充值才干用,所以咱们选择剑走偏锋,直接运用 ChatGPT 网页版。但是国内环境无法访问 ChatGPT,所以咱们需求一个 Proxy。不用担心,国外已经有热心小哥给咱们供给了公共的 Proxy,咱们只需求直接调用就好啦!

国内服务器 3 分钟将 ChatGPT 接入微信公众号(超详细)

详情可参考 ChatGPTUnofficialProxyAPI 的运用文档。

只要你有 ChatGPT 账号,都能够运用这种办法,最的是,你能够直接在 Laf 的国内环境 laf.run 中运用!!!

中心函数:

  • getOpenAIReply函数经过引进ChatGPTUnofficialProxyAPI模块,创立实例并调用其办法,获取 ChatGPT 的回复内容。
  • verifySignature函数用于校验微信服务器发送的音讯是否合法。
  • toXML函数将回复内容组装成XML格局。
  • processCommandText函数用于处理指令,现在支撑铲除前史会话获取协助信息两个指令。

注意:

  • token要与微信大众号中设置共同。
  • ACCESSTOKEN 的获取方法:你需求先在浏览器中登录 ChatGPT 网页版,然后在浏览器中访问这个 URL:**chat.openai.com/api/auth/se… JSON,里面包含了 accessToken 字段,将这个字段的值仿制即可。

云函数写完之后就点击发布,左边的接口地址要保存一下,稍后将在微信大众号中运用此地址。

国内服务器 3 分钟将 ChatGPT 接入微信公众号(超详细)

装备微信大众号

这一步咱们需求在微信大众号渠道上装备开发者信息,并将服务器地址设置为部署好的云函数服务地址。过程如下:

首要你需求有一个大众号,然后登录微信大众渠道,点开左边的「设置与开发」,点击「基本设置」,然后点击「服务器装备」,服务器装备那里点击修正装备:

国内服务器 3 分钟将 ChatGPT 接入微信公众号(超详细)

将云函数服务地址仿制到「服务器 URL」中,下边的 Token 与云函数代码中的 token 保持共同,下边的 EncodingAESKey 点击右侧随机生成就行,然后点击提交:

国内服务器 3 分钟将 ChatGPT 接入微信公众号(超详细)

回来 token 校验成功后,点击「启用」即可。

国内服务器 3 分钟将 ChatGPT 接入微信公众号(超详细)

现在你已经完成了所有必要的设置和装备,下面就能够直接进入微信大众号「Laf 开发者」后台与机器人进行交互啦!

国内服务器 3 分钟将 ChatGPT 接入微信公众号(超详细)

ChatGPT 机器人能够回答用户提出的问题,而且能够根据用户供给的上下文进行回复。以下是一些指令和关键字,能够协助您更好地运用 ChatGPT 机器人:

  • 【1】:获取上一次问题的回复。
  • /clear:铲除上下文。
  • /help:获取更多协助。 除了以上指令和关键字外,你还能够根据自己的需求进行定制化开发,以满意用户的需求。

国内服务器 3 分钟将 ChatGPT 接入微信公众号(超详细)

总结

经过以上过程,您已经成功地将 ChatGPT 接入微信大众号,并运用 Laf 渠道来部署 ChatGPT 云函数。这样,您就能够在大众号中为您的用户供给智能问答、谈天机器人等服务了,微信大众号自带的自动回复功能能够扔掉了。

当然,直接接入 ChatGPT 网页版肯定没有接入 API 安稳,假如你想经过 API 的方法接入,能够参考原作者的官方库房:

  • github.com/husanr/wech…