关于ElectronVue3中集成讯飞星火AI

news2024/9/27 21:29:08

前言:我的最终目的是为了在QQ上集成一个AI机器人,因此在这里先实现一个简单的集成
先上效果图
在这里插入图片描述
总体还是很简单的,我在调用websock获取回复内容的基础上另外集成了一个事件总线,让我们在调用获取消息的时候能够更加方便快捷
工具代码如下:

import CryptoJS from 'crypto-js'

export function getWebsocketUrl(API_KEY: string, API_SECRET: string) {
  return new Promise((resolve, reject) => {
    var apiKey = API_KEY
    var apiSecret = API_SECRET
    var url = 'wss://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 /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 {
  appId: string;
  apiKey: string;
  apiSecret: string;
  status: string;
  onWillStatusChange: any;
  ttsWS: any;
  content: string;
  revertText: string;
  _events: any[];
  constructor(appId: string, API_KEY: string, API_SECRET: string) {
    this.appId = appId
    this.apiKey = API_KEY
    this.apiSecret = API_SECRET
    this._events = [];
    this.status = 'init'
  }

  // 修改状态
  setStatus(status: string) {
    this.onWillStatusChange && this.onWillStatusChange(this.status, status)
    this.status = status
  }

  // 连接websocket
  connectWebSocket() {
    this.setStatus('ttsing')
    return getWebsocketUrl(this.apiKey, this.apiSecret).then(url => {
      let ttsWS
      if ('WebSocket' in window) {
        ttsWS = new WebSocket(url as string)
      } 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 => {
        clearTimeout(this.playTimeout)
        this.setStatus('error')
        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,
        "uid": "fd3f47e4-d"
      },
      "parameter": {
        "chat": {
          "domain": "general",
          "temperature": 0.5,
          "max_tokens": 1024
        }
      },
      "payload": {
        "message": {
          "text": [
            {
              "role": "user",
              "content": this.content
            }
          ]
        }
      }
    }
    console.log(JSON.stringify(params))
    this.ttsWS.send(JSON.stringify(params))
  }

  start(text: string) {
    this.revertText = ""; // 请空回答历史
    this.content = text
    this.connectWebSocket()
  }

  // websocket接收数据的处理
  result(resultData: string) {
    let jsonData = JSON.parse(resultData)

    // 提问失败
    if (jsonData.header.code !== 0) {
      const data = {
        code: jsonData.header.code,
        content: jsonData.header.message
      }
      this.emit('error', data)
      return
    }
    if (jsonData.header.code === 0 && jsonData.header.status === 2) {
      this.ttsWS.close()
      this.setStatus("init")
      this.emit('message', {
        content: this.revertText,
        code: 0
      })
      this.emit('endRecord', {
        content: this.revertText,
        code: 0
      })
    }
    // 记录回答
    const textArr = jsonData.payload.choices.text && jsonData.payload.choices.text.map(item => item.content) || []
    this.revertText = this.revertText + textArr.join('')
  }

  on(event: string, fn: Function) {
    if (Array.isArray(event)) {
      for (let i = 0, l = event.length; i < l; i++) {
        this.on(event[i], fn)
      }
    } else {
      // 存在直接push, 不存在创建为空数组再push
      (this._events[event] || (this._events[event] = [])).push(fn)
    }
  }

  once(event: string, fn: Function) {
    let _self = this;
    function handler() {
      _self.off(event, handler);
      fn.apply(null, arguments);//emit里面调用时会给on方法传参
    }

    handler.fn = fn;//off里面根据这个判断销毁事件
    this.on(event, handler);
  }

  off(event: string, fn: Function) {
    //不传参数表示清空所有
    if (!arguments.length) {
      this._events = [];
    }
    //数组循环清空
    if (Array.isArray(event)) {
      for (let i = 0, l = event.length; i < l; i++) {
        this.off(event[i], fn)
      }
    }
    const cbs = this._events[event];
    if (!cbs) {
      return;
    }
    //不传第二参表示清空某事件所有监听函数
    if (arguments.length == 1) {
      this._events[event] = null
    }
    let cb, i = cbs.length
    while (i--) {
      cb = cbs[i]
      if (cb === fn || cb.fn === fn) { //cb.fn===fn用来移除once注册的事件
        cbs.splice(i, 1)
        break
      }
    }
  }

  emit(event: string, ...args: any[]) {
    console.log(args, typeof args)
    // 不存在event,直接返回
    if (!this._events[event]) {
      return
    }
    let cbs = [...this._events[event]];
    if (cbs) {
      for (let i = 0, l = cbs.length; i < l; i++) {
        try {
          cbs[i].apply(null, [...arguments].slice(1))
        } catch (e) {
          new Error(`event handler for "${e}"`)
        }
      }
    }
  }
}

不管你是想一次性接收到所有的内容,还是想像官方一样一点一点的接收,都能很方便的使用,视图调用代码如下:

const xfConfig = reactive({
  appid: "",
  apisecret: "",
  apikey: "",
});


function testXfSend() {
  if (!sendTest.content) {
    ElNotification.error({
      title: "请输入发送内容",
    });
    return;
  }

  const XfBot = new XfUtil(xfConfig.appid, xfConfig.apikey, xfConfig.apisecret);
  sendTest.revert = "";
  sendTest.loading = true;
  XfBot.start(sendTest.content);

  XfBot.on("endRecord", (data) => {
    console.log("回复内容", data.content);
    sendTest.loading = false;
    sendTest.revert = data.content;
  });
  
  // XfBot.on("message", (data) => {});

  XfBot.on("error", (data) => {
    sendTest.loading = false;
    ElNotification.error({
      title: data.content,
    });
  });
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1243120.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【SwiftUI】7.预览及其内部机制

上一篇讲到了组件及组件化&#xff0c;从概念和优/缺点两个方向说明了组件化的意义&#xff0c;更为重要的是&#xff0c;组件和组件化是一个在编程领域&#xff0c;放之四海皆可以的概念&#xff0c;理解和运用它是非常必要的&#xff0c;希望大家能掌握。今天我们介绍另一个特…

Spring第一课,了解IDEA里面的文件,回顾Cookie和Session,获取Session,Cookie,Header的方式

目录 IDEA第一课&#xff08;熟悉里面内容&#xff09; 建立连接 -RequestMapping 路由映射 请求 1.传递单个参数​编辑 2.多个参数​编辑 3.传递数组 4.传递一个集合&#xff0c;但是这里我们传递的时候发生了500的错误 简单介绍JSON 回顾Cookie和S…

软文推广中如何提炼好产品卖点,媒介盒子分享

内容同质化的时代下&#xff0c;企业应该如何让用户留下印象&#xff0c;并且成功将产品卖出去&#xff0c;核心思维就在于提炼产品卖点&#xff0c;产品卖点是销量提升的关键&#xff0c;相信企业在推广产品时都会有点困惑&#xff0c;感觉自家产品和竞品比起来只是logo、外观…

【SpringCloud】为什么选择微服务?

一般的平台会遇到的问题&#xff1a; 服务配置复杂。基础服务多&#xff0c;服务的资源配置复杂&#xff0c;传统方式管理服务复杂 服务之间调用复杂。检索服务、用户中心服务等&#xff0c;服务之间的调用复杂&#xff0c;依赖多 服务监控难度大。服务比较多&#xff0c;…

【SpringCloud】什么是微服务?

一、单体架构 单体架构就是把所有业务模块编写在一个项目&#xff0c;最终打包成一个 war 包&#xff0c;进行部署 单体架构的优点&#xff1a; 部署简单&#xff1a;由于是完整的结构体&#xff0c;可以直接部署在一个服务器上即可 技术单一&#xff1a;项目不需要复杂的…

世界这么大,极米投影仪RS Pro 3任意门带你“云旅游”

在繁忙的工作之后&#xff0c;许多小伙伴选择出门旅游&#xff0c;但也有不少人想在家“躺平”。其实&#xff0c;对于当代年轻人来说&#xff0c;行走在钢筋混凝土丛林&#xff0c;在家用智能投影观影娱乐好好放松身心也是不错的选择。有一台投影仪来相伴&#xff0c;能够抚平…

Let’s xrOS 一款让你优先体验社区创作者的 visionOS App工具

Let’s xrOS Apple Vision Pro 发布预示着空间计算时代的到来&#xff0c;让科技爱好者和开发者开始思考如何在新的交互、系统和硬件上打造独特的三维应用。 自 WWDC 2023 的发布会后&#xff0c;社交媒体上涌现了许多精美的 visionOS App 的效果图和演示视频&#xff0c;然而…

Mac安装配置typescript及在VSCode上运行ts

一、Mac上安装typescript sudo npm install -g typescript 测试一下&#xff1a;出现Version则证明安装成功 tsc -v 二、在VSCode上运行 新建一个xxx.ts文件&#xff0c;测试能否运行 console.log("helloworld") 运行报错&#xff1a;ts-node: command not…

【无标题】学习HTML

由于工作需求&#xff0c;学习了一些html的相关知识&#xff0c;最终应用到打印功能上使用。 HTML是指超文本标记语言&#xff08;HyperText Markup Language&#xff09;。它是一种用于创建和呈现互联网上页面的标准标记语言。HTML是Web开发的基础&#xff0c;是构建网页和应…

关于SseEmitter(SSE)在本地可以响应,部署到服务器后无法响应的问题

关于SseEmitter(SSE)在本地可以响应&#xff0c;部署到服务器后无法响应的问题 GetMapping(value "/v3/detail", produces MediaType.TEXT_EVENT_STREAM_VALUE) ResponseBody public SseEmitter v3Detail(String id) {SseEmitter emitter new SseEmitter((long) …

探究Kafka原理-2.Kafka基本命令实操

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱吃芝士的土豆倪&#xff0c;24届校招生Java选手&#xff0c;很高兴认识大家&#x1f4d5;系列专栏&#xff1a;Spring源码、JUC源码、Kafka原理&#x1f525;如果感觉博主的文章还不错的话&#xff0c;请&#x1f44…

【开源】基于JAVA的高校实验室管理系统

项目编号&#xff1a; S 015 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S015&#xff0c;文末获取源码。} 项目编号&#xff1a;S015&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容2.1 实验室类型模块2.2 实验室模块2.3 实…

2023年第十六届中国系统架构师大会(SACC2023)-核心PPT资料下载

一、峰会简介 本届大会以“数字转型 架构演进”为主题&#xff0c; 涵盖多个热门领域&#xff0c;如多云多活、海量分布式存储、容器、云成本、AIGC大数据等&#xff0c;同时还关注系统架构在各个行业中的应用&#xff0c;如金融、制造业、互联网、教育等。 与往届相比&#…

StarRocks 算子落盘:让大查询又快又稳

内存是对数据库非常重要的数据存储介质&#xff0c;它承载了所有查询计算的请求&#xff0c;在提升性能、实时分析等场景都有着重要的作用。正是由于内存如此重要&#xff0c;经常会遇到内存不够的情况&#xff0c;从而导致查询被强制终止&#xff0c;甚至对线上其他查询性能产…

UML建模图文详解教程04——对象图

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl本文参考资料&#xff1a;《UML面向对象分析、建模与设计&#xff08;第2版&#xff09;》吕云翔&#xff0c;赵天宇 著 对象图 对象图(object diagram)显示了某一时刻的一组…

OSG动画与声音-动画(3)

动画 动画是一种常见的动画形式(Frame ByFrame)&#xff0c;其原理是在连续的关键帧中分解动画动作&#xff0c;从另一个方面来说&#xff0c;也就是在时间轴的每帧上逐顿绘制不同的内容&#xff0c;使其连续播放而形成动画。 因为帧动画的帧序列内容不一样&#xff0c;不但给制…

通过 OGNL 注入执行 Confluence 预身份验证远程代码 (CVE-2022-26134)

漏洞描述 Confluence 是由澳大利亚软件公司 Atlassian 开发的基于 Web 的企业 wiki。 02 年 2022 月 <> 日&#xff0c;Atlassian 发布了针对其 Confluence Server 和 Data Center 应用程序的安全公告&#xff0c;强调了一个严重严重的未经身份验证的远程代码执行漏洞。…

java项目之网络在线考试系统(ssm)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于ssm的网络在线考试系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; &#xff08;1&#xff09;登录…

python如何快速查找到想要的文档

字多不看版&#xff0c;直接体验 待补充 演示代码 # -*- coding:UTF-8 -*-# region 导入必要的依赖包 import os import subprocess from enum import Enum模块名 pyperclip try:import pyperclip # 需要安装 pyperclip 模块&#xff0c;以支持粘贴板操作 except ImportEr…

Java零基础——SpringMVC篇

1.SpringMVC介绍 SpringMVC是Spring框架中的一个组件&#xff0c;是一个轻量级的web的MVC框架&#xff0c;充当controller,其本质就是一个Servlet。 1.1 传统Servlet的不足 每个请求&#xff0c;都需要定义一个Servlet。虽然可以在service方法中&#xff0c;根据业务标识进行…