uniapp中实现语音识别(app+小程序)

news2024/11/16 9:54:52

一.app版本需要先去百度智能云申请
在这里插入图片描述

注意填写完,需要打包成自定义基座或者安装rpk包,本地是无效的

封装recording-popup.vue组件

<template>
	<up-popup round="16" closeable :show="recordShow" :close-on-click-overlay="false" :safe-area-inset-bottom="false"
		@close="close" @open="open">
		<view class="tag-popup-box">
			<view class="title">
				<text>{{ tips }}</text>
				<image
					src="https://observe-oss.oss-cn-shanghai.aliyuncs.com/wisdom-bay-vue/home/home-icon-close-gray-20.075vw%402x.png"
					@click="close" />
			</view>
			<view class="voice-box">
				<image
					src="https://observe-oss.oss-cn-shanghai.aliyuncs.com/wisdom-bay-vue/home/home-release-recording-blue-90px%402x.png"
					class="voice-icon" @click="startRecord" />
			</view>
		</view>
	</up-popup>
</template>
<script setup>
	import {
		onBeforeUnmount,
		onMounted,
		ref,
		watch
	} from "vue";
	const recordShow = ref(false)
	const tips = ref('点击开始录音')
	const emits = defineEmits(['micInput'])

	const startRecord = async () => {
		// #ifdef H5
		uni.showToast({
			title: '浏览器暂不支持该功能,请前往APP体验',
			icon: 'none',
			duration: 2000
		})
		// #endif

		// #ifdef APP-PLUS
		let options = {
			engine: 'baidu',
			timeout: 10 * 1000, //超时时间
			punctuation: true, //是否需要标点符号
			continue: true, //语音识别是否采用持续模式
			userInterface: true, //安卓手机为true时会影响@touchend触摸结束事件,暂未发现好的解决方法
		};
		plus.speech.startRecognize(options, (s) => {
			emits('micInput', s)
		}, (errMsg) => {
			console.log('语音识别失败:' + JSON.stringify(errMsg));
		});
		// #endif
	}
	
	const onEnd = () => {
		close()
	}

	const open = () => {
		// #ifdef H5
		uni.showToast({
			title: '浏览器暂不支持该功能,请前往APP体验',
			icon: 'none',
			duration: 2000
		})
		// #endif
		// #ifdef APP-PLUS
		const info = uni.getAppAuthorizeSetting();
		if(info.microphoneAuthorized !== 'authorized') {
			plus.nativeUI.toast('请打开麦克风权限,再重启应用');
			return false;
		}
		plus.speech.addEventListener('end', onEnd, false);
		// #endif
	}
	const close = () => {
		recordShow.value = false
		// #ifdef APP-PLUS
		plus.speech.stopRecognize();
		// #endif
	}

	onBeforeUnmount(() => {
		// #ifdef APP-PLUS
		plus.speech.stopRecognize();
		// #endif
	})

	defineExpose({
		recordShow
	})
</script>
<style scoped lang="scss">
	.tag-popup-box {
		height: 19.655vw;
		background: #FFFFFF;
		width: 100%;
		padding: 1.5vw 1.5vw 0;
		box-sizing: border-box;
		border-radius: 1.2vw 1.2vw 0vw 0vw;

		.voice-box {
			width: 100%;
			display: flex;
			justify-content: center;
			margin-top: 2.251vw;

			.voice-icon {
				width: 6.752vw;
				height: 6.752vw;
			}
		}

		.title {
			display: flex;
			justify-content: space-between;
			align-items: center;
			margin-bottom: 2.251vw;

			&>text {
				font-size: 1.125vw;
				font-family: PingFangSC-Medium, PingFang SC;
				font-weight: 500;
				color: #333333;
				line-height: 1.65vw;
			}

			&>image {
				width: 1.65vw;
				height: 1.65vw;
			}
		}

		.content {
			width: 100%;
			height: 3.601vw;
			background: rgba(153, 153, 153, 0.08);
			border-radius: 0.45vw;
			padding: 0 0.975vw;
			box-sizing: border-box;
		}

		.confirm-btn {
			margin-top: 5.176vw;
			width: 100%;
			height: 3vw;
			text-align: center;
			background: #07B780;
			border-radius: 0.3vw;
			font-size: 1.05vw;
			font-family: PingFangSC-Regular, PingFang SC;
			font-weight: 400;
			color: #FFFFFF;
			line-height: 3vw;
		}
	}
</style>

使用recording-popup

<recording-popup ref="recordingPopupRef" @mic-input="micInput" />

const recordingPopupRef = ref('')
const text = ref('')
		
