针对上一篇微信同声传译语音播报部分坑的解决和优化

news2024/11/20 3:20:05

1. 上一篇语音播报其实是不完美的,就是如何停止上一个音频开始下一个音频的问题,我在此做一下修改

在这里插入图片描述
比如说:现在正在播放1,我点击2让2开始播放,1停止播放,我上面的写法是有问题的:

  • 通过 innerAudioContext.pause() 是可以停止播放音频的;
  • wx.createInnerAudioContext()的实例,我是在readStart方法里面创建的
  • 再次执行readStart方法,会重新创建wx.createInnerAudioContext()实例
  • 我们如果在点击播放图标的时候执行pause() 方法,执行的不是正在播放的音频的实例

因此:我们需要创建一个全局的实例,这样我们执行pause() 方法时,在同一个实例下,就是停止正在播放的音频
代码如下:

	data:{
	dialogue:'您好,我是您的健康管家"向我提问。您好,我是您的健康管家"质迹"!您有什么疑问都可以在此向我提问。',
	type:'play'
	}
	// 在onLoad中创建一个全局的实例
	onLoad(){
		this.innerAudioContext = wx.createInnerAudioContext();
	}
  // 阅读文字
  readText: async function () {
    const that = this;
    // ------------------------------在点击播放图标之前,我们先执行一个pause()方法,停止上一段音频--------------------
    that.innerAudioContext.pause()
    that.setData({
      type :'pause'
    })
    // 将文字按照每200个长度截取成一段,组成一个数组
    // 切片处理,将超过1000个字符的文字,截取成几段
    let list =this.splitStringByLength(dialogue, 200)
    // 循环遍历数组,将文字转化成音频
    let radioList = list.map(el => {
      return new Promise(resolve => {
        plugin.textToSpeech({
          lang: "zh_CN",
          tts: true,
          content: el,
          success: function (res) {
            resolve(res.filename)
          },
          fail: function (res) {
            wx.showToast({
              title: '语音转换失败',
            })
          }
        })
      })
    })
    // 将promise执行结果放在一起执行(解决for循环中有异步操作的方法之一,经典面试题)
    // 有个弊端: 如果前面的promise有一个执行错误,Promise.all就不会执行,因此:可以用map/filter将radioList过滤一遍(本项目中有一个Promise执行失败,就应该失败)
    Promise.all(radioList).then(res => {
      that.readStart(res)
    })
  },
	// 将字符串每隔length个就截取一段
   splitStringByLength :function (str, length)  {
	  let result = [];
	  for (let i = 0; i < str.length; i += length) {
	    result.push(str.substring(i, i + length));
	  }
	  return result;
	}// 开始阅读
  readStart: async function (radioList) {
    const that = this
    for (let text of radioList) {
    // --------------------------在此就不需要再次创建实例了---------------------------
      // const innerAudioContext = wx.createInnerAudioContext();
      that.innerAudioContext.src = text;

      that.innerAudioContext.onPlay(() => {
        console.log('开始播放当前片段', 'onPlay');
      });

      that.innerAudioContext.onError((err) => {
        console.error('音频播放出错', err);
      });

      that.innerAudioContext.onEnded(async () => {
        // 如果是最后一个片段,这里可以结束,否则不需要await
        if (text === radioList[radioList.length - 1]) {
          that.setData({
            type: 'play',
          })
        }
      });
      // 确保前一个音频播放结束后再播放下一个
      await new Promise(resolve => {
        that.innerAudioContext.onEnded(resolve);
        that.innerAudioContext.play();
      });
    }
  },
  // 暂停阅读
  readPause: function () {
    this.innerAudioContext.pause()
    const that = this;
    that.setData({
      type: 'play',
    })
  }

2. 对于splitStringByLength方法,我也进行了一些优化 (wx.createInnerAudioContext()只支持1000个字符以内的文字转为音频)

下面一段代码是无脑按照长度切割,在进行语音播报的时候,第一段语音和第二段语音之前的衔接会有1-2秒的停顿,语音播报不流畅
比如:您好,我是您的健康管家"向我提问。您好,我是您的健康 | 管家"质迹"!您有什么疑问都可以在此向我提问。
在 | 处切成两段,语音在播放到‘康’的时候,会停顿1-2秒,在开始播放‘管家…’

splitStringByLength :function (str, length)  {
	  let result = [];
	  for (let i = 0; i < str.length; i += length) {
	    result.push(str.substring(i, i + length));
	  }
	  return result;
	}

在此,我对切割方法进行了一下优化

  • 不超过length的长度,不进行切割
  • 超过length的长度,首先找中文句号,在中文句号处切割
  • 如果整个文本都没有中文句号,则在中文逗号处切割
  • 语音在逗号和句号处本来就是会停顿的,在此处切割,这样用户的体验更好一些
