讯飞星火大模型V3.0 WebApi使用
文档说明:星火认知大模型Web文档 | 讯飞开放平台文档中心 (xfyun.cn)
实现效果
初始化
首先构建一个基础脚手架项目
npm init vue@latest
用到如下依赖
"dependencies":{"crypto-js":"^4.2.0","highlight.js":"^11.9.0","marked":"^9.1.3","pinia":"^2.1.7","pinia-plugin-persistedstate":"^3.2.0","vue":"^3.3.4","vue-router":"^4.2.5"}
修改
main.js
import'./assets/main.css'import{ createApp }from'vue'import{ createPinia }from'pinia'import PiniaPluginPersistedstate from"pinia-plugin-persistedstate"import App from'./App.vue'import router from'./router'import highlight from'highlight.js'import"highlight.js/styles/atom-one-dark.css"const app =createApp(App)// 配置Pinia并设置持久化缓存const pinia =createPinia()
pinia.use(PiniaPluginPersistedstate)
app.use(pinia)
app.use(router)// 配置Markdown语法高亮
app.directive("highlight",function(el){let blocks = el.querySelectorAll('pre code');
blocks.forEach((block)=>{
highlight.highlightBlock(block);})})
app.mount('#app')
TTSRecorder
新建
utils/TTSRecorder.js
这个文件封装了发送消息并相应消息的核心功能
import CryptoJS from"crypto-js"constAPPID=''// 从控制台可以获取constAPI_SECRET=''// 从控制台可以获取constAPI_KEY=''// 从控制台可以获取let total_res ="";functiongetWebsocketUrl(){returnnewPromise((resolve, reject)=>{var apiKey =API_KEYvar apiSecret =API_SECRETvar url ='ws://spark-api.xf-yun.com/v3.1/chat'var host = location.host
var date =newDate().toGMTString()var algorithm ='hmac-sha256'var headers ='host date request-line'var signatureOrigin =`host: ${host}\ndate: ${date}\nGET /v3.1/chat HTTP/1.1`var signatureSha = CryptoJS.HmacSHA256(signatureOrigin, apiSecret)var signature = CryptoJS.enc.Base64.stringify(signatureSha)var authorizationOrigin =`api_key="${apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`var authorization =btoa(authorizationOrigin)
url =`${url}?authorization=${authorization}&date=${date}&host=${host}`resolve(url)})}exportdefaultclassTTSRecorder{constructor({appId =APPID}={}){this.appId = appId
this.msgStore =nullthis.msgDom =null}// 连接websocketconnectWebSocket(){returngetWebsocketUrl().then(url=>{let ttsWS
if('WebSocket'in window){
ttsWS =newWebSocket(url)}elseif('MozWebSocket'in window){
ttsWS =newMozWebSocket(url)}else{alert('浏览器不支持WebSocket')return}this.ttsWS = ttsWS
ttsWS.onopen=e=>{this.webSocketSend()}
ttsWS.onmessage=e=>{this.result(e.data)}
ttsWS.onerror=e=>{alert('WebSocket报错,请f12查看详情')
console.error(`详情查看:${encodeURI(url.replace('wss:','https:'))}`)}
ttsWS.onclose=e=>{
console.log(e)}})}// websocket发送数据webSocketSend(){var params ={"header":{"app_id":this.appId,},"parameter":{"chat":{// 指定访问的领域,general指向V1.5版本,generalv2指向V2版本,generalv3指向V3版本 。// 注意:不同的取值对应的url也不一样!"domain":"generalv3",// 核采样阈值。用于决定结果随机性,取值越高随机性越强即相同的问题得到的不同答案的可能性越高"temperature":0.5,// 模型回答的tokens的最大长度"max_tokens":1024}},"payload":{"message":{"text":this.msgStore.list
}}}
console.log(params,'请求的参数')this.ttsWS.send(JSON.stringify(params))}start(msgStore,msgDom){this.msgStore = msgStore
this.msgDom = msgDom.value
total_res ="";// 请空回答历史this.connectWebSocket().then(r=>{})}// websocket接收数据的处理result(resultData){let jsonData =JSON.parse(resultData)
jsonData.payload.choices.text.forEach(res=>{this.msgStore.aiAddMsg(res.content,jsonData.header.status)this.msgDom.scrollTop =this.msgDom.scrollHeight +500})// 提问失败if(jsonData.header.code !==0){alert(`提问失败: ${jsonData.header.code}:${jsonData.header.message}`)
console.error(`${jsonData.header.code}:${jsonData.header.message}`)return}if(jsonData.header.code ===0&& jsonData.header.status ===2){// 关闭WebSocketthis.ttsWS.close()}}}
msgStore
新建
stores/msgStore.js
用于存放历史问题
import{ defineStore }from'pinia'import{ marked }from'marked'exportconst userMsgStore =defineStore("userMsgStore",{// 持久化persist:true,state:()=>{return{list:[]}},actions:{userAddMsg(msg){this.list.push({role:"user",content:msg,status:2})},aiAddMsg(content,status){let runMsg =this.list.find(i=>i.status !==2)if(!runMsg){this.list.push({role:"assistant",content:content,status:status
})}else{
runMsg.content += content
runMsg.status = status
if(status ===2){
runMsg.content =marked(runMsg.content)}}}},})
编写界面代码
<template><divclass="content"><divclass="message"id='message-box'><divv-for="(msg,index) in msgList":key="index":class="{
'user':msg.role === 'user',
'assistant':msg.role === 'assistant'
}"><div><div><imgclass='role-img':src="userImg"v-if="msg.role === 'user'"/></div><divclass='imgbox'v-if="msg.role === 'assistant'"><imgclass='role-img':src="aiImg"/><divclass='name'>讯飞AI</div></div></div><divv-highlightv-html='msg.content'></div></div></div><divclass="footer"><textarearows="5"placeholder="请输入问题"class="text"v-model="msgValue"></textarea><buttonclass="btn"@click="submitMsg">发送</button></div></div></template><scriptsetup>import userImg from"@/assets/user.png"import aiImg from"@/assets/ai.png"import{ nextTick, onMounted, ref }from'vue'import TTSRecorder from"@/utils/TTSRecorder"import{ userMsgStore }from'@/stores/msgStore'const msgStore =userMsgStore()const msgValue =ref("")let ttsRecorder =newTTSRecorder()const msgList =ref([])let msgDom =ref(null)onMounted(()=>{
msgDom.value = document.getElementById("message-box")
msgList.value = msgStore.list
scroll()})// 滚动到最底部constscroll=()=>{nextTick(()=>{
msgDom.value.scrollTop = msgDom.value.scrollHeight
})}// 发送消息constsubmitMsg=async()=>{
msgStore.userAddMsg(msgValue.value)
msgValue.value =""// 开始提问
ttsRecorder.start(msgStore,msgDom)scroll()}</script><stylescopedlang="less">.content{height: 100%;position: relative;.message{position: absolute;top: 0;left: 20%;right: 20%;bottom: 150px;display: flex;overflow: auto;flex-direction: column;.user{background-color: #ebf7f8;padding: 15px;box-sizing: border-box;display: flex;flex-direction: column;align-items: flex-end;border-bottom: 1px solid #dfdfdf;}.assistant{background-color: #f7f7f7;padding: 15px;box-sizing: border-box;border-bottom: 1px solid #dfdfdf;}}.footer{position: absolute;bottom: 50px;left: 20%;right: 20%;display: flex;align-items: flex-end;gap: 15px;.text{width: 100%;}.btn{width: 100px;height: 40px;background-color: #1a60ea;color: white;border: none;}}@media screen and(max-width: 768px){.message,.footer{left: 0;right: 0;}.message{bottom: 100px;}.footer{bottom: 10px;}}}.imgbox{display: flex;align-items: center;gap: 10px;margin-bottom: 10px;.name{font-size: 13px;color: #fd919e;font-weight: 400;}}.role-img{width: 40px;height: 40px;border-radius: 50%;overflow: hidden;}</style>
版权归原作者 szx的开发笔记 所有, 如有侵权,请联系我们删除。