Uniapp 安卓实现讯飞语音听写(复制即用)

        在移动应用开发中,语音交互功能能够极大提升用户体验,让操作更加便捷自然。讯飞语音听写技术凭借其高准确率和稳定性,成为众多开发者的选择。本文将详细介绍如何在 Uniapp 项目中,实现安卓端的讯飞语音听写功能,帮助你快速为应用增添实用的语音交互能力。
        但是,由于uniapp录音管理器 uni.getRecorderManager()的实时监听音频大小帧的功能onFrameRecorded不支持app,app端只能在录音结束后获取临时录音文件,因此需要把录音文件转成base64,在切片传输给讯飞的接口。

一、准备工作​

1. 注册讯飞开放平台账号​

首先,你需要前往讯飞开放平台注册账号,完成实名认证。认证通过后,你将获得使用讯飞相关服务的权限。​

2. 创建应用并获取 AppID 和密钥​

在讯飞开放平台控制台中,创建一个新的应用。创建成功后,你会得到该应用的 AppID、AppKey 和 AppSecret,这些信息在后续集成过程中至关重要,用于验证应用身份。​

二、实现代码

以下是已经实现的uniapp在app端的一个简单的利用讯飞语音听写api完成的语音识别的demo,复制代码到你的项目中,把你申请的appid、apiSecret、apiKey替换到代码中,即可运行识别。