const splitStringByLength = (text, length) => {
  const MAX_LENGTH = length;  // 最大长度
  const CHINESE_PERIOD = '。'; // 首个切割条件
  const CHINESE_COMMA = ',';  // 当首个切割条件不存在时的次要切割条件
  let result = [];
  let startIndex = 0;
  // 文本长度不超过最大长度,就不切割,直接返回
  if (text.length < MAX_LENGTH) {
    return [text]
  }
  while (startIndex < text.length) {
    // 查找下一个中文句号的位置,若找不到则返回-1
    let periodIndex = text.indexOf(CHINESE_PERIOD, startIndex);
    if (periodIndex === -1 || periodIndex - startIndex > MAX_LENGTH) {
      // 如果没有找到句号,或者句号距离起始点超过了300个字符
      // 则查找中文逗号的位置,同样,若找不到则返回-1
      let commaIndex = text.lastIndexOf(CHINESE_COMMA, startIndex + MAX_LENGTH);
      if (commaIndex === -1 || commaIndex <= startIndex) {
        // 如果也没有找到逗号,或者逗号位置不满足条件,则直接在MAX_LENGTH处截断
        result.push(text.substring(startIndex, startIndex + MAX_LENGTH));
        startIndex += MAX_LENGTH;
      } else {
        // 找到了逗号并且位置合适,就在逗号后分割
        result.push(text.substring(startIndex, commaIndex + 1));
        startIndex = commaIndex + 1;
      }
    } else {
      // 找到了句号并且位置合适,就在句号后分割
      result.push(text.substring(startIndex, periodIndex + 1));
      startIndex = periodIndex + 1;
    }
  }

  return result;
}

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

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

相关文章

编译器 编译过程 compiling 动态链接库 Linking 接口ABI LTO PGO inline bazel增量编译

编译器 编译过程 compiling 动态链接库 Linking 接口ABI LTO PGO Theory Shared Library Symbol Conflicts (on Linux) 从左往右查找:Note that the linker only looks further down the line when looking for symbols used by but not defined in the current lib.Linux 下…

【全部更新完毕】2024电工杯B题详细思路代码成品文章教学:大学生平衡膳食食谱的优化设计及评价

大学生平衡膳食食谱的优化设计及评价 摘要 大学阶段是学生获取知识和身体发育的关键时期&#xff0c;也是形成良好饮食习惯的重要阶段。然而&#xff0c;当前大学生中存在饮食结构不合理和不良饮食习惯的问题&#xff0c;主要表现为不吃早餐或早餐吃得马虎&#xff0c;经常食用…

JVM学习-垃圾收集器(三)

G1回收器-区域化分代式 为了适应不断扩大的内存和不断增加的处理器数量&#xff0c;进一步降低暂停时间&#xff0c;同时兼顾良好的吞吐量官方给G1设定的目标&#xff1a;延迟可控的情况下获得尽可能高的吞吐量&#xff0c;所以才担当起“全功能收集器”的重任与期望G1是一款面…

构建数字未来:探索Web3在物联网中的新视角

引言 随着Web3时代的来临&#xff0c;物联网技术正迎来一场新的变革。在这个数字化时代&#xff0c;Web3所带来的技术创新将为物联网的发展开辟新的视角。本文将深入探讨Web3在物联网领域的应用&#xff0c;揭示其在构建数字未来中的重要性和影响。 Web3与物联网的融合 区块链…

Docker学习笔记(二)Dockerfile自定义镜像、DockerCompose、Docker私有镜像仓库

文章目录 前言3 Dockerfile自定义镜像3.1 镜像结构3.2 Dockerfile文件3.3 构建自定义镜像3.3.1 基于Ubuntu构建Java项目3.3.2 基于Java8构建Java项目 3.4 小结 4 DockerCompose4.1 安装DockerCompose4.2 部署微服务集群 5 Docker私有镜像仓库 前言 Docker学习笔记(一)安装Dock…

ctfhub中的SSRF的相关例题(下)

目录 URL Bypass 知识点 相关例题 数字IP Bypass 相关例题 方法一&#xff1a;使用数字IP 方法二&#xff1a;转16进制 方法三&#xff1a;用localhost代替 方法四&#xff1a;特殊地址 302跳转 Bypass ​编辑 关于localhost原理: DNS重绑定 Bypass 知识点&…

每日练习之数学——砝码和天平

砝码和天平 题目描述 运行代码 #include<iostream> using namespace std; int main() {int w,m,T;cin>>T;while(T--){cin>>w>>m;while(m){if((m-1)%w0)m(m-1)/w;else if((m1)%w0)m(m1)/w;else if(m%w0)m/w;else break;}if(!m)cout<<"YES&…

「职场必备」让你摆脱思维混乱的7个工具

1. 升维思考&#xff0c;降维拆解 解决复杂问题时&#xff0c;有两个关键的阶段&#xff0c;能让我们事半功倍。 第一个阶段是思考阶段&#xff0c;要自下而上进行“升维思考”&#xff0c;明确问题的本质是什么。第二阶段是行动阶段&#xff0c;要自上而下进行“降维拆解”&am…