const openRecord = () => {
	  recordingPopupRef.value.recordShow = true
},
const micInput = (str) => {
   //如果你知道输入框的cursor,就可以像我这样写,要是不知道就写成text.value += str了
	if (cursor === 0) {
			text.value += str
	} else {
			text.value = text.value.slice(0, cursor) + str + text.value.slice(cursor);
	}
}

二.小程序版本,进入微信小程序后台-->进入设置-->第三方设置-->添加插件->搜索同声传译-->完成添加。
在这里插入图片描述
在manifest.json文件中增加插件版本等信息

 "mp-weixin" : {
   "plugins" : {
            "WechatSI" : {
                "version" : "0.3.5",
                "provider" : ""
            }
        },
 }

封装recording-popup.vue组件

<template>
  <view>
    <u-popup
      round="16" :show="recordShow" :close-on-click-overlay="false"
      :safe-area-inset-bottom="false"
      @close="close"
      @open="open"
    >
      <view class="tag-popup-box">
        <view class="title">
          <text>{{ tips }}</text>
          <image
            src=""
            @click="close"
          />
        </view>
        <view class="voice-box" @touchstart="startRecord" @touchend="stopRecord" @touchcancel="stopRecord">
          <image
            src=""
            class="voice-icon"
          />
        </view>
      </view>
    </u-popup>
  </view>
</template>
<script setup lang="ts">
import {onMounted, ref, watch} from "vue";
let start = false
const tips = ref<string>('按住开始录音')
const props = defineProps({
  show: {
    type: Boolean,
    default: false
  }
})
const manager = ref<any>()
const emits = defineEmits(['update:show','startRecord','textChange','micInput'])

const startRecord = async () => {
  if (start) return // 防止还在识别中时又触发录音
  console.log('touch started')
  tips.value = '准备中...'
  try {
    await checkPermission()
  } catch (e) {
    tips.value = '需要授权'
    return
  }
  manager.value.start()
  emits("startRecord")
}

const stopRecord = () => {
  if (!start) return // 触发极短时间,stop会在还未start的情况下触发
  console.log('touch ended or canceled')
  manager.value.stop()
}


watch(() => props.show, (value) => {
  recordShow.value = value
})

const recordShow = ref<boolean>(props.show)
const open = () => {
  manager.value = requirePlugin("WechatSI").getRecordRecognitionManager()
  // recordShow.value = true
  manager.value.onStart = (e:any) => {
    console.log('on-start')
    console.log(e)
    start = true
    tips.value = '正在识别...'
  }
  manager.value.onStop = (e:any) => {
    console.log('on-stop')
    console.log(e)
    start = false
    if (e.result){
      tips.value = '按住开始录音'
      emits("micInput", e.result)
    } else {
      tips.value = '识别失败,请重试'
    }
  }
  manager.value.onRecognize = (e:any) => {
    console.log('on-recognize')
    console.log(e)
  }
  manager.value.onError = (e:any) => {
    console.log('on-error')
    console.log(e)
    start = false
    tips.value = '识别失败,请重试'
  }
}
const close = () => {
  recordShow.value = false
  emits('update:show', recordShow.value)
}


const  checkPermission = async () => {
  const sRes = await uni.getSetting()
  if (sRes.authSetting['scope.record']) return
  try {
    const aRes = await uni.authorize({
      scope: 'scope.record'
    })
  } catch (e) {
    const mRes = await uni.showModal({
      title: '授权',
      content: '请打开 录音功能 权限以便进行语音识别',
      showCancel: true,
    })
    if (mRes.cancel) throw new Error('授权失败')
    const sRes = await uni.openSetting()
    if (sRes.authSetting['scope.record']) {
      uni.showModal({
        title: '授权成功',
        content: '请继续点击下方按钮 进行语音输入',
        showCancel: false
      })
      throw new Error('授权成功')
    }
    throw new Error('授权失败')
  }
}
</script>
<style scoped lang="scss">
.tag-popup-box{
  height: 524rpx;
  background: #FFFFFF;
  width: 100%;
  padding: 40rpx 40rpx 0 ;
  box-sizing: border-box;
  border-radius: 32rpx 32rpx 0rpx 0rpx;
  .voice-box{
    width: 100%;
    display: flex;
    justify-content: center;
    margin-top: 60rpx;
    .voice-icon{
      width: 180rpx;
      height: 180rpx;
    }
  }

  .title{
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 60rpx;
    &>text{
      font-size: 30rpx;
      font-family: PingFangSC-Medium, PingFang SC;
      font-weight: 500;
      color: #333333;
      line-height: 44rpx;
    }
    &>image{
      width: 44rpx;
      height: 44rpx;
    }
  }
  .content{
    width: 100%;
    height: 96rpx;
    background: rgba(153, 153, 153, 0.08);
    border-radius: 12rpx;
    padding: 0 26rpx;
    box-sizing: border-box;
  }
  .confirm-btn{
    margin-top: 138rpx;
    width: 100%;
    height: 80rpx;
    text-align: center;
    background: #07B780;
    border-radius: 8rpx;
    font-size: 28rpx;
    font-family: PingFangSC-Regular, PingFang SC;
    font-weight: 400;
    color: #FFFFFF;
    line-height: 80rpx;
  }
}
</style>