<template><div class="asr"><button class="btn" shape="circle" type="info" @touchstart="openMedia" @touchend="stopMedia">按住说话</button><view v-if="show" class="iating"><text text="正在说话中...." color="#49ABFE" size="27rpx" line-height="60rpx" align="center"></text></view></div>
</template><script>
import CryptoJS from "crypto-js";export default {data() {return {config: {hostUrl: "wss://iat-api.xfyun.cn/v2/iat",host: "iat-api.xfyun.cn",appid: "申请的讯飞appid",apiSecret: "申请的讯飞apiSecret",apiKey: "申请的apiKey",uri: "/v2/iat",highWaterMark: 1280,},uniSocketTask: null,show: false,resultText: "",resultTextTemp: "",renderText: ""};},methods: {// 鉴权签名getAuthStr(date) {let signatureOrigin = `host: ${this.config.host}\ndate: ${date}\nGET ${this.config.uri} HTTP/1.1`;let signatureSha = CryptoJS.HmacSHA256(signatureOrigin, this.config.apiSecret);let signature = CryptoJS.enc.Base64.stringify(signatureSha);let authorizationOrigin =`api_key="${this.config.apiKey}", algorithm="hmac-sha256", headers="host date request-line", signature="${signature}"`;let authStr = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(authorizationOrigin));return authStr;},getUrl() {let date = new Date().toUTCString();let wssUrl =this.config.hostUrl +"?authorization=" +this.getAuthStr(date) +"&date=" +encodeURIComponent(date) +"&host=" +this.config.host;console.log("websocke科大讯飞的地址为", wssUrl);return wssUrl;},// 打开麦克风openMedia() {this.connectSocket();},// 创建连接并返回数据connectSocket() {if (this.uniSocketTask === null) {this.uniSocketTask = uni.connectSocket({url: this.getUrl(),success() {},});this.uniSocketTask.onOpen(() => {console.log("监听到开启连接成功");this.startRecord();});this.uniSocketTask.onClose(() => {console.log("监听到关闭连接成功");this.uniSocketTask = null;});this.uniSocketTask.onError(() => {console.log("监听到连接发生错误");});this.uniSocketTask.onMessage((res) => {const message = JSON.parse(res.data);if (res.data) {console.log("收到服务器消息,并开始渲染", message);this.renderResult(message);if (message.code === 0 && message.data.status === 2) {console.log('最后一条', this.renderText);this.closeSocket();// 注意:这里需要根据实际情况处理事件触发// this.$emit('renderText', this.renderText);}if (message.code !== 0) {this.closeSocket();console.error(message);}} else {console.log("未监听到消息:原因:", JSON.stringify(res));}});} else {console.log("socketTask实例已存在");}},// 发送给科大讯飞的第一帧的模板数据格式getInitialFrame() {return {common: {app_id: this.config.appid,},business: {language: "zh_cn",domain: "iat",accent: "mandarin",dwa: "wpgs", // 可选参数,动态修正vad_eos: 5000,},data: {status: 0,format: "audio/L16;rate=16000",encoding: "lame"},};},// 发送消息sendMessage(sendData) {console.log('发送', JSON.stringify(sendData));this.uniSocketTask.send({data: JSON.stringify(sendData),success() {},fail() {console.log("发送失败");},});},// 关闭连接closeSocket() {console.log("开始尝试关闭连接");this.uniSocketTask.close();},// 开启录音startRecord() {const recordOption = {sampleRate: 16000,format: "mp3",};const recordManager = uni.getRecorderManager();recordManager.onStart(() => {console.log("开始录音");this.show = true;});recordManager.onStop((res) => {console.log("录音停止,文件路径为:", res.tempFilePath);this.sendMessage(this.getInitialFrame());this.pathToBase64(res.tempFilePath).then(base64 => {let buff = base64.split(",")[1];const arrayBuffer = uni.base64ToArrayBuffer(buff);const audioString = this.toString(arrayBuffer);console.log("文件读取成功", audioString.length);let offset = 0;while (offset < audioString.length) {const subString = audioString.substring(offset, offset + 1280);offset += 1280;const isEnd = offset >= audioString.length;let params = {data: {status: isEnd ? 2 : 1,format: "audio/L16;rate=16000",encoding: "lame",audio: btoa(subString)}};this.sendMessage(params);}}).catch(error => {console.error(error);});});recordManager.onError((err) => {console.log("录音出现错误", err);});recordManager.start(recordOption);},// 关闭录音stopMedia() {const recordManager = uni.getRecorderManager();recordManager.stop();this.show = false;},// 工具方法toString(buffer) {var binary = '';var bytes = new Uint8Array(buffer);var len = bytes.byteLength;for (var i = 0; i < len; i++) {binary += String.fromCharCode(bytes[i]);}return binary;},// 录音文件路径转base64pathToBase64(path) {return new Promise((resolve, reject) => {if (typeof plus === 'object') {plus.io.resolveLocalFileSystemURL(path, function(entry) {entry.file(function(file) {var fileReader = new plus.io.FileReader();fileReader.onload = function(evt) {resolve(evt.target.result);};fileReader.onerror = function(error) {reject(error);};fileReader.readAsDataURL(file);}, function(error) {reject(error);});}, function(error) {reject(error);});return;}reject(new Error('not support'));});},// 讯飞回复字段拼接renderResult(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;}if (data.pgs) {if (data.pgs === "apd") {this.resultText = this.resultTextTemp;}this.resultTextTemp = this.resultText + str;} else {this.resultText = this.resultText + str;}this.renderText = this.resultTextTemp || this.resultText || "";}console.log("渲染后的数据为", this.renderText);}}
}
</script><style scoped>
.asr {display: flex;justify-content: center;padding: 20rpx;
}.btn {width: 200rpx;height: 200rpx;
}.iating {position: fixed;top: 50%;left: 50%;transform: translate(-50%, -50%);display: flex;flex-direction: column;align-items: center;background-color: rgba(0, 0, 0, 0.7);padding: 30rpx;border-radius: 20rpx;z-index: 999;
}</style>    

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

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

相关文章

【golang】DNS 资源记录(RR)接口

Go 中 miekg/dns 包对 DNS 资源记录&#xff08;RR&#xff09;接口 的定义&#xff1a; type RR interface {Header() *RR_HeaderString() stringcopy() RRlen(off int, compression map[string]struct{}) intpack(...)unpack(...)parse(...)isDuplicate(r2 RR) bool }这个接…

16.2 VDMA视频转发实验之模拟源

文章目录 1 实验任务2 系统框图3 硬件设计3.1 IP核配置3.2 注意事项3.3 自定义IP核源码 4 软件设计4.1 注意事项4.2 工程源码4.2.1 main.c文件 1 实验任务 基于14.1&#xff0c;相较于16.1&#xff0c;使用自定义IP核vid_gen_motion替换Xilinx TPG IP核。 2 系统框图 基于14…

深度学习之用CelebA_Spoof数据集搭建一个活体检测-训练好的模型用MNN来推理

一、模型转换准备 首先确保已完成PyTorch到ONNX的转换&#xff1a;深度学习之用CelebA_Spoof数据集搭建活体检测系统&#xff1a;模型验证与测试。这里有将PyTorch到ONNX格式的模型转换。 二、ONNX转MNN 使用MNN转换工具进行格式转换&#xff1a;具体的编译过程可以参考MNN的…

JVM学习专题(一)类加载器与双亲委派

目录 1、JVM加载运行全过程梳理 2、JVM Hotspot底层 3、war包、jar包如何加载 4、类加载器 我们来查看一下getLauncher&#xff1a; 1.我们先查看getExtClassLoader() 2、再来看看getAppClassLoader(extcl) 5、双亲委派机制 1.职责明确&#xff0c;路径隔离​&#xff…

部署安装gitlab-ce-17.9.7-ce.0.el8.x86_64.rpm

目录 ​编辑 实验环境 所需软件 实验开始 安装部署gitlab171.配置清华源仓库&#xff08;版本高的系统无需做&#xff09;vim /etc/yum.repos.d/gitlab-ce.repo 2.提前下载包dnf localinstall gitlab-ce-17.9.7-ce.0.el8.x86_64.rpm --rocklinux 3.修改配…

使用LoRA微调Qwen2.5-VL-7B-Instruct完成电气主接线图识别

使用LoRA微调Qwen2.5-VL-7B-Instruct完成电气主接线图识别 动机 任务适配需求 Qwen2.5-VL在视觉理解方面表现优异&#xff0c;但电气主接线图识别需要特定领域的结构化输出能力&#xff08;如设备参数提取、拓扑关系解析&#xff09;。微调可增强模型对专业符号&#xff08;如…

系统集成项目管理工程师学习笔记

第九章 项目管理概论 1、项目基本要素 项目基础 项目是为创造独特的产品、服务或成果而进行的临时性工作。 项目具有临时性、独特性、渐进明细的特点。项目的“临时性”是指项目只有明确的起点和终点。“临时性”并一定意味着项目的持续时间短。 项目可宣告结束的情况&…

Secs/Gem第七讲(基于secs4net项目的ChatGpt介绍)

好的&#xff0c;那我们现在进入&#xff1a; 第七讲&#xff1a;掉电重连后&#xff0c;为什么设备不再上报事件&#xff1f;——持久化与自动恢复的系统设计 关键词&#xff1a;掉电恢复、状态重建、初始化流程、SecsMessage 缓存机制、自动重连、事件再注册 本讲目标 你将理…

室内定位:热门研究方向与未解难题深度解析

I. 引言:对普适性室内定位的持续探索 A. 室内定位在现代应用中的重要性 室内定位系统(IPS)正迅速成为众多应用领域的基石技术,其重要性源于现代社会人们约70%至90%的时间在室内度过的事实 1。这些应用横跨多个行业,包括应急响应 1、智能建筑与智慧城市 6、医疗健康(如病…

Android学习总结之Glide自定义三级缓存(实战篇)

一、为什么需要三级缓存 内存缓存&#xff08;Memory Cache&#xff09; 内存缓存旨在快速显示刚浏览过的图片&#xff0c;例如在滑动列表时来回切换的图片。在 Glide 中&#xff0c;内存缓存使用 LruCache 算法&#xff08;最近最少使用&#xff09;&#xff0c;能自动清理长…

Linux的文件查找与压缩

查找文件 find命令 # 命令&#xff1a;find 路径范围 选项1 选项1的值 \[选项2 选项2 的值…]# 作用&#xff1a;用于查找文档&#xff08;其选项有55 个之多&#xff09;# 选项&#xff1a;# -name&#xff1a;按照文档名称进行搜索&#xff08;支持模糊搜索&#xff0c;\* &…

python处理异常,JSON

异常处理 #异常处理 # 在连接MySQL数据库的过程中&#xff0c;如果不能有效地处理异常&#xff0c;则异常信息过于复杂&#xff0c;对用户不友好&#xff0c;暴露过多的敏感信息 # 所以&#xff0c;在真实的生产环境中&#xff0c; 程序必须有效地处理和控制异常&#xff0c;按…

线程的两种实现方式

线程的两种实现方式——内核支持线程&#xff08;kernal Supported Thread, KST&#xff09;&#xff0c; 用户级线程&#xff08;User Level Thread, ULT&#xff09; 1. 内核支持线程 顾名思义&#xff0c;内核支持线程即为在内核支持下的那些线程&#xff0c;它们的创建&am…

vue3基础学习(上) [简单标签] (vscode)

目录 1. Vue简介 2. 创建Vue应用 2.1 下载JS文件 2.2 引用JS文件 2.3 调用Vue方法​编辑 2.4 运行一下试试: 2.5 代码如下 3.模块化开发模式 3.1 Live Server插件 3.2 运行 4. 常用的标签 4.1 reactive 4.1.1 运行结果 4.1.2 代码: 4.2 ref 4.2.1 运行结果 4.2.2…

自定义分区器-基础

什么是分区 在 Spark 里&#xff0c;弹性分布式数据集&#xff08;RDD&#xff09;是核心的数据抽象&#xff0c;它是不可变的、可分区的、里面的元素并行计算的集合。 在 Spark 中&#xff0c;分区是指将数据集按照一定的规则划分成多个较小的子集&#xff0c;每个子集可以独立…

深入解析HTTP协议演进:从1.0到3.0的全面对比

HTTP协议作为互联网的基础协议&#xff0c;经历了多个版本的迭代演进。本文将详细解析HTTP 1.0、HTTP 1.1、HTTP/2和HTTP/3的核心特性与区别&#xff0c;帮助开发者深入理解网络协议的发展脉络。 一、HTTP 1.0&#xff1a;互联网的奠基者 核心特点&#xff1a; 短连接模式&am…

基于windows环境Oracle主备切换之后OGG同步进程恢复

基于windows环境Oracle主备切换之后OGG同步进程恢复 场景&#xff1a;db1是主库&#xff0c;db2是备库&#xff0c;ogg从db2备库抽取数据同步到目标数据库 db1 - db2(ADG) – ogg – targetdb 场景&#xff1a;db2是主库&#xff0c;db1是备库&#xff0c;ogg从db1备库抽取数…

微服务,服务粒度多少合适

项目服务化好处 复用性&#xff0c;消除代码拷贝专注性&#xff0c;防止复杂性扩散解耦合&#xff0c;消除公共库耦合高质量&#xff0c;SQL稳定性有保障易扩展&#xff0c;消除数据库解耦合高效率&#xff0c;调用方研发效率提升 微服务拆分实现策略 统一服务层一个子业务一…

【工奥阀门科技有限公司】签约智橙PLM

近日&#xff0c;工奥阀门科技有限公司正式签约了智橙泵阀行业版PLM。 忠于质量&#xff0c;臻于服务&#xff0c;精于研发 工奥阀门科技有限公司&#xff08;以下简称工奥阀门&#xff09;坐落于浙江永嘉&#xff0c;是一家集设计、开发、生产、销售、安装、服务为一体的阀门…

2025-5-15Vue3快速上手

1、setup和选项式API之间的关系 (1)vue2中的data,methods可以与vue3的setup共存 &#xff08;2&#xff09;vue2中的data可以用this读取setup中的数据&#xff0c;但是反过来不行&#xff0c;因为setup中的this是undefined &#xff08;3&#xff09;不建议vue2和vue3的语法混用…