小程序(三十五)接入讯飞-星火AI助手

529 阅读6分钟

AI时代,万物皆可AI,当然,我就说说,我有点跟不上潮流。

 

业务需要,现在要将讯飞的星火大模型接入微信小程序,下面记录一下我在接入全过程中遇到的坑。

 

一:首先下载官方示例:

下载地址:

www.xfyun.cn/doc/spark/W…

1.jpg

下载完成之后,使用微信开发者工具打开,配置上你自己申请的APPID、APPKEY、APPSECRET之后,即可成功运行项目。

 

但是有一个小小的问题,这个小程序的示例代码好像不是原生小程序的代码,好像是uniapp开发的小程序,也可能是我孤陋寡闻了,反正,我没这么写过……

 

倒也无所谓,有示例能借鉴就可以。问题不大,下边是我借鉴代码过程中踩得坑。我这里只使用发文字的功能做测试。

 

一:鉴权部分代码

1:安装CryptoJS

鉴权部分代码加密需要使用到CryptoJS加密库,我得项目中本来是引用了的,但是在这里不好用,后来我一琢磨,是不是可以使用npm安装一下呢?

npm install crypto-js

 

安装完成要记得构建npm:工具–>构建npm,详情请移步《小程序(二)使用npm安装weui

 

在项目中引用:

const CryptoJS = require('crypto-js');

 

2:安装base64

鉴权部分代码还需要使用到base64库,上边的CryptoJS库都能使用npm安装,base64库我觉得也可以啊。

npm install base-64

 

还是一样,安装完成要记得构建npm:工具–>构建npm

在项目中引用:

const base64 = require('base-64');

 

完整的鉴权部分代码:

  /**
   * @name: 鉴权
   * @author: camellia
   */
  getWebSocketUrl()
  {
    const CryptoJS = require('crypto-js');
    const base64 = require('base-64');
    var self = this;
    var httpUrlHost = self.data.httpUrl.substring(828);
    var httpUrlPath = self.data.httpUrl.substring(28);
    var url = "wss://" + httpUrlHost + httpUrlPath;
    console.log(url)
    var host = "spark-api.xf-yun.com";
    var apiKeyName = "api_key";
    var date = new Date().toGMTString();
    var algorithm = "hmac-sha256";
    var headers = "host date request-line";
    var signatureOrigin = "host: ".concat(host, "\ndate: ").concat(date, "\nGET ").concat(httpUrlPath, " HTTP/1.1");
    var signatureSha = CryptoJS.HmacSHA256(signatureOrigin, self.data.APISecret);
    var signature = CryptoJS.enc.Base64.stringify(signatureSha);
    var authorizationOrigin = "".concat(apiKeyName, "="").concat(self.data.APIKey, "", algorithm="").concat(algorithm, "", headers="").concat(headers, "", signature="").concat(signature, """);
    // var authorization = self.weBtoa(authorizationOrigin);
    var authorization = base64.encode(authorizationOrigin);
    url = "".concat(url, "?authorization=").concat(authorization, "&date=").concat(encodeURI(date), "&host=").concat(host);
    console.log(url)
    return url; // 主要是返回地址
  },

 

后来,我在github的一位大佬的代码仓库里边发现了一个base64函数,刚好也可以完美适配鉴权中的使用。这样你就可以不用配置npm了,多一种选择吧,建议使用npm构建。代码如下:

  weBtoa(string) {
    var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
    string = String(string);
    var bitmap, a, b, c, result = "",
      i = 0,
      rest = string.length % 3;
    for (; i < string.length;) {
      if ((a = string.charCodeAt(i++)) > 255 ||
        (b = string.charCodeAt(i++)) > 255 ||
        (c = string.charCodeAt(i++)) > 255)
        throw new TypeError("Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range.");
      bitmap = (a << 16) | (b << 8) | c;
      result += b64.charAt(bitmap >> 18 & 63) + b64.charAt(bitmap >> 12 & 63) +
        b64.charAt(bitmap >> 6 & 63) + b64.charAt(bitmap & 63);
    }
    return rest ? result.slice(0, rest - 3) + "===".substring(rest) : result;
  },