Excel查找匹配函数(VLOOKUP):功能与应用解析

文章目录 概述VLOOKUP函数语法查询并返回单列结果查找并返回多列结果MATCH函数VLOOKUPMATCH 从右向左逆向查找&#xff1a;INDEX函数INDEXMATCH 函数匹配方式查找匹配注意事项函数名称错误: #NAME?值错误&#xff1a;#VALUE!引用错误&#xff1a;#REF!找不到数据&#xff1a;#…

1、NLP分词

分词处理 1、token&#xff08;词汇单元&#xff09;2、Tokenizer&#xff08;分词&#xff09;3、ElasticSearch 分词器&#xff08;Analyzer&#xff09;4、分词工具停用词&#xff08;Stop words&#xff09; 1、token&#xff08;词汇单元&#xff09; “token”主要用于文…

AI早班车5.25

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是「奇点」&#xff0c;江湖人称 singularity。刚工作几年&#xff0c;想和大家一同进步&#x1f91d;&#x1f91d; 一位上进心十足的【Java ToB端大厂…

51-53 DriveWorld:通过自动驾驶世界模型进行 4D 预训练场景理解 (含模型数据流梳理)

24年5月&#xff0c;北京大学、国防创新研究院无人系统技术研究中心、中国电信人工智能研究院联合发布了DriveWorld: 4D Pre-trained Scene Understanding via World Models for Autonomous Driving。 DriveWorld在UniAD的基础上又有所成长&#xff0c;提升了自动驾驶目标检测…

linux之防火墙工具

netfilter Linux防火墙是由Netfilter组件提供的&#xff0c;Netfilter工作在内核空间&#xff0c;集成在linux内核中。 Netfilter在内核中选取五个位置放了五个hook(勾子) function(INPUT、OUTPUT、FORWARD、PREROUTING、POSTROUTING)&#xff0c;而这五个hook function向用户…

人工智能应用-实验8-用生成对抗网络生成数字图像

文章目录 &#x1f9e1;&#x1f9e1;实验内容&#x1f9e1;&#x1f9e1;&#x1f9e1;&#x1f9e1;代码&#x1f9e1;&#x1f9e1;&#x1f9e1;&#x1f9e1;分析结果&#x1f9e1;&#x1f9e1;&#x1f9e1;&#x1f9e1;实验总结&#x1f9e1;&#x1f9e1; &#x1f9…

Stable Diffusion【艺术特效】【霓虹灯】:霓虹灯像素化马赛克特效

提示词 Neon pixelated mosaic of [Subject Description],highly detailed [主题]的霓虹灯像素化马赛克&#xff0c;高度详细 参数设置 大模型&#xff1a;万享XL_超写实摄影V8.2 采样器&#xff1a;Euler a 采样迭代步数&#xff1a;25 CFG&#xff1a;3 反向提示词&#x…

Docker Desktop安装和如何在WSL2中使用Docker

最近在使用WSL的过程中&#xff0c;想使用docker遇到了一些问题&#xff0c;在WSL中安装Linux版本的docker&#xff0c;启动镜像之后不能从Windows机器的端口映射出来&#xff0c;查了一圈之后&#xff0c;发现应该使用Docker Desktop软件&#xff0c;下面是安装和使用的方式 …

UE5 双手握剑的实现(逆向运动学IK)

UE5 双手握剑的实现 IK 前言 什么是IK&#xff1f; UE官方给我们提供了很多对于IK处理的节点&#xff0c;比如ABRIK、Two Bone IK、Full Body IK 、CCD IK等&#xff0c;但是看到这&#xff0c;很多人就好奇了&#xff0c;什么是IK&#xff1f; 首先我们来看看虚幻小白人的骨…

实战Java虚拟机-实战篇

一、内存调优 1.内存溢出和内存泄漏 内存泄漏&#xff08;memory leak&#xff09;&#xff1a;在Java中如果不再使用一个对象&#xff0c;但是该对象依然在GC ROOT的引用链上&#xff0c;这个对象就不会被垃圾回收器回收&#xff0c;这种情况就称之为内存泄漏。内存泄漏绝大…

图论(二)-图的建立

引言&#xff1a; 建图&#xff0c;将图放进内存的方法 常用的建图方式&#xff1a;邻接矩阵&#xff0c;邻接链表&#xff0c;链式前向星 一、邻接矩阵 通过一个二维数组即可将图建立&#xff0c;邻接矩阵&#xff0c;考虑节点集合 &#xff0c;用一个二维数组定义邻接矩…

自定义原生小程序顶部及获取胶囊信息

需求&#xff1a;我需要将某个文字或者按钮放置在小程序顶部位置 思路&#xff1a;根据获取到的顶部信息来定义我需要放的这个元素样式 * 这里我是定义某个指定页面 json&#xff1a;给指定页面的json中添加自定义设置 "navigationStyle": "custom" JS&am…