微信小程序文字转语音播放

我们用到的是微信小程序的同声传译小插件,首先去开通这个插件

微信同声传译 | 小程序插件 | 微信公众平台

这个插件可以实现

  • 语音转文字

  • 语音合成

  • 文本翻译

 接下来开发的第一步,

将富文本转为纯文字,下面是封装好的方法可以直接使用

// 富文本转纯文字
export function RichToText(richText) {
	return richText.replace(/<[^>]+>/g, "").replace(/&nbsp;/g, " ")
		.replace(/&amp;/g, "&")
		.replace(/&lt;/g, "<")
		.replace(/&gt;/g, ">")
		.replace(/&quot;/g, '"')
		.replace(/&apos;/g, "'")
		.replace(/&#39;/g, "'")
		.replace(/&ldquo;/g, '"')
		.replace(/&rdquo;/g, '"')
		.replace(/&lsquo;/g, "'")
		.replace(/&rsquo;/g, "'")
		.replace(/&mdash;/g, "—")
		.replace(/&ndash;/g, "–");
}

第二步,进行语音合成,将文本合成语音,这里官方提供的插件有一个限制,就是单次合成的内容大小是1000字节,

如果当我们字数较多时候,我们可以分段去合成,并存储他们的顺序(因为合成的时候,有的文字多,有的文字少,所以会导致合成回来的语音顺序会乱),语音合成方法如下,先把你所有的内容按照一定的长度进行分段,然后分别进行语音合成,记得带顺序

//	文本长度和你每段能翻译的长度进行对比,100字节==500汉字,安全起见,我们可以把长度给小一点	
	
if (this.text.length > 300) {
	this.count = Math.ceil(this.text.length / this.size)
	for (let i = 0; i <= this.text.length; i += this.size) {
		const label = this.text.slice(i, i + this.size)
        //分段进行语音合成,并把顺序传入
		this.openVoice(label, i).then(res => {
		    this.voiceUrl.push(res)   //将合成的语音及顺序存入数组
	    })
	}
} else {
	this.count = 1
	console.log('text', this.text)
	openVoice(this.text, 0).then(res => {
		this.voiceUrl = [res]
	})
}
const plugin = requirePlugin('WechatSI');

// 语音合成
export function openVoice(label, sort) {
	return new Promise((resolve, reject) => {
		plugin.textToSpeech({
			lang: "zh_CN",
			tts: true,
			content: label,
			success: (res) => {
				resolve({
					url: res.filename,
					sort
				})
			},
			fail: (res) => {
				reject(res)
			}
		})
	})
}

第三步,就可以进行语音的播放和暂停和停止啦

const innerAudioContext = wx.createInnerAudioContext()

// 语音播放
yuyinPlay() {
	if (this.voiceUrl.length == 0) return;
    //将前面存的带顺序的音频数组进行排序
	const urlArr = this.voiceUrl.sort((a, b) => a.sort - b.sort).map(i => i.url)
	function play(index) {
		innerAudioContext.src = urlArr[index]; //设置音频地址
		innerAudioContext.play(); //播放音频
	}
	play(this.curIndex) //存储一个全局的curIndex,以便暂停的时候继续播放
    //音频自然播放结束事件	
	innerAudioContext.onEnded(() => {
	    if (this.curIndex + 1 >= this.count) {
			innerAudioContext.destroy() //多次会调用播放新的文件时,提前销毁实例,可避免-99错误
			innerAudioContext = null
			return
		}
		this.curIndex++
		play(this.curIndex)
	})
},
// 语音暂停
yuyinPause() {
	innerAudioContext.pause()
},
// 退出播放--结束播放
yuyinEnd() {
	innerAudioContext.stop()
	innerAudioContext.destroy() //多次会调用播放新的文件时,提前销毁实例,可避免-99错误
	innerAudioContext = null
},

以上就是完整的播放啦

完整代码附上

 

<template>
	<view class="">
		<view class="liste-all" @click="yuyinPlay">
			<u-icon name="volume-up" color="#2878FF" size="40"></u-icon>
			听全文
		</view>
		<!-- 播放悬浮窗 -->
		<view class="float-audio" :style="{right: floatShow?'25rpx':'-100%'}">
			<image :src="coverImg" mode="" class="img"></image>
			<view class="icon-list">
				<u-icon name="pause" @click="yuyinPause" size='36' v-if="pauseShow==true"></u-icon>
				<u-icon name="play-right-fill" @click="yuyinPlay" size='36' v-else></u-icon>
				<u-icon name="close" @click="yuyinEnd" size='36'></u-icon>
			</view>
		</view>
	</view>
	</view>
</template>

<script>
	const innerAudioContext = wx.createInnerAudioContext()
	import {
		RichToText,
		openVoice
	} from '@/utils/utils.js'

	export default {
		data() {
			return {
				text: '放入你想朗读的内容,如果是纯文本,则不需要使用RichToText方法',
				voiceUrl: [],
				size: 300, //一次读取最大值
				count: 1,
				curIndex: 0,
				pauseShow: false,
				floatShow: false,
			}
		},
		onLoad(option) {
			this.toText(this.text)
		},
		onBackPress(options) {
			innerAudioContext.stop()
		},
		methods: {
			// 富文本转纯文字
			toText(val) {
				if (val != null && val != '') {
					this.text = RichToText(val)
					if (this.text.length > this.size) {
						this.count = Math.ceil(this.text.length / this.size)
						for (let i = 0; i <= this.text.length; i += this.size) {
							const label = this.text.slice(i, i + this.size)
							this.openVoice(label, i).then(res => {
								this.voiceUrl.push(res)
							})
						}
					} else {
						this.count = 1
						console.log('text', this.text)
						openVoice(this.text, 0).then(res => {
							this.voiceUrl = [res]
						})
					}
				} else return ''
			},
			// 语音播放
			yuyinPlay() {
				if (this.voiceUrl.length == 0) return;
				this.floatShow = true
				this.pauseShow = true
				const urlArr = this.voiceUrl.sort((a, b) => a.sort - b.sort).map(i => i.url)

				function play(index) {
					innerAudioContext.src = urlArr[index]; //设置音频地址
					innerAudioContext.play(); //播放音频
				}
				play(this.curIndex)
				innerAudioContext.onEnded(() => {
					if (this.curIndex + 1 >= this.count) {
						this.floatShow = false
						innerAudioContext.destroy() //销毁当前实例
						innerAudioContext = null
						return
					}
					this.curIndex++
					play(this.curIndex)
				})
			},
			// 语音暂停
			yuyinPause() {
				this.pauseShow = false
				innerAudioContext.pause()
			},
			// 退出播放--结束播放
			yuyinEnd() {
				this.floatShow = false
				innerAudioContext.stop()
				innerAudioContext.destroy() //销毁当前实例
				innerAudioContext = null
			},
		},
	}
</script>

<style lang="scss" scoped>
	.float-audio {
		width: 220rpx;
		height: 227rpx;
		position: fixed;
		top: 530rpx;
		// right: 25rpx;
		background: #ffffff;
		border-radius: 16rpx;
		padding: 5rpx;
		box-sizing: border-box;
		transition: all 0.5s ease-in-out;

		.icon-list {
			display: flex;
			align-items: center;
			justify-content: space-between;
			padding: 0 25rpx;
		}

		.img {
			flex-shrink: 0;
			width: 210rpx;
			height: 160rpx;
			border-radius: 16rpx;
		}
	}
</style>

  • 8
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值