0


FastGpt+Laf 将AI知识库装进公众号

准备账号

  1. 已微信认证的公众号(需要使用到客服消息):https://mp.weixin.qq.com/
  2. FastGpt账号,及知识库:https://fastgpt.run.
  3. Laf账号: https://laf.run/

Step1: Laf 准备

1. 进入Laf官网,注册账号
2. 新建应用,直接新建免费的进行测试

在这里插入图片描述
在这里插入图片描述
3. 复制代码
直接复制,先不需要改动任何内容
在这里插入图片描述

import cloud from '@lafjs/cloud';import * as crypto from 'crypto';

// 公众号配置
const appid ='wxb1833715d8f0809d'
const appsecret ='fd76ce714a8083112100c2160b2f2c5d'
const wxToken ='test';
// fastgpt配置
const apikey ="63f9a14228d2a688d8dc9e1b-skmzjonmv1gyno2iyky1z"
const modelId ="642adec15f01d67d4613efdb"

// 创建数据库连接并获取Message集合
const db = cloud.database();
const _ = db.command
const Message = db.collection('messages')

// 处理接收到的微信公众号消息
export async function main(event){
  // const res = await cloud.fetch.post(` https://api.weixin.qq.com/cgi-bin/menu/create?access_token=${await getAccess_token()}`, {
  //   button: [
  //     {
  //       "type":"click",
  //       "name":"清空记录",
  //       "key":"CLEAR"
  //     },
  //   ]
  // })
  const { signature, timestamp, nonce, echostr }= event.query;

  // 验证消息是否合法,若不合法则返回错误信息
  if(!verifySignature(signature, timestamp, nonce, wxToken)){return'Invalid signature';}
  // 如果是首次验证,则返回 echostr 给微信服务器
  if(echostr){return echostr;}

  // -------------- 正文开始

  const payload = event.body.xml;
  const sessionId = payload.fromusername[0]

  console.log(payload)
  // 点击了清空记录
  if(payload.msgtype[0]==='event'&& payload.eventkey[0]==='CLEAR'){
    console.log(1111)
    await Message.where({ sessionId: sessionId }).remove({ multi: true})
    await replyBykefu('记录已清空', sessionId)return'clear record'}

  // 仅做文本消息例子
  if(payload.msgtype[0]!=='text')return'no text'
  const newMessage ={
    msgid: payload.msgid[0],
    question: payload.content[0].trim(),
    username: payload.fromusername[0],
    sessionId,
    createdAt: Date.now()}

  await replyText(newMessage, payload.fromusername[0])return'success'}

// 处理文本回复消息
async function replyText(message, touser){
  const { question, sessionId, msgid }= message;

  // 重复的内容,不回复
  const { data: msg }= await Message.where({ msgid: message.msgid }).getOne()if(msg)return

  console.log("收到用户消息", touser, message)

  // 立即添加一条待回复记录 
  await Message.add(message);

  // 回复提示
  await replyBykefu("🤖机器人正在思考🤔中...", sessionId)
  await changesState(sessionId)

  const reply = await getFastGptReply(question, sessionId);

  const { answer }= reply;

  await Message.where({ msgid: message.msgid }).update({
    answer,
  });

  // return answer;
  await replyBykefu(answer, touser)}

// 获取微信公众号ACCESS_TOKEN
async functiongetAccess_token(){
  const shared_access_token = await cloud.shared.get("mp_access_token")if(shared_access_token){if(shared_access_token.exp > Date.now()){return shared_access_token.access_token
    }}
  // ACCESS_TOKEN不存在或者已过期
  // 获取微信公众号ACCESS_TOKEN
  const mp_access_token = await cloud.fetch.get(`https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appid}&secret=${appsecret}`)
  cloud.shared.set("mp_access_token", {
    access_token: mp_access_token.data.access_token,
    exp: Date.now() + 7100 * 1000})return mp_access_token.data.access_token
}

