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

 更新时间:2024年12月12日 08:38:12   作者:逆旅行天涯  
这篇文章主要为大家详细介绍了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使用讯飞大模型内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • vue 实现 ios 原生picker 效果及实现思路解析

    vue 实现 ios 原生picker 效果及实现思路解析

    这篇文章主要介绍了vue 实现 ios 原生picker 效果及实现思路解析,本文给大家介绍的非常详细,具有参考借鉴价值,需要的朋友可以参考下
    2017-12-12
  • 使用Vue + Tippy.js打造高定制浮层提示组件(Tooltip/Popover)

    使用Vue + Tippy.js打造高定制浮层提示组件(Tooltip/Popover)

    这篇文章主要介绍了使用Vue + Tippy.js打造高定制浮层提示组件(Tooltip/Popover)的相关资料,支持延迟显示、手动控制、响应式内容及图片图标等功能,适用于Tooltip、Popover、关键词推荐等场景,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-07-07
  • 基于Vue3与免费满血版DeepSeek实现无限滚动+懒加载+瀑布流模块及优化过程

    基于Vue3与免费满血版DeepSeek实现无限滚动+懒加载+瀑布流模块及优化过程

    在进行非完全标准化数据的可视化展示时,瀑布流是一种经常被采用的展示方法,瀑布流能够有效地将不同大小规格的内容以一种相对规整的方式呈现出来,本文给大家介绍了基于Vue3与免费满血版DeepSeek实现无限滚动+懒加载+瀑布流模块,需要的朋友可以参考下
    2025-03-03
  • 多个Vue项目部署到服务器的步骤记录

    多个Vue项目部署到服务器的步骤记录

    这篇文章主要给大家介绍了关于多个Vue项目部署到服务器的相关资料,文中通过图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-10-10
  • vue3与webpack5安装element-plus样式webpack编译报错问题解决

    vue3与webpack5安装element-plus样式webpack编译报错问题解决

    这篇文章主要介绍了vue3与webpack5安装element-plus样式webpack编译报错,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-04-04
  • vue 国际化 vue-i18n 双语言 语言包

    vue 国际化 vue-i18n 双语言 语言包

    这篇文章主要介绍了vue 国际化 vue-i18n 双语言 语言包的相关知识,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-06-06
  • 详解Vue如何使用xlsx库导出Excel文件

    详解Vue如何使用xlsx库导出Excel文件

    第三方库xlsx提供了强大的功能来处理Excel文件,它可以简化导出Excel文件这个过程,本文将为大家详细介绍一下它的具体使用,需要的小伙伴可以了解下
    2025-01-01
  • vue拖拽组件vuedraggable使用说明详解

    vue拖拽组件vuedraggable使用说明详解

    这篇文章主要为大家详细介绍了vue拖拽组件vuedraggable的使用说明,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-04-04
  • vue视图响应式更新详细介绍

    vue视图响应式更新详细介绍

    这篇文章主要介绍了Vue响应式原理,响应式就是当对象本身(对象的增删值)或者对象属性(重新赋值)发生了改变的时候,就会运行一些函数,最常见的示render函数
    2022-09-09
  • vue父子组件的嵌套的示例代码

    vue父子组件的嵌套的示例代码

    本篇文章主要介绍了vue父子组件的嵌套的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-09-09

最新评论