使用base64函数的完整代码如下:

  /**
   * @name: 鉴权
   * @author: camellia
   */
  getWebSocketUrl()
  {
    const CryptoJS = require('crypto-js');
    // const base64 = require('base-64');
    var self = this;
    var httpUrlHost = self.data.httpUrl.substring(828);
    var httpUrlPath = self.data.httpUrl.substring(28);
    var url = "wss://" + httpUrlHost + httpUrlPath;
    console.log(url)
    var host = "spark-api.xf-yun.com";
    var apiKeyName = "api_key";
    var date = new Date().toGMTString();
    var algorithm = "hmac-sha256";
    var headers = "host date request-line";
    var signatureOrigin = "host: ".concat(host, "\ndate: ").concat(date, "\nGET ").concat(httpUrlPath, " HTTP/1.1");
    var signatureSha = CryptoJS.HmacSHA256(signatureOrigin, self.data.APISecret);
    var signature = CryptoJS.enc.Base64.stringify(signatureSha);
    var authorizationOrigin = "".concat(apiKeyName, "="").concat(self.data.APIKey, "", algorithm="").concat(algorithm, "", headers="").concat(headers, "", signature="").concat(signature, """);
    var authorization = self.weBtoa(authorizationOrigin);
    // var authorization = base64.encode(authorizationOrigin);
    url = "".concat(url, "?authorization=").concat(authorization, "&date=").concat(encodeURI(date), "&host=").concat(host);
    console.log(url)
    return url; // 主要是返回地址
  },

 

二:链接webscoket部分的代码

  /**
   * 创建WebSocket连接
   */
  onWorkerfunction () {
    const self = this;
    // 发送消息参数
    var params = {
      "header": {
        "app_id": self.data.APPID
      },
      "parameter": {
        "chat": {
          "domain""general",
          "temperature"0.5,
          "max_tokens"1024
        }
      },
      "payload": {
        "message": {
          "text": self.data.historyTextList
        }
      }
    }
    // 根据文档要求 历史对话添加参数
    self.data.historyTextList.push({
      "role""user",
      "content": self.data.TEXT
    });
    // 获取webscoket 链接地址
    let url = this.getWebSocketUrl();
    console.log(url);
    // 初始化
    wx.connectSocket({
      url: url,
      success(res) {
        console.log('success', res);
        utils.vantToast('加载中……'0true);
      },
      fail(res) {
        console.log('fail', res)
      }
    })
    // 连接成功
    wx.onSocketOpen(function (res) {
      console.log("webscoket 链接成功!");
      console.log(res);
      console.log(params);
      wx.sendSocketMessage({
        // data: JSON.stringify({ type: 'message', data: '这是一条测试消息' }),
        dataJSON.stringify(params)
      })
    })
    // 接收数据
    wx.onSocketMessage(function (data) {
      console.log(data);
      // var objData = JSON.parse(data.data); // 注意这里有时会报错
      // console.log(objData);
    })
    // 连接失败
    wx.onSocketError(function () {
      console.log('websocket连接失败!');
    })
    // 断开连接
    wx.onSocketClose(function (res) {
      console.log('WebSocket 已关闭!')
    })
  },//*/

具体功能,代码中都有注释。

 

最后,放一下完整的js代码:

// 公共函数库
const utils = require("../../utils/util.js");
Page({
 
  /**
   * 页面的初始数据
   */
  data: {
    httpUrl'https://spark-api.xf-yun.com/v3.5/chat',
    TEXT'你好,我的名字叫大王',
    // 地址必须填写,代表着大模型的版本号!!!!!!!!!!!!!!!!
    modelDomain'',
    // V1.1-V3.5动态获取,高于以上版本手动指定
    APPID: xxxxxx,
    // 控制台获取填写
    APISecret: xxxxxxxxxxxxxxxxxxxx,
    APIKey: xxxxxxxxxxxxxxxxxxxx,
    sparkResult'',
    historyTextList: [],
    // 历史会话信息,由于最大token12000,可以结合实际使用,进行移出
    tempRes'' // 临时答复保存
  },
 
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad(options) {},
 
  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady() {},
 
  /**
   * 生命周期函数--监听页面显示
   */
  onShow() {
    var self = this;
    // self.connectWebsocket();
    self.onWorker();
  },
 
  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide() {},
 
  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload() {},
 
  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh() {},
 
  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom() {},
 
  /**
   * 用户点击右上角分享
   */
  onShareAppMessage() {},
 
  weBtoa(string) {
    var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
    string = String(string);
    var bitmap, a, b, c, result = "",
      i = 0,
      rest = string.length % 3;
    for (; i < string.length;) {
      if ((a = string.charCodeAt(i++)) > 255 ||
        (b = string.charCodeAt(i++)) > 255 ||
        (c = string.charCodeAt(i++)) > 255)
        throw new TypeError("Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range.");
      bitmap = (a << 16) | (b << 8) | c;
      result += b64.charAt(bitmap >> 18 & 63) + b64.charAt(bitmap >> 12 & 63) +
        b64.charAt(bitmap >> 6 & 63) + b64.charAt(bitmap & 63);
    }
    return rest ? result.slice(0, rest - 3) + "===".substring(rest) : result;
  },
 
  /**
   * @name: 鉴权
   * @author: camellia
   */
  getWebSocketUrl()
  {
    const CryptoJS = require('crypto-js');
    // const base64 = require('base-64');
    var self = this;
    var httpUrlHost = self.data.httpUrl.substring(828);
    var httpUrlPath = self.data.httpUrl.substring(28);
    var url = "wss://" + httpUrlHost + httpUrlPath;
    console.log(url)
    var host = "spark-api.xf-yun.com";
    var apiKeyName = "api_key";
    var date = new Date().toGMTString();
    var algorithm = "hmac-sha256";
    var headers = "host date request-line";
    var signatureOrigin = "host: ".concat(host, "\ndate: ").concat(date, "\nGET ").concat(httpUrlPath, " HTTP/1.1");
    var signatureSha = CryptoJS.HmacSHA256(signatureOrigin, self.data.APISecret);
    var signature = CryptoJS.enc.Base64.stringify(signatureSha);
    var authorizationOrigin = "".concat(apiKeyName, "="").concat(self.data.APIKey, "", algorithm="").concat(algorithm, "", headers="").concat(headers, "", signature="").concat(signature, """);
    var authorization = self.weBtoa(authorizationOrigin);
    // var authorization = base64.encode(authorizationOrigin);
    url = "".concat(url, "?authorization=").concat(authorization, "&date=").concat(encodeURI(date), "&host=").concat(host);
    console.log(url)
    return url; // 主要是返回地址
  },
 
  /**
   * 创建WebSocket连接
   */
  onWorkerfunction () {
    const self = this;
    // 发送消息参数
    var params = {
      "header": {
        "app_id": self.data.APPID
      },
      "parameter": {
        "chat": {
          "domain""general",
          "temperature"0.5,
          "max_tokens"1024
        }
      },
      "payload": {
        "message": {
          "text": self.data.historyTextList
        }
      }
    }
    // 根据文档要求 历史对话添加参数
    self.data.historyTextList.push({
      "role""user",
      "content": self.data.TEXT
    });
    // 获取webscoket 链接地址
    let url = this.getWebSocketUrl();
    console.log(url);
    // 初始化
    wx.connectSocket({
      url: url,
      success(res) {
        console.log('success', res);
        utils.vantToast('加载中……'0true);
      },
      fail(res) {
        console.log('fail', res)
      }
    })
    // 连接成功
    wx.onSocketOpen(function (res) {
      console.log("webscoket 链接成功!");
      console.log(res);
      console.log(params);
      wx.sendSocketMessage({
        // data: JSON.stringify({ type: 'message', data: '这是一条测试消息' }),
        dataJSON.stringify(params)
      })
    })
    // 接收数据
    wx.onSocketMessage(function (data) {
      console.log(data);
      // var objData = JSON.parse(data.data); // 注意这里有时会报错
      // console.log(objData);
    })
    // 连接失败
    wx.onSocketError(function () {
      console.log('websocket连接失败!');
    })
    // 断开连接
    wx.onSocketClose(function (res) {
      console.log('WebSocket 已关闭!')
    })
  },//*/
})

 

以上就是微信小程序纯前端接入星火大模型完整代码

 

有好的建议,请在下方输入你的评论。