小程序纯前端接入讯飞星火大模型

2,654 阅读5分钟

书接上回

在我的小程序接入三个免费功能后(没看过的可以看看这篇# 因为我也不想打工,所以跟着做了小程序),我决定整点高级功能,免得小程序没什么亮点。正愁有啥功能不需要后端实现呢。叮~一阵悦耳的手机短信提示声,将我从天马行空的想象之中拉回了现实。星火大模型API公测啦!!!真是瞌睡送枕头,人工智能虽迟但到,命运的羁绊让我再次考虑把人工智能并入我的小程序中。

申请

API是要申请的,走这个链接讯飞星火认知大模型开放能力,进入这个页面后点击“API测试申请”这个按钮,跳转到它的工单填报。

屏幕截图 2023-08-21 094924.jpg 里面的工单信息,建议是如实填写。公司名如果没有可以填写无,APPID需要提前创建,不知道如何使用的可以点击他下面的“创建应用即可获取APPID”。 实名认证后,它的工单审核非常之快。大概两个小时就搞定了(有人更快,还没见过第二天才给过)。 然后就可以在自己的控制台里面看到有两个星火大模型,分别是1.5与2.0版本的,每个版本都送2000000token,一年时间,这点token,流量不大的话明年都用不完。

开发

搞定了API的申请,就可以开始开发了。文档如下# 星火认知大模型Web文档,一开始不知道小程序有demo,我看了很久的python代码想复现,有点异想天开了,建议大家下载他的小程序demo进行查看。

主要流程如下:

确认请求类型

你需要1.5模型就请求v1.5,需要2.0模型就请求v2,文档说的很明白,是个websocket链接。

接口鉴权

可以先看看它提供的鉴权文档

这里我讲一下小程序的修改与使用

星火提供的小程序demo的鉴权函数是这么写的

getWebSocketUrl: function getWebSocketUrl() {
var _this2 = this;
return new Promise(function (resolve, reject) {
  // 请求地址根据语种不同变化 https://spark-api.xf-yun.com/v1.1/chat
  var url = "wss://spark-api.xf-yun.com/v1.1/chat";
  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 /v1.1/chat HTTP/1.1");
  var signatureSha = _cryptoJs.default.HmacSHA256(signatureOrigin, _this2.APISecret);
  var signature = _cryptoJs.default.enc.Base64.stringify(signatureSha);
  var authorizationOrigin = "".concat(apiKeyName, "=\"").concat(_this2.APIKey, "\", algorithm=\"").concat(algorithm, "\", headers=\"").concat(headers, "\", signature=\"").concat(signature, "\"");
  var authorization = base64.encode(authorizationOrigin);
  url = "".concat(url, "?authorization=").concat(authorization, "&date=").concat(encodeURI(date), "&host=").concat(host);

  // console.log(url)
  resolve(url); // 主要是返回地址
});
}

主要难点(也不算难点,百度就行,我这边直接提供结果)就是hmac-sha256获取签名和btoa编码 hmac-sha256算法你需要下载crypto-js,你只需要在小程序项目下打开终端窗口,输入如下代码:

npm install crypto-js

安装完成要记得构建npm:工具–>构建npm,然后引用

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

btoa编码可以用这段代码封装一下

  function 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;
    };

以上代码是我在微信小程序社区一位大佬提供的回复中找到的,大家可以看一下大佬git

然后完整代码如下:

 //鉴权
  getWebsocketUrl() {
    return new Promise((resolve, reject) => {
      const CryptoJS = require('crypto-js');
      var url = "wss://spark-api.xf-yun.com/v1.1/chat";
      var host = "spark-api.xf-yun.com";
      var apiKeyName = "api_key";
      var date = new Date().toGMTString();
      // var date = 'Fri, 05 May 2023 10:43:39 GMT';
      var algorithm = "hmac-sha256";
      var headers = "host date request-line";
      var signatureOrigin = "host: ".concat(host, "\ndate: ").concat(date, "\nGET /v1.1/chat HTTP/1.1");
      var signatureSha = CryptoJS.HmacSHA256(signatureOrigin, '{APISecret}');
      var signature = CryptoJS.enc.Base64.stringify(signatureSha);
      var authorizationOrigin = "".concat(apiKeyName, "=\"").concat('{APIKey}', "\", algorithm=\"").concat(algorithm, "\", headers=\"").concat(headers, "\", signature=\"").concat(signature, "\"");
      var authorization = weBtoa(authorizationOrigin);
      url = "".concat(url, "?authorization=").concat(authorization, "&date=").concat(encodeURI(date), "&host=").concat(host);
      resolve(url)
    })

    function 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;
    };
  },

这个时候返回的url就是最终的websocket链接。代码中的APISecret和APIKey填入自己控制台显示的APISecret和APIKey

接口请求

请求就简单了,websocket一连,直接无敌

代码如下:

  connectWebsocket(){
    this.getWebsocketUrl().then(res => {
      wx.connectSocket({
        url: res,
        method: "GET",
        header: {
          'content-type': 'application/json'
        },
        protocols: ['protocol1'],
        success(res) {
          console.log('连接成功', res)
        },
        fail(err) {
          console.log(err)
        }
      });

      wx.onSocketOpen(function () {
        console.log('WebSocket 已连接')
        wx.hideLoading()
      })

      wx.onSocketMessage(function (res) {
        console.log('收到服务器内容:')
        console.log(res.data)
      })
      wx.onSocketError(function (res) {
        console.log(res)
      })
      wx.onSocketClose((res) => {
        console.log(res)
      })
    }).catch(err=>{
    })
  },

以上是链接websocket,发送可以这么写

var params = {
          "header": {
            "app_id": "{APPID}"
          },
          "parameter": {
            "chat": {
              "domain": "general",
              "temperature": 0.5,
              "max_tokens": 1024
            }
          },
          "payload": {
            "message": {
              "text": this.data.chatList
            }
          }
        }
        wx.sendSocketMessage({
          data: JSON.stringify(params)
        })

APPID填写自己的,chatList按照文档的格式填写然后参数详见文档吧,理论上我的操作已经完成了,就可以开始使用大模型了,但是我暂时不清楚为什么我的小程序开发工具不能运行,我都是使用真机测试,真机是可以运行的。离谱的是星火提供的demo可以完全在模拟器上跑起来。大家可以试试,找到问题可以教教我,还有有什么不清楚的也可以在评论中评论。

提醒一下,请求完后websocket就会断掉,需要重新链接,上下文联系可以用chatList填入上次对话内容来实现,文档也是这么讲的。

总结

真的是好用,可能怀疑我是广告,可是他的好处真的很明显,某些方面可能比不上chatgpt,但是他的响应很快,也不会被小程序封掉,我觉得V2差不多有gpt2.99999999的能力甚至某些交互可以达到3.5。星火v2.0好像还支持图片,大家搞一搞,然后教教我。大家也可以去我的小程序体验一波,看一看成品。

gh_109069a7858b_344.jpg