使用recording-popup

<recording-popup :show="recordShow" @mic-input="micInput" />

const recordShow = ref<boolean>(false)
const text = ref('')

const open = () => {
recordShow.value = true
}
const micInput = (str) => {
   //如果你知道输入框的cursor,就可以像我这样写,要是不知道就写成text.value += str了
	if (cursor === 0) {
			text.value += str
	} else {
			text.value = text.value.slice(0, cursor) + str + text.value.slice(cursor);
	}
}

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

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

相关文章

计算机网络—电路、分组、报文交换—图文详解

计算机网络—电路、分组、报文交换 计算机网络中的数据传输方式可以根据数据的处理方式和网络资源的使用方式分为电路交换、分组交换和报文交换三种类型。 这些方式在网络设计和数据传输过程中起到了不同的作用和效果。 1. 电路交换&#xff08;Circuit Switching&#xff0…

数字中国:智能交通的未来发展方向

随着数字中国的不断推进&#xff0c;智能交通作为数字化时代的一个重要领域&#xff0c;正面临着前所未有的机遇和挑战。人工智能、大数据应用和物联网等新兴技术的加入&#xff0c;不仅改变了传统交通的运行模式&#xff0c;还赋予了智能交通更多的功能和价值。首先&#xff0…

Convert Ensembl IDs to gene symbols python包

links&#xff1a; https://pypi.org/project/ensembl-converter/ pip install Ensembl_converter批量转&#xff1a; from Ensembl_converter import EnsemblConverter# Create an instance of EnsemblConverter converter EnsemblConverter()# Provide a list of Ensembl …

IEC MMS协议源码运行

环境准备 源码下载链接 https://github.com/mz-automation/libiec61850 我的运行环境是ubuntu虚拟机。 首先进入文件夹根目录进行编译 make clean makeserver代码的编译和运行 进入examples/serve_example_simpler的目录下编译 直接执行会发现报错&#xff0c;异常退出。 …

JLink烧录失败

1. 现象&#xff1a; 这个位置是灰色的&#xff0c;没有SW Device信息。 MDK下面的打印&#xff1a; J-Flash的打印&#xff1a; windows上面的弹框的现象没有截屏。 2. 解决办法&#xff1a; 1.打开J-Link Commander,输入unlock kinetis&#xff0c;看现象不起作用,网…

Python学习笔记48:游戏篇之外星人入侵(九)

前言 到目前为止&#xff0c;飞船&#xff0c;子弹&#xff0c;外星人的创建&#xff0c;移动都已经完成。接下来我们需要完成功能主要就是子弹击中外星人和飞船接触到外星人两个中功能。 碰撞 我们需要实现的功能中&#xff0c;子弹击中外星人和飞船接触外星人本质上就是两…

Navicat For Mysql连接Mysql8.0报错:客户端不支持服务器请求的身份验证协议

windows通过navicat连接本地mysql时报错:Client does not support authentication protocol requested by server; consider upgrading MySQL client 一、问题原因二、解决方法1--失败1. 连接mysql客户端2. 修改加密方式3.正确的解决方法1.查找my.ini文件2.修改my.ini文件3.重…

【读点论文】Object Detection in 20 Years: A Survey,宏观了解大方向发展,常看常新,这篇越看到后面越泛

Object Detection in 20 Years: A Survey Abstract 目标检测作为计算机视觉领域最基本、最具挑战性的问题之一&#xff0c;近年来受到了极大的关注。在过去的二十年里&#xff0c;我们目睹了目标检测技术的快速演进及其对整个计算机视觉领域的深远影响。如果说今天的目标检测…

关于RAG进展|| RankRAG:在大模型中统一检索增强生成的上下文排序

欢迎了解公众号&#xff1a;AI论文解读 背景&#xff1a;探索RankRAG的创新之处 检索增强生成&#xff08;Retrieval-Augmented Generation, RAG&#xff09;技术已成为提升大型语言模型&#xff08;Large Language Models, LLMs&#xff09;处理知识密集型任务的关键方法。传…

使用AI大模型Kimi轻松助力速通代理IP知识

