腾讯IM uniapp微信小程序版本实现迅飞语音听写(流式版)

在之前文章《腾讯IM web版本实现迅飞语音听写(流式版)》实现了腾讯IM web版本实现迅飞语音听写,本文将基于uniapp vue2/vue3(cli 脚手架)的Demo项目集成迅飞语音听写(流式版):

在这里插入图片描述

主要代码:

// \src\TUIKit\components\TUIChat\message-input\index.vue<template><!-- 录音按钮 --><VoiceToText @change="changeVoiceToText"/><!-- 输入框 --><MessageInputEditor  ref="editor"/>
</template>
// voice-to-text/index.vue<template><div v-if="!openShow" class="message-input-asr" @click="openMedia" /><div v-if="openShow" class="message-input-asr" :class="{active: openShow}" @click="stopMedia" />
</template><script setup>
import { onMounted, ref } from "vue";
import ChatApi from '@/api/chat.js'const emits = defineEmits(['change'])
const openShow = ref(false)// 发给科大讯飞的每一帧的定义
//参考接口调用流程: https://www.xfyun.cn/doc/asr/voicedictation/API.html#%E6%8E%A5%E5%8F%A3%E8%B0%83%E7%94%A8%E6%B5%81%E7%A8%8B
const FRAME = {STATUS_FIRST_FRAME: 0, //第一帧音频STATUS_CONTINUE_FRAME: 1, //中间的音频STATUS_LAST_FRAME: 2, //最后一帧音频,最后一帧必须要发送
};
let status = FRAME.STATUS_FIRST_FRAME;//心跳定时器
let heartTimer = null;
// 心跳数据(发给科大讯飞的数据)发送队列
let sendDataStack = [];//websocket实例化
let uniSocketTask = null;//打开麦克风
function openMedia() {status = FRAME.STATUS_FIRST_FRAME; //初始化音频状态(设置当前录音状态为首帧)sendDataStack = []stopMedia()connectSocket(); //创建websocket连接startRecord(); //打开录音
}
//关闭麦克风
function stopMedia() {//关闭录音stopRecord();//为什么关闭录音的时候不直接关闭websocket连接,这是因为://关闭麦克风的时候会回调出录音最后一帧,并且会触发监听录音结束事件(也不是在这个地方结束)。//发送最后一帧后,得到最后一帧返回的消息后,此时此刻才应该关闭websocket连接//但是可以关闭心跳定时器clearInterval(heartTimer);//初始化已经渲染了的数据renderText.value = "";resultText = "";resultTextTemp = "";
}
/*** 获取麦克风权限并开始录音(步骤一)*/
// 录音配置项
const recordOption = {duration: 60000, //指定录音的时长,单位 ms,微信可设置的最大值为 600000(10 分钟),科大讯飞最高支持时间为 60000 (1分钟)sampleRate: 16000, // 采样率(pc不支持)numberOfChannels: 1.25, // 录音通道数// encodeBitRate: 48000, // 编码码率(默认就是48000)// frameSize 为指定帧大小,单位 KB。传入 frameSize 后,每录制指定帧大小的内容后,会回调录制的文件内容,不指定则不会回调。// 暂仅支持 mp3、pcm 格式。科大讯飞建议:每40ms发送一个节数为1280B的为压缩PCM格式frameSize: 1,format: "pcm", // 音频格式,默认是 aac
};
let recordManager = null;
//开启录音
const startRecord = () => {openShow.value = truerecordManager = uni.getRecorderManager();recordManager.onStart(() => {console.log("开始录音");// ...});// recordManager.onPause(() => {//   console.log("录音暂停");// });recordManager.onStop((res) => {// tempFilePath	String	录音文件的临时路径console.log("录音停止,文件路径为:", res.tempFilePath);});recordManager.onError((err) => {// errMsg	String	错误信息console.log("录音出现错误", err);});//获得录音结果的回调函数recordManager.onFrameRecorded((res) => {// console.log("开始产生录音结果:");// frameBuffer:	type:[ArrayBuffer]	录音分片结果数据// isLastFrame:	type:[Boolean]	当前帧是否正常录音结束前的最后一帧const { frameBuffer, isLastFrame } = res;// console.log("录音分片结果:", toBase64(frameBuffer));// console.log("开始判断当前帧为第几帧");// 判断当前录音数据是否为最后一帧if (isLastFrame) {console.log("当前帧为录音最后一帧");status = FRAME.STATUS_LAST_FRAME;}//存入心跳数据栈中,再合适的时候发送给科大讯飞(第四步)sendDataStack.push(packFrame(frameBuffer)); //入栈});recordManager.start(recordOption);
};
//关闭录音
const stopRecord = () => {recordManager?.stop();openShow.value = false
};
//音频转码(步骤二)[把音频片段转换成base64]
function toBase64(buffer) {return uni.arrayBufferToBase64(buffer);
}//创建连接并返回数据
async function connectSocket() {const res = await ChatApi.getXFVoiceAuthUrl()uniSocketTask = uni.connectSocket({url: res.url,success() {},});//监听连接成功的事件uniSocketTask.onOpen(() => {console.log("监听到开启连接成功");//启动心跳定时器onHeartBeat();});//监听连接关闭的事件uniSocketTask.onClose(() => {console.log("监听到关闭连接成功");uniSocketTask = null;});uniSocketTask.onError(() => {console.log("监听到连接发生错误");});//监听科大讯飞消息返回uniSocketTask.onMessage((res) => {//收到消息const message = JSON.parse(res.data);//判断是否存在数据if (res.data) {console.log("收到服务器消息,并开始渲染");renderResult(message);if (message.code === 0 && message.data.status === 2) {//此时此刻我们可以得知当前科大讯飞返回的数据为最后一帧可以关闭连接//该函数为当前页唯一的关闭连接函数closeSocket();}//收到不正常服务器消息,返回错误到控制台if (message.code !== 0) {closeSocket();console.error(message);}} else {console.log("未监听到消息:原因:", JSON.stringify(res));}});
}
//关闭连接
function closeSocket() {console.log("开始尝试关闭连接");// 关闭心跳if (heartTimer) {clearInterval(heartTimer);}// 关闭连接uniSocketTask.close();
}//发送给科大讯飞的每一帧的模板数据格式
let frame = {common: {app_id: '自己的appid',},business: {language: "zh_cn",domain: "iat",accent: "mandarin",dwa: "wpgs", // 可选参数,动态修正vad_eos: 5000,},data: {status: 0,format: "audio/L16;rate=16000",encoding: "raw",audio: "", //音频内容},
};
//封装录音后的每一"帧"数据(步骤三)
function packFrame(audioData) {//转载音频数据frame.data.audio = toBase64(audioData);switch (status) {//首条空白消息(第一帧)case FRAME.STATUS_FIRST_FRAME:// console.log("当前帧为第一帧");frame.data.status = 0;status = FRAME.STATUS_CONTINUE_FRAME;break;//正文(中间帧)case FRAME.STATUS_CONTINUE_FRAME:// console.log("当前帧为中间帧");frame.data.status = 1;break;//传输结束(最后一帧)case FRAME.STATUS_LAST_FRAME:// console.log("当前帧为最后一帧");frame.data.status = 2;break;}return JSON.stringify(frame);
}//启动心跳连接定时器,每40ms发送一次数据(第五步发送数据)
function onHeartBeat() {let sendData = null; //发送给科大讯飞的每一帧数据heartTimer = setInterval(() => {//发送队列中有数据的时候执行下述逻辑发送数据,否则不执行下述函数console.log("当前发送队列中数据的长度为", sendDataStack.length);if (sendDataStack.length !== 0) {sendData = sendDataStack.shift();uniSocketTask.send({data: sendData,success() {// console.log("发送成功");},fail() {console.log("发送失败");},});}}, 40);
}//根据科大讯飞语音听写识别结果进行渲染(最后一步,根据onMessage()方法返回的数据进行渲染)
let resultText = "";
let resultTextTemp = "";
let renderText = ref("");
function renderResult(jsonData) {// console.log("开始执行渲染函数", jsonData);if (jsonData.data && jsonData.data.result) {let data = jsonData.data.result;let str = ""; // 初始化一个字符串变量用于存储拼接后的识别结果let ws = data.ws;for (let i = 0; i < ws.length; i++) {str = str + ws[i].cw[0].w;}// 开启wpgs会有此字段(前提:在控制台开通动态修正功能)// 取值为 "apd"时表示该片结果是追加到前面的最终结果;取值为"rpl" 时表示替换前面的部分结果,替换范围为rg字段if (data.pgs) {if (data.pgs === "apd") {// 将resultTextTemp同步给resultTextresultText = resultTextTemp;}// 将结果存储在resultTextTemp中resultTextTemp = resultText + str;} else {resultText = resultText + str;}renderText.value = resultTextTemp || resultText || "";}console.log("渲染后的数据为");console.log(renderText.value);emits.$emit('change', {content: renderText.value,})
}
</script>

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

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

相关文章

实现高效运行管理:如何使用 NSSM 工具将 IoTDB 注册为 Windows 系统服务

后台自动无干扰运行 IoTDB 的“指导手册”&#xff01; IoTDB 是一个专为工业物联网领域设计的高性能时间序列数据库。在生产环境中&#xff0c;确保 IoTDB 的稳定运行对于业务连续性至关重要。通常情况下&#xff0c;通过批处理&#xff08;bat&#xff09;脚本运行 IoTDB 会始…

Windows配置域名映射IP

一、找到 hosts 文件 打开 C:\Windows\System32\drivers\etc 二、添加hosts文件修改、写入权限 右击hosts文件&#xff0c;点击属性 -> 安全 -> Users -> 编辑 -> Users -> 添加修改、写入权限 -> 确定 -> 确定 进入常规&#xff0c;将只读属性关闭 三、…

专题二十_动态规划_简单多状态dp问题_买卖股票系列问题_算法专题详细总结

目录 动态规划 1. 按摩师&#xff08;easy&#xff09; 解析&#xff1a; 1.状态表达式&#xff1a; 2.状态转移方程 3.初始化 4.填表方向 5.返回值&#xff1a; 代码编写&#xff1a; 总结&#xff1a; 2. 打家劫舍II &#xff08;medium&#xff09; 解析&#xf…

多模态简述

多模态学习概念 【多模态简述-哔哩哔哩】 https://b23.tv/UrUyfln 定义&#xff1a; 模态&#xff1a;事物表达或感知的方式 多模态&#xff1a;研究异构和相互连接数据的科学&#xff0c;涵盖了从原始的器官信号到抽象概念的多种模态 语音和语言是理解人物交互的关键模态&am…

mac2019环境 Airflow+hive+spark+hadoop本地环境安装

1 环境介绍 本地安装可分为两个部分&#xff0c;mac软件环境&#xff0c; python开发环境 ps: 安装过程参考chatgpt、csdn文章 1.1 mac软件环境 目标安装的的软件是hive、apache-spark、hadoop&#xff0c;但是这三个软件又依赖java(spark依赖&#xff09;、ssh&#xff08…

HarmonyOS4+NEXT星河版入门与项目实战--------开发工具与环境准备

文章目录 1、熟悉鸿蒙官网1、打开官网2、下载 DevEco Studio3、HarmonyOS 资源库4、开发指南与API 2、安装 DevEco Studio1、软件安装2、配置开发工具 1、熟悉鸿蒙官网 1、打开官网 百度搜索 鸿蒙开发者官网 点击进入开发者官网&#xff0c;点击开发&#xff0c;可以看到各种…

11.16 JavaScript

什么是JavaScript&#xff1f; JavaScript&#xff08;简称&#xff1a;js&#xff09;是一门跨平台&#xff0c;面向对象的脚本语言&#xff0c;是用来控制网页行为的&#xff0c;它能使网页可交互。JavaScript和java是完全不同的语言&#xff0c;不论是概念还是设计。但是基…

【网络安全面经】技术性问题

1.SQL注入原理 主要基于Web应用程序对用户输入数据的合法性缺乏严格的判断或过滤 2.windows上提权的方式和linux提权方式 windows&#xff1a;本地溢出漏洞提权&#xff0c;AT(计划任务提权)&#xff0c;SC(创建服务提权)&#xff0c;PS(微软官方工具pstool)&#xff0c;数据…

20241116下载中科创达的TurboX D660核心板的Android11的SDK的详细LOG

20241116下载中科创达的TurboX D660核心板的Android11的SDK的详细LOG 2024/11/16 15:28 下载速度&#xff0c;工作日&#xff1a;20MBps/周末30MBps。 【实际情况&#xff0c;取决于您的实际网络环境】 https://docs.thundercomm.com/turbox_doc/products/smart-modules/turbox…

计算机网络 (6)物理层的基本概念

前言 计算机网络物理层是OSI模型&#xff08;开放式系统互联模型&#xff09;中的第一层&#xff0c;也是七层中的最底层&#xff0c;它涉及到计算机网络中数据的物理传输。 一、物理层的主要任务和功能 物理层的主要任务是处理物理传输介质上的原始比特流&#xff0c;确保数据…

大模型(LLMs)微调篇

大模型&#xff08;LLMs&#xff09;微调篇 一、如果想要在某个模型基础上做全参数微调&#xff0c;究竟需要多少显存&#xff1f; 一般 n B的模型&#xff0c;最低需要 16-20 n G的显存。&#xff08;cpu offload基本不开的情况下&#xff09; 二、为什么SFT之后感觉LLM傻了…

企业网络链路聚合、数据抓包、远程连接访问实验

前言&#xff1a; 随着信息技术的飞速发展和企业业务的不断扩大&#xff0c;企业网络面临着越来越多的挑战。其中&#xff0c;网络带宽、数据安全和远程访问等问题尤为突出。为了解决这些问题&#xff0c;我们进行了本次企业网络链路聚合、数据抓包和远程连接访问的实验。 链路…

移除元素(leetcode 27)

给定一个数组&#xff0c;在数组中删除等于这个目标值的元素&#xff0c;然后返回新数组的大小 数组理论&#xff1a; 数组是一个连续的类型相近的元素的一个集合&#xff0c;数组上的删除是覆盖&#xff0c;只能由后面的元素进行覆盖&#xff0c;而不能进行真正意义上的地理位…

前端面试笔试(三)

目录 一、数据结构算法等综合篇 二、代码输出篇 1.yield与生成器函数 2.this指向有关 3.instanceof 与Array.isArray 4.继承class cls extends Array&#xff0c;调用里面的sum方法 三、css、html、JavaScript篇 1.哪项不能提高dom元素操作效率&#xff1f; 2.contente…

7.高可用集群架构Keepalived双主热备原理

一. 高可用集群架构Keepalived双主热备原理 (1)主机+备机keepalived配置(192.168.1.171) ! Configuration File for keepalivedglobal_defs {# 路由id:当前安装keepalived节点主机的标识符,全局唯一router_id keep_101 } #计算机节点(主机配置) vrrp_instance VI_1 {</

IntelliJ IDEA 2023.2x——图文配置

IntelliJ IDEA 2023.2——配置说明 界面如下图所示 : 绿泡泡查找 “码猿趣事” 查找【idea99】 IntelliJ IDEA 的官方下载地址 IntelliJ IDEA 官网下载地址 一路上NEXT 到结尾&#xff1a; 继续NEXT 下一步:

Linux网络:守护进程

Linux网络&#xff1a;守护进程 会话进程组会话终端 守护进程setsiddaemon 在创建一个网络服务后&#xff0c;往往这个服务进程是一直运行的。但是对于大部分进程来说&#xff0c;如果退出终端&#xff0c;这个终端上创建的所有进程都会退出&#xff0c;这就导致进程的生命周期…

Linux Android 正点原子RK3568替换开机Logo完整教程

0.这CSDN是有BUG吗?大家注意:表示路径的2个点号全都变成3个点号啦! 接下来的后文中,应该是2个点都被CSDN变成了3个点: 1.将这两个 bmp 图片文件720x1280_8bit拷贝到内核源码目录下,替换内核源码中默认的 logo 图片。注意:此时还缺少电量显示图片 2.编译内核 make d…

安卓开发作业

整体效果: 安卓小作业 [TOC](页面配置) 整体框架有4个fragment页面,聊天,朋友,发现,设置. 配置如下: bash <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android" xm…

2024-ISCTF WP

Web 25时晓山瑞希生日会 经典 HTTP 头伪造&#xff0c;伪造流程如下&#xff1a; User-Agent: Project Sekai //伪造UA头 X-Forwarded-For:127.0.0.1 //伪造本地用户 伪造日期是本题最大的坑点&#xff0c;一直在想怎么伪造 25 时&#xff0c;没想到是二刺螈 搜索得知 …