当前位置:   article > 正文

手把手教你搭建微信聊天机器人系列(三):搭建对接文心一言(ERNIE-Bot大模型)接口的微信聊天机器人_自建微信聊天机器人

自建微信聊天机器人

        上一章介绍了eggjs+wechaty搭建一个简单的微信聊天机器人,只是实现了简单的回复,这一章我们将对接ERNIE-Bot接口,实现智能回复。

access_token的请求

config.default.js配置

        我们在上一章代码基础上进行调整,首先我们要加入access_token的请求逻辑。第一章我们说过,请求需要使用应用对应的API Key,Secret Key作为入参。eggjs规定了配置的写法,我们可以将其配置在config/config.default.js里面。

  1. //配置ernie
  2. config.ernie = {
  3. client_id: '填入您的API Key', //API Key
  4. client_secret: '填入您的Secret Key',//Secret Key
  5. access_token: '',//先置空,后续由程序填充
  6. expire_day: 30 //access_token过期时长(天)
  7. }

ernie.js定义getAccessToken

        我们在app/service目录增加ernie.js。

        ernie.js文件专门用来和ERNIE-Bot接口进行交互,代码如下:

  1. const {
  2. Service
  3. } = require('egg');
  4. class ErnieService extends Service {
  5. async getAccessToken() {
  6. console.log('===================ErnieService getAccessToken=====================');
  7. let ctx = this.ctx;
  8. try {
  9. const res = await ctx.curl(
  10. `https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=${ctx.app.config.ernie.client_id}&client_secret=${ctx.app.config.ernie.client_secret}`, {
  11. method: 'GET',
  12. rejectUnauthorized: false,
  13. data: {},
  14. headers: {},
  15. timeout: 30000,
  16. contentType: 'json',
  17. dataType: 'json',
  18. })
  19. console.log(res)
  20. if (res.data.access_token) {
  21. ctx.app.config.ernie.access_token = res.data.access_token;
  22. console.log('access_token', ctx.app.config.ernie.access_token)
  23. }
  24. } catch (error) {
  25. console.log(error)
  26. }
  27. }
  28. }
  29. module.exports = ErnieService;

我们按eggjs的service的写法,定义了一个方法,用来请求access_token,但是这样写并不能执行,我们需要有个逻辑,在应用启动完毕后会调用这个方法。

app.js执行getAccessToken

        我们在根目录增加app.js。

app.js代码如下:

  1. module.exports = app => {
  2. app.beforeStart(async () => {
  3. // 应用会等待这个函数执行完成才启动
  4. console.log("==app beforeStart==");
  5. });
  6. app.ready(async () => {
  7. console.log("==app ready==");
  8. let ctx = app.createAnonymousContext();
  9. ctx.service.ernie.getAccessToken(); //请求AccessToken
  10. })
  11. app.beforeClose(async () => {
  12. console.log("==app beforeClose==");
  13. })
  14. };

我们执行命令npm run dev启动项目,看到最终会打印出access_token,有了access_token我们继续开发接口请求函数sendMsg。

对话请求

ernie.js定义sendMsg

sendMsg函数用于调用ERNIE-Bot会话接口,传入对话内容并返回对话结果。在class ErnieService中加入以下代码:

  1. async sendMsg(msg) {
  2. console.log('===================ErnieService sendMsg=====================');
  3. let ctx = this.ctx;
  4. try {
  5. const res = await ctx.curl(
  6. `https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions?access_token=${ctx.app.config.ernie.access_token}`, {
  7. method: 'POST',
  8. rejectUnauthorized: false,
  9. data: {
  10. "messages": msg
  11. },
  12. timeout: 30000,
  13. contentType: 'json',
  14. dataType: 'json',
  15. })
  16. console.log(res)
  17. if (res.data) {
  18. return res.data;
  19. }
  20. return null;
  21. } catch (error) {
  22. console.log(error)
  23. return null;
  24. }
  25. }

wechat.js

我们在wechat.js中,将原先的逻辑调整一下,主要是改两个地方,

1、我们在之前的代码中经常有看到ctx这个变量,可以通过他获取配置文件的参数值。但Service文件中的ctx的获取只能通过app.js调用Service中函数的方式来获得。所以我们将机器人初始化的操作定义在startBot()方法中,由app.js来执行这个方法,就可以接收到ctx的值。

2、原先回复是直接扔回用户发的信息的,现在将其对接到ernie.js中的sendMsg方法。

wechat.js全部代码如下:

  1. const {
  2. Service
  3. } = require('egg');
  4. const {
  5. WechatyBuilder,
  6. ScanStatus
  7. } = require("wechaty");
  8. const qrcode = require("qrcode-terminal");
  9. let ctx;
  10. let wechaty;
  11. let startStatus = false;
  12. const onMessage = async (message) => {
  13. console.log(`收到消息: ${message}`);
  14. if (message.type() === wechaty.Message.Type.Text) {
  15. const userMsg = await message.text();
  16. try {
  17. let msgRecord = [{
  18. "role": "user",
  19. "content": userMsg
  20. }];
  21. let res = await ctx.service.ernie.sendMsg(msgRecord);
  22. if (res) {
  23. if (res.error_code) {
  24. message.say(JSON.stringify(res));
  25. console.log(`报错: ${JSON.stringify(res)}`);
  26. } else {
  27. if (res.result) {
  28. message.say(res.result);
  29. console.log(`回复: ${res.result}`);
  30. }
  31. }
  32. }
  33. } catch (error) {
  34. console.log(error);
  35. message.say(JSON.stringify(error));
  36. }
  37. }
  38. };
  39. const onLogout = (user) => {
  40. console.log(`用户 ${user} 退出成功`);
  41. };
  42. const onLogin = async (user) => {
  43. console.log(`用户 ${user} 登录成功`);
  44. };
  45. const onError = console.error;
  46. const onScan = (code, status) => {
  47. // status: 2代表链接等待调用,3代表链接已打开,这个链接实际上是提供一个登录的二维码供扫描
  48. if (status === ScanStatus.Waiting) {
  49. // status: 2代表等待,3代表扫码完成
  50. qrcode.generate(code, {
  51. small: true
  52. }, console.log)
  53. }
  54. };
  55. class WechatService extends Service {
  56. async startBot() {
  57. console.log('===================WechatService startBot=====================');
  58. ctx = this.ctx;
  59. if (startStatus && wechaty) {
  60. if (wechaty.isLoggedIn) {
  61. await wechaty.logout();
  62. }
  63. await wechaty.stop();
  64. startStatus = false;
  65. wechaty = null;
  66. }
  67. wechaty = await WechatyBuilder.build();
  68. wechaty
  69. .on("scan", onScan)
  70. .on("login", onLogin)
  71. .on("logout", onLogout)
  72. .on("error", onError)
  73. .on("message", onMessage);
  74. await wechaty.start();
  75. startStatus = true;
  76. }
  77. }
  78. module.exports = WechatService;

app.js执行startBot

在AccessToken请求后加入初始化BOT

  1. app.ready(async () => {
  2. console.log("==app ready==");
  3. let ctx = app.createAnonymousContext();
  4. await ctx.service.ernie.getAccessToken(); //请求AccessToken
  5. await ctx.service.wechat.startBot(); //初始化BOT
  6. })

至此,我们已经实现了一次会话的功能。多轮对话的功能等下一章再详述。

本章完整代码在这里​​​​​​​下载。运行前请配置好config/config.default.js里面config.ernie下的client_id和client_secret配置项。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/374571
推荐阅读
相关标签
  

闽ICP备14008679号