本文目录 一、 引言二、代理IP介绍2.1 代理IP定义2.2 代理IP的工作原理2.3 代理IP的分类2.4 2.4 为什么需要代理IP&#xff1f; 三、代理IP的使用场景四、如何选择合适的代理IP服务五、使用代理IP的基本步骤六、使用代理IP爬取亚马逊电商信息七、总结八、代码附录 一、 引言 喜…

怎么使用rdma-core进行调用开发?

RDMA (Remote Direct Memory Access) 是一种网络协议,可以在计算节点之间实现高效的内存数据传输,而无需CPU的干预。rdma-core 是 RDMA 的一个用户空间库,提供了一些简单易用的接口来使用 RDMA 功能。 目录: 一、环境准备: 1.1 安装依赖 在安装 rdma-core 之前,确保你的…

token验证

验证客户端传输过来的请求是否合法 try-catch是用来捕获并处理异常的。当你在编写代码时&#xff0c;可能会遇到一些不可预见的情况&#xff0c;这些情况会阻止代码的正常执行&#xff0c;这时就会抛出异常。使用try-catch语句&#xff0c;你可以捕获这些异常并采取相应的措施来…

【OpenCV C++20 学习笔记】形态学变换(morphologyEx)

TOC 理论 开运算 开运算实际上就是腐蚀之后再膨胀&#xff0c;用公式表达就是&#xff1a; d s t o p e n ( s r c , e l e m e n t ) d i l a t e ( e r o d e ( s r c , e l e m e n t ) ) dstopen(src, element) dilate(erode(src, element)) dstopen(src,element)di…

保研408真题练习:2009年全国硕士研究生入学统一考试(单选篇2)

&#x1f9ca;&#x1f9ca;&#x1f9ca;单项选择题&#xff08;共40道&#xff09; &#x1f9ca;操作系统&#xff08;8道&#xff09; &#x1f965;1.进程调度算法 高响应比优先调度&#xff1a;选出响应比最高的进程投入执行&#xff0c;响应比R(等待时间&#xff0b;执…

钉钉 钉钉打卡 钉钉定位 2024 免费试用 保用

打卡助手定位 如图&#xff0c;表示开启成功&#xff0c;软件已定位到钉钉打卡位置。 测试显示&#xff0c;高德地图位置已成功修改。 开启助手定位后&#xff0c;观察效果&#xff0c;打卡按钮由无法打卡变为可打卡状态&#xff0c;照片还显示打卡地点。 伙伴们担心作弊行为会…

如何使用nodejs的fsPromise.access()判断文件权限

同学们可以私信我加入学习群&#xff01; 正文开始 一种错误示范fsPromise.access正确的书写总结 一种错误示范 我们操作文件的时候&#xff0c;经常需要提前判断文件的状态&#xff1a;文件是否存在、文件是否可读、文件是否可写。 查看官网介绍后&#xff0c;按照我们平时的…

WinRAR右键压缩文件功能消失。有什么方法可以恢复吗?

WinRAR作为一款广受欢迎的压缩软件&#xff0c;以其高效、便捷的特点深受用户喜爱。然而&#xff0c;在使用过程中&#xff0c;有时我们可能会遇到右键菜单中WinRAR的压缩文件功能消失的情况&#xff0c;这无疑给我们的文件操作带来了不便。下面小编就来给大家详细介绍当WinRAR…

【C语言】【计算机组成原理】进制转换和原码、反码、补码

目录 一、进制转换 &#xff08;1&#xff09;数字进制的4个概念 &#xff08;2&#xff09;x进制转换成十进制 &#xff08;3&#xff09;十进制转换成x进制&#xff08;除x取余法&#xff09; &#xff08;4&#xff09;二进制与八进制的相互转换 &#xff08;5&#xf…

【AI落地应用实战】DAMODEL深度学习平台部署+本地调用ChatGLM-6B解决方案

ChatGLM-6B是由清华大学和智谱AI开源的一款对话语言模型&#xff0c;基于 General Language Model (GLM)架构&#xff0c;具有 62亿参数。该模型凭借其强大的语言理解和生成能力、轻量级的参数量以及开源的特性&#xff0c;已经成为在学术界和工业界引起了广泛关注。 本篇将介…

成为 Spring Boot + Vue 图书作者的必备素养

个人名片 🎓作者简介:java领域优质创作者 🌐个人主页:码农阿豪 📞工作室:新空间代码工作室(提供各种软件服务) 💌个人邮箱:[2435024119@qq.com] 📱个人微信:15279484656 🌐个人导航网站:www.forff.top 💡座右铭:总有人要赢。为什么不能是我呢? 专栏导…