• 讯飞开放平台--星火认知大模型--开发技术文档--js实例代码详解


     阿丹:

            之前调用写过调用百度的文心一言写网站,讯飞的星火认知模型开放了,这次尝试一下使用流式来进行用户的交互。

    官网:

    平台简介 | 讯飞开放平台文档中心

    星火认知大模型Web文档 | 讯飞开放平台文档中心

    简介:

            本文章主要开发的是一个web应用。

    值得一提的是官网很贴心的给了代码!!!

     我这里展示的js的小demo

    阅读解析一下demo代码--js

    解析了一下代码结构:
    主要的核心代码是在index.html为简单的页面。

    index.js中封装了方法,惊喜的发现前台使用的流式相应是使用的websocket协议

    解读分析一下代码:

    index.html

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
    6. <meta http-equiv="X-UA-Compatible" content="ie=edge">
    7. <title>产品体验-大模型title>
    8. head>
    9. <body>
    10. <div>
    11. <div>
    12. <h2>产品体验-大模型h2>
    13. <div class="page-main">
    14. <div>
    15. <textarea id="input_text" placeholder="请输入您要问大模型的问题" style="width: 600px">秦始皇的儿子是谁?textarea>
    16. div>
    17. <div>
    18. <button class="audio-ctrl-btn">立即提问button>
    19. div>
    20. <br>
    21. <div>
    22. <textarea id="output_text" style="width: 800px;height: 500px">textarea>
    23. div>
    24. div>
    25. div>
    26. div>
    27. body>
    28. html>

     其实这个主页没有太多解释的地方。

    我们来看一下封装的方法--index.js

    我们将后台代码分模块进行研究

    构造与后台建立websocket连接的url

    1. function getWebsocketUrl() {
    2. return new Promise((resolve, reject) => {
    3. var apiKey = API_KEY
    4. var apiSecret = API_SECRET
    5. var url = 'wss://spark-api.xf-yun.com/v1.1/chat'
    6. var host = location.host
    7. var date = new Date().toGMTString()
    8. var algorithm = 'hmac-sha256'
    9. var headers = 'host date request-line'
    10. var signatureOrigin = `host: ${host}\ndate: ${date}\nGET /v1.1/chat HTTP/1.1`
    11. var signatureSha = CryptoJS.HmacSHA256(signatureOrigin, apiSecret)
    12. var signature = CryptoJS.enc.Base64.stringify(signatureSha)
    13. var authorizationOrigin = `api_key="${apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`
    14. var authorization = btoa(authorizationOrigin)
    15. url = `${url}?authorization=${authorization}&date=${date}&host=${host}`
    16. resolve(url)
    17. })
    18. }

    代码解析:

    1. function getWebsocketUrl() { 定义了一个名为 getWebsocketUrl 的函数。
    2. return new Promise((resolve, reject) => { 使用 Promise 构造函数创建了一个异步操作,并传入 resolve 和 reject 回调函数。
    3. var apiKey = API_KEY 声明了一个变量 apiKey,并将其初始化为 API_KEY 的值。
    4. var apiSecret = API_SECRET 声明了一个变量 apiSecret,并将其初始化为 API_SECRET 的值。
    5. var url = 'wss://spark-api.xf-yun.com/v1.1/chat' 声明了一个变量 url,并将其初始化为一个 WebSocket 连接的 URL。
    6. var host = location.host 声明了一个变量 host,并将其初始化为当前页面的主机名。
    7. var date = new Date().toGMTString() 声明了一个变量 date,并将其初始化为当前时间的 GMT 表示形式。
    8. var algorithm = 'hmac-sha256' 声明了一个变量 algorithm,并将其初始化为字符串 'hmac-sha256'
    9. var headers = 'host date request-line' 声明了一个变量 headers,并将其初始化为字符串 'host date request-line'
    10. var signatureOrigin = host: ${host}\ndate: ${date}\nGET /v1.1/chat HTTP/1.1`` 声明了一个变量 signatureOrigin,并将其初始化为一个字符串,包含了请求的头部信息。
    11. var signatureSha = CryptoJS.HmacSHA256(signatureOrigin, apiSecret) 使用 CryptoJS 的 HMAC-SHA256 算法对 signatureOrigin 进行哈希运算,并将结果存储在变量 signatureSha 中。
    12. var signature = CryptoJS.enc.Base64.stringify(signatureSha) 将 signatureSha 转换为 Base64 编码的字符串,并将结果存储在变量 signature 中。
    13. var authorizationOrigin = api_key="${apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"声明了一个变量authorizationOrigin`,并将其初始化为一个包含授权信息的字符串。
    14. var authorization = btoa(authorizationOrigin) 使用 btoa 函数将 authorizationOrigin 转换为 Base64 编码的字符串,并将结果存储在变量 authorization 中。
    15. url = ${url}?authorization=${authorization}&date=${date}&host=${host}将带有授权信息的 URL 拼接在原始 URL 的后面,并将结果存储回变量url` 中。
    16. resolve(url) 调用 resolve 回调函数,并将带有授权信息的 URL 作为参数传递给它。
    17. }) } 结束异步操作块和函数定义。
    18. return new Promise((resolve, reject) => { ... } ) } 返回一个 Promise 对象,该对象将在异步操作完成后通过调用 resolve 回调函数来解析 URL。

    这段代码的目的是通过使用 HMAC-SHA256 算法对请求进行签名,并添加授权信息到 WebSocket 连接 URL 中,以获取一个合法的 WebSocket 连接 URL。

    封装的调用的工具类

    1. class TTSRecorder {
    2. constructor({
    3. appId = APPID
    4. } = {}) {
    5. this.appId = appId
    6. this.status = 'init'
    7. }
    8. // 修改状态
    9. setStatus(status) {
    10. this.onWillStatusChange && this.onWillStatusChange(this.status, status)
    11. this.status = status
    12. }
    13. // 连接websocket
    14. connectWebSocket() {
    15. this.setStatus('ttsing')
    16. return getWebsocketUrl().then(url => {
    17. let ttsWS
    18. if ('WebSocket' in window) {
    19. ttsWS = new WebSocket(url)
    20. } else if ('MozWebSocket' in window) {
    21. ttsWS = new MozWebSocket(url)
    22. } else {
    23. alert('浏览器不支持WebSocket')
    24. return
    25. }
    26. this.ttsWS = ttsWS
    27. ttsWS.onopen = e => {
    28. this.webSocketSend()
    29. }
    30. ttsWS.onmessage = e => {
    31. this.result(e.data)
    32. }
    33. ttsWS.onerror = e => {
    34. clearTimeout(this.playTimeout)
    35. this.setStatus('error')
    36. alert('WebSocket报错,请f12查看详情')
    37. console.error(`详情查看:${encodeURI(url.replace('wss:', 'https:'))}`)
    38. }
    39. ttsWS.onclose = e => {
    40. console.log(e)
    41. }
    42. })
    43. }
    44. // websocket发送数据
    45. webSocketSend() {
    46. var params = {
    47. "header": {
    48. "app_id": this.appId,
    49. "uid": "fd3f47e4-d"
    50. },
    51. "parameter": {
    52. "chat": {
    53. "domain": "general",
    54. "temperature": 0.5,
    55. "max_tokens": 1024
    56. }
    57. },
    58. "payload": {
    59. "message": {
    60. "text": [
    61. {
    62. "role": "user",
    63. "content": "中国第一个皇帝是谁?"
    64. },
    65. {
    66. "role": "assistant",
    67. "content": "秦始皇"
    68. },
    69. {
    70. "role": "user",
    71. "content": "秦始皇修的长城吗"
    72. },
    73. {
    74. "role": "assistant",
    75. "content": "是的"
    76. },
    77. {
    78. "role": "user",
    79. "content": $('#input_text').text()
    80. }
    81. ]
    82. }
    83. }
    84. }
    85. console.log(JSON.stringify(params))
    86. this.ttsWS.send(JSON.stringify(params))
    87. }
    88. start() {
    89. total_res = ""; // 请空回答历史
    90. this.connectWebSocket()
    91. }
    92. // websocket接收数据的处理
    93. result(resultData) {
    94. let jsonData = JSON.parse(resultData)
    95. total_res = total_res + resultData
    96. $('#output_text').val(total_res)
    97. // console.log(resultData)
    98. // 提问失败
    99. if (jsonData.header.code !== 0) {
    100. alert(`提问失败: ${jsonData.header.code}:${jsonData.header.message}`)
    101. console.error(`${jsonData.header.code}:${jsonData.header.message}`)
    102. return
    103. }
    104. if (jsonData.header.code === 0 && jsonData.header.status === 2) {
    105. this.ttsWS.close()
    106. bigModel.setStatus("init")
    107. }
    108. }
    109. }

    代码解释: 

    在构造函数中,有一个可选的参数appId,默认值为"APPID"。该函数会将appId赋值给隶属于类的属性this.appId,并将状态初始化为"init"。

    setStatus(status)是一个方法,用于改变状态。在调用该方法之前,可以通过设置onWillStatusChange回调函数来执行一些额外操作。该方法会将状态设置为传入的status值。

    connectWebSocket()是一个方法,用于建立WebSocket连接。在开始建立连接之前,会将状态设置为"ttsing"。然后,通过调用getWebsocketUrl()方法获取WebSocket的URL,并创建一个WebSocket实例,保存在ttsWS属性中。如果浏览器不支持WebSocket,则会弹出一个警告,而后续的操作将中止。

    创建WebSocket实例后,定义了几个回调函数:onopenonmessageonerroronclose。在连接成功时,会调用webSocketSend()方法发送数据;接收到消息时,会调用result()方法处理数据;发生错误时,会更改状态为"error";关闭连接时,在控制台打印相关信息。

    webSocketSend()方法用于向WebSocket发送数据。首先,创建了一个包含参数的params对象,其中包括应用ID、用户ID、聊天参数和要转换为语音的文本。通过调用JSON.stringify()方法将参数对象转换为字符串,并使用WebSocket实例的send()方法发送。

    start()方法是启动TTS录制的入口。在该方法中,将总的回答历史total_res初始化为空字符串,然后调用connectWebSocket()方法建立WebSocket连接。

    result(resultData)方法用于处理接收到的WebSocket数据。首先,将接收到的JSON字符串转换为对象,将结果累加到total_res变量中,并将其值显示在output_text元素中。如果提问失败(header.code不为0),会弹出一个警告并输出错误信息。如果提问成功但会话结束(header.status为2),则关闭WebSocket连接,并将状态设置为"init"。

  • 相关阅读:
    Nodejs系列之模块加载机制
    http1.0到http3.0的介绍以及新特性
    TRC心血管研究之艾美捷TRC缺血研究领域
    腾讯云4核8G云服务器租用价格选轻量还是CVM?性能如何?
    vue2.0动态数据表格
    C++避坑:基类函数有无virtual关键字,差别巨大
    如何查看linux 服务器的内存容量
    C++算法之旅、04 基础篇 | 第一章 基础算法
    【Linux-Windows】千兆网口以及千兆网线
    如何将项目(工程/代码)文件上传到gitee?(注意一下,有几个坑)
  • 原文地址:https://blog.csdn.net/weixin_72186894/article/details/132736666