vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > Vue3使用讯飞大模型

一文带你搞懂Vue3如何使用讯飞大模型

作者:逆旅行天涯

这篇文章主要为大家详细介绍了Vue3使用讯飞大模型的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

初始化

首先构建一个基础脚手架项目

用到如下依赖

"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"
const APPID = '' // 从控制台可以获取
const API_SECRET = '' // 从控制台可以获取
const API_KEY = '' // 从控制台可以获取
let total_res = "";
 
function getWebsocketUrl() {
  return new Promise((resolve, reject) => {
    var apiKey = API_KEY
    var apiSecret = API_SECRET
    // var url = 'ws://spark-api.xf-yun.com/v3.1/chat'
    var url = 'ws://spark-api.xf-yun.com/v1.1/chat'
    var host = location.host
    var date = new Date().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 signatureOrigin = `host: ${host}\ndate: ${date}\nGET /v1.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)
  })
}
 
 
export default class TTSRecorder {
  constructor({appId = APPID} = {}) {
    this.appId = appId
    this.msgStore = null
    this.msgDom = null
  }
 
  // 连接websocket
  connectWebSocket() {
    return getWebsocketUrl().then(url => {
      let ttsWS
      if ('WebSocket' in window) {
        ttsWS = new WebSocket(url)
      } else if ('MozWebSocket' in window) {
        ttsWS = new MozWebSocket(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",
          "domain": "lite",
          // 核采样阈值。用于决定结果随机性,取值越高随机性越强即相同的问题得到的不同答案的可能性越高
          "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) {
      // 关闭WebSocket
      this.ttsWS.close()
    }
  }
}

msgStore

新建 stores/msgStore.js

用于存放历史问题

import { defineStore } from 'pinia'
import { marked } from 'marked'
 
export const 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>
  <div class="content">
 
    <div class="message" id='message-box'>
      <div v-for="(msg,index) in msgList" :key="index" :class="{
          'user':msg.role === 'user',
          'assistant':msg.role === 'assistant'
        }">
        <div>
          <div>
            <img class='role-img' :src="userImg" v-if="msg.role === 'user'"/>
          </div>
          <div class='imgbox' v-if="msg.role === 'assistant'">
            <img class='role-img' :src="aiImg" />
            <div class='name'>讯飞AI</div>
          </div>
        </div>
        <div v-highlight v-html='msg.content'></div>
      </div>
    </div>
 
 
    <div class="footer">
      <textarea rows="5" placeholder="请输入问题" class="text" v-model="msgValue"></textarea>
      <button class="btn" @click="submitMsg">发送</button>
    </div>
  </div>
</template>
 
<script setup>
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 = new TTSRecorder()
const msgList = ref([])
let msgDom = ref(null)
 
onMounted(()=>{
  msgDom.value = document.getElementById("message-box")
  msgList.value = msgStore.list
  scroll()
})
 
// 滚动到最底部
const scroll = () => {
  nextTick(()=>{
    msgDom.value.scrollTop = msgDom.value.scrollHeight
  })
}
 
// 发送消息
const submitMsg = async () => {
  msgStore.userAddMsg(msgValue.value)
  msgValue.value = ""
  // 开始提问
  ttsRecorder.start(msgStore,msgDom)
  scroll()
}
</script>
 
<style scoped lang="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>

main.css 修改

@import './base.css';
 
#app {
    height: 100vh;
    overflow: auto;
}

到此这篇关于一文带你搞懂Vue3如何使用讯飞大模型的文章就介绍到这了,更多相关Vue3使用讯飞大模型内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文