// 公众号客服回复文本消息
export async function replyBykefu(message, touser){
  // 判断是否为中文字符
  function isChinese(char){return /[\u4e00-\u9fa5]/.test(char)  // 判断是否是中文字符
  }
  // 拆分文本长度
  function splitText(text){let result =[]let len = text.length
    let index =0while(index < len){let part =''let charCount =0while(charCount <800&& index < len){let char = text[index]
        charCount++
        part += char
        if(isChinese(char)) charCount++  // 中文字符计数+1
        index++
      }
      result.push(part)}return result
  }
  // 定义休眠函数
  function sleep(ms){return new Promise(resolve => setTimeout(resolve, ms))};

  const access_token = await getAccess_token()let text = splitText(message)let len = splitText(message).length

  try{for(let i =0; i < len; i++){let part = text[i]  // 获取第 i 段
      await sleep(1000)
      // 回复消息
      const res = await cloud.fetch.post(`https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=${access_token}`, {"touser": touser,
        "msgtype":"text",
        "text":{"content": part
        }})}}catch(err){
    console.log(err)}}

// 修改公众号回复状态
export async function changesState(touser){
  const access_token = await getAccess_token()
  // 修改正在输入的状态
  const res = await cloud.fetch.post(`https://api.weixin.qq.com/cgi-bin/message/custom/typing?access_token=${access_token}`, {"touser": touser,
    "command":"Typing"})}

// 校验微信服务器发送的消息是否合法
exportfunction 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
exportfunction 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>`}

// 调用 fastgpt 回答
async function getFastGptReply(question, sessionId){
  const res = await db.collection('messages')
    .where({ sessionId })
    .get()

  // 获取最多10组上下文
  const list = res.data.slice(-10)
  const prompts = list.map((item)=>[{
    obj: "Human",
    value: item.question ||''}, {
    obj: "AI",
    value: item.answer ||''}]).concat({
    obj: "Human",
    value: question
  }).flat()

  const config ={
    method: 'post', // 设置请求方法为POST
    url: 'https://fastgpt.run/api/openapi/chat/chat', // 设置请求地址
    headers: { // 设置请求头信息
      apikey,
      'Content-Type':'application/json'},
    data: { // 设置请求体数据
      modelId,
      isStream: false,
      prompts
    }}
  try {
    const ret = await cloud.fetch(config)
    console.log("fastgpt响应", ret.data)return{ answer: ret.data.data || ret.data ||''}} catch (e){
    console.log("出错了", e.response)return{
      error: "问题太难了 出错了. (uДu〃).",
    }}}

5.点击发布
在这里插入图片描述
6.复制地址
在这里插入图片描述

Step2 公众号准备

务必是要认证后的公众号,否则无效。我没有认证的号,所以视频是用测试号展示的。下面截图是完整步骤:
1.给公众号设置laf地址

在这里插入图片描述
2. 获取wx appId和secret

3. 验证laf地址
把前面两步获取到的3个内容,填写到laf
在这里插入图片描述
在这里插入图片描述

Step3 FastGpt准备

1. 获取apikey
在这里插入图片描述
在这里插入图片描述
2. 获取modelId
在这里插入图片描述
3. 替换Laf变量
在这里插入图片描述

测试

给公众号发送一条消息,看是否有回复。

QA

发送消息后无响应

先去laf日志检查是否收到用户消息,有下面的提示代表正常。 可能需要点下搜索才能刷新出来。
在这里插入图片描述
如果收到了消息,但是没有回复,八成是公众号没有发送客服消息权限。对应是下图的权限
在这里插入图片描述

私信加入技术讨论群

标签: ai

本文转载自: https://blog.csdn.net/DevonL/article/details/130804714
版权归原作者 DevonL77 所有, 如有侵权,请联系我们删除。

“FastGpt+Laf 将AI知识库装进公众号”的评论:

还没有评论