微信小程序语音同步智能识别的实现案例代码解析


Posted in Javascript onMay 29, 2020

一、背景

在小程序的一些应用场景中,会有语音转文字的需求。原有的做法一般是先通过小程序的录音功能录下语音文件,然后再通过调用语音智能识别WebApi(比如百度云AI平台,科大讯飞平台)将语音文件转成文字信息,以上的做法比较繁琐且用户的体验性较差。

为解决此问题,微信直接开放了同声传译的插件,小程序作者可以直接使用该插件进行语音同声传译的开发。此文章将通过前后端整合应用的完整案例完成语音的实时转换,并将语音上传到服务端后台备份。

二、同声传译插件介绍

微信同声传译由微信智聆语音团队、微信翻译团队与公众平台联合推出的同传开放接口,首期开放语音转文字、文本翻译、语音合成接口,为开发者赋能。

1、 微信小程序后台添加插件

进入微信小程序后台-->进入设置-->第三方设置-->添加插件->搜索同声传译-->完成添加。

微信小程序语音同步智能识别的实现案例代码解析
微信小程序语音同步智能识别的实现案例代码解析

2、 微信小程序启用插件

在小程序app.json文件中增加插件版本等信息:

"plugins": {
 "WechatSI": {
 "version": "0.3.3",
 "provider": "wx069ba97219f66d99"
 }
 },

在页面程序文件中引入插件:

/* index.js */

const plugin = requirePlugin("WechatSI")

// 获取**全局唯一**的语音识别管理器**recordRecoManager**
const manager = plugin.getRecordRecognitionManager()

recordRecoManager 对象的方法列表:

方法 参数 说明
start options 开始识别
stop 结束识别
onStart callback 正常开始录音识别时会调用此事件
onRecognize callback 有新的识别内容返回,则会调用此事件
onStop callback 识别结束事件
onError callback 识别错误事件

官方开发文档:插件的语音识别管理器

三、语音同步转换的前端实现

1、界面UI与操作

UI参考微信官方的DEMO:长按按钮进行录音,松开按钮实时将录音转换为文字。

微信小程序语音同步智能识别的实现案例代码解析

用户可对同步转换的文字进行编辑,同时可将原始语音文件与文字上传后台服务端。

微信小程序语音同步智能识别的实现案例代码解析

2、代码实现

语音同步转换的主要代码:

//导入插件
const plugin = requirePlugin("WechatSI");
// 获取**全局唯一**的语音识别管理器**recordRecoManager**
const manager = plugin.getRecordRecognitionManager();

/**
 * 加载进行初始化
 */
 onLoad: function () {
 	//获取录音权限
	app.getRecordAuth();
	//初始化语音识别回调
 this.initRecord();
 },

 ...
 
/**
 * 初始化语音识别回调
 * 绑定语音播放开始事件
 */
 initRecord: function () {
 //有新的识别内容返回,则会调用此事件
 manager.onRecognize = (res) => {
 let currentData = Object.assign({}, this.data.currentTranslate, {
 text: res.result,
 });
 this.setData({
 currentTranslate: currentData,
 });
 this.scrollToNew();
 };

 // 识别结束事件
 manager.onStop = (res) => {
 let text = res.result;

 console.log(res.tempFilePath);

 if (text == "") {
 this.showRecordEmptyTip();
 return;
 }

 let lastId = this.data.lastId + 1;

 let currentData = Object.assign({}, this.data.currentTranslate, {
 text: res.result,
 translateText: "正在识别中",
 id: lastId,
 voicePath: res.tempFilePath,
 duration: res.duration
 });

 this.setData({
 currentTranslate: currentData,
 recordStatus: 1,
 lastId: lastId,
 });
 //将当前识别内容与语音文件加入列表
 this.addRecordFile(currentData, this.data.dialogList.length);
 //刷新列表
	 this.scrollToNew();
 };

 // 识别错误事件
 manager.onError = (res) => {
 this.setData({
 recording: false,
 bottomButtonDisabled: false,
 });
 };

 },

 /**
 * 按住按钮开始语音识别
 */
 streamRecord: function (e) {
 let detail = e.detail || {};
 let buttonItem = detail.buttonItem || {};
 //开始中文录音
 manager.start({
 lang: buttonItem.lang,
 });

 this.setData({
 recordStatus: 0,
 recording: true,
 currentTranslate: {
 // 当前语音输入内容
 create: util.recordTime(new Date()),
 text: "正在聆听中",
 lfrom: buttonItem.lang,
 lto: buttonItem.lto,
 },
 });
 //刷新列表
 this.scrollToNew();
 },

 /**
 * 松开按钮结束语音识别
 */
 streamRecordEnd: function (e) {
 let detail = e.detail || {}; // 自定义组件触发事件时提供的detail对象
 let buttonItem = detail.buttonItem || {};

 // 防止重复触发stop函数
 if (!this.data.recording || this.data.recordStatus != 0) {
 console.warn("has finished!");
 return;
 }

 manager.stop();

 this.setData({
 bottomButtonDisabled: true,
 });
 },

编辑识别文字并完上传的主要代码:

/**
 * 页面的初始数据
 */
 data: {
 edit_text_max: 200,
 remain_length: 200,
 edit_text: "",
 is_focus: false,
 tips: "",
 index: -1,
 voicePath: "",
 
 },

/**
 * 加载初始化
 */
 onLoad: function (options) {
 //根据传入的文字内容填充编辑框
 this.setEditText(options.content)
 
 this.setData({
 index: index,
 oldText:options.content,
 voicePath: options.voicePath
 })
 
 },

 /**
 * 编辑文字
 */
 editInput: function (event) {
 console.log(event)
 if (event.detail.value.length > this.getEditTextMax()) {

 } else {
 this.data.edit_text = event.detail.value
 this.updateRemainLength(this.data.edit_text)
 }
 },

 /**
 * 上传文字与语音文件
 */
 editConfirm: function (event) {
 let json=this.data.edit_text
 //调用微信上传文件api将信息上传至服务端webApi
 wx.uploadFile({
 url: api.wxFileUploadUrl,
 filePath: this.data.voicePath,
 name: "file",
 header: {
 Authorization: wx.getStorageSync("loginFlag"),
 "Content-Type": "multipart/form-data",
 },
 formData: {
 openId: app.globalData.userInfo.openId,
 realName: "语音文件",
 json: JSON.stringify(json),
 },
 success: (result) => {
 console.log("success:", result);
 if (result.statusCode == "200") {
  let data = JSON.parse(result.data);
  console.log("data", data);
  if (data.success == true) {
  let module = data.module;
  console.log("module", module);
  app.showInfo("上传成功");  
  setTimeout( ()=>{
  wx.navigateBack();
  }, 2000)
   
  } else {
  app.showInfo("异常错误" + data.errMsg + ",请重新进入");
  wx.navigateTo({
  url: "/pages/index/index",
  });
  }
 } else {
  app.showInfo("访问后台异常,重新进入系统");
  wx.navigateTo({
  url: "/pages/index/index",
  });
 }
 },
 fail: (result) => {
 console.log("fail", result);
 wx.navigateTo({
  url: "/pages/index/index",
 });
 },
 complete: () => {},
 });

 },

四、后端SpringBoot实现语音文件上传webApi

1、SpringBoot项目API相关结构树

微信小程序语音同步智能识别的实现案例代码解析

2、文件上传工具类的实现

tools工具类包中主要存文件通用的文件上传工具类,该工具类会将文件上传至配置指定的文件夹下,并将文件信息写入upload_file表中。

  • 文件信息实体类:与数据库中表upload_file对应;
  • 文件存储仓库类:通过Spring Data JPA接口实现数据的CRUD;
  • 文件上传工具接口:对外统一封装文件上传方法;
  • 文件上传工具实现类:实现文件上传方法接口。

文件信息实体类:UploadFile.java

/**
 * 文件信息表
 *
 * @author zhuhuix
 * @date 2020-04-20
 */
@Entity
@Getter
@Setter
@Table(name = "upload_file")
public class UploadFile {

 @Id
 @GeneratedValue(strategy = GenerationType.IDENTITY)
 @NotNull(groups = Update.class)
 private Long id;

 /**
 * 文件实际名称
 */
 @Column(name = "real_name")
 private String realName;

 /**
 * 文件名
 */
 @NotNull
 @Column(name = "file_name")
 private String fileName;

 /**
 * 文件主名称
 */
 @NotNull
 @Column(name = "primary_name")
 private String primaryName;

 /**
 * 文件扩展名
 */
 @NotNull
 private String extension;

 /**
 * 存放路径
 */
 @NotNull
 private String path;

 /**
 * 文件类型
 */
 private String type;

 /**
 * 文件大小
 */
 private Long size;

 /**
 * 上传人
 */
 private String uploader;

 @JsonIgnore
 @Column(name = "create_time")
 @CreationTimestamp
 private Timestamp createTime;

 public UploadFile(String realName, @NotNull String fileName, @NotNull String primaryName, @NotNull String extension, @NotNull String path, String type, Long size, String uploader) {
 this.realName = realName;
 this.fileName = fileName;
 this.primaryName = primaryName;
 this.extension = extension;
 this.path = path;
 this.type = type;
 this.size = size;
 this.uploader = uploader;
 }

 @Override
 public String toString() {
 return "UploadFile{" +
  "fileName='" + fileName + '\'' +
  ", uploader='" + uploader + '\'' +
  ", createTime=" + createTime +
  '}';
 }
}

文件存储仓库类:UploadFileRepository.java

/**
 * 上传文件DAO接口层
 *
 * @author zhuhuix
 * @date 2020-04-03
 */
public interface UploadFileRepository extends JpaRepository<UploadFile, Long>, JpaSpecificationExecutor<UploadFile> {
//该接口继承JpaRepository及CrudRepository接口,已实现了如findById,save,delete等CRUD方法
}

UploadFileRepository 接口继承JpaRepository及CrudRepository接口,已实现了如findById,save,delete等CRUD方法

微信小程序语音同步智能识别的实现案例代码解析

文件上传工具接口:UploadFileTool.java

/**
 * 文件上传接口定义
 *
 * @author zhuhuix
 * @date 2020-04-20
 */
public interface UploadFileTool {

 /**
 * 文件上传
 * @param multipartFile 文件
 * @return 上传信息
 */
 UploadFile upload(String uploader,String realName,MultipartFile multipartFile);
}

文件上传工具实现类:UploadFileToolImpl.java

/**
 * 文件上传实现类
 *
 * @author zhuhuix
 * @date 2020-04-20
 */
@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class UploadFileToolImpl implements UploadFileTool {

 private final UploadFileRepository uploadFileRepository;

 @Value("${uploadFile.path}")
 private String path;

 @Value("${uploadFile.maxSize}")
 private long maxSize;

 public UploadFileToolImpl(UploadFileRepository uploadFileRepository) {
 this.uploadFileRepository = uploadFileRepository;
 }

 @Override
 @Transactional(rollbackFor = Exception.class)
 public UploadFile upload(String uploader, String realName, MultipartFile multipartFile) {
 //检查文件大小
 if (multipartFile.getSize() > maxSize * Constant.MB) {
  throw new RuntimeException("超出文件上传大小限制" + maxSize + "MB");
 }
 //获取上传文件的主文件名与扩展名
 String primaryName = FileUtil.mainName(multipartFile.getOriginalFilename());
 String extension = FileUtil.extName(multipartFile.getOriginalFilename());
 //根据文件扩展名得到文件类型
 String type = getFileType(extension);
 //给上传的文件加上时间戳
 LocalDateTime date = LocalDateTime.now();
 DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyyMMddhhmmssS");
 String nowStr = "-" + date.format(format);
 String fileName = primaryName + nowStr + "." + extension;

 try {
  String filePath = path + type + File.separator + fileName;
  File dest = new File(filePath).getCanonicalFile();
  if (!dest.getParentFile().exists()) {
  dest.getParentFile().mkdirs();
  }
  multipartFile.transferTo(dest);
  if (ObjectUtil.isNull(dest)) {
  throw new RuntimeException("上传文件失败");
  }

  UploadFile uploadFile = new UploadFile(realName, fileName, primaryName, extension, dest.getPath(), type, multipartFile.getSize(), uploader);
  return uploadFileRepository.save(uploadFile);

 } catch (Exception e) {
  e.printStackTrace();
  throw new RuntimeException(e.getMessage());
 }

 }

 /**
 * 根据文件扩展名给文件类型
 *
 * @param extension 文件扩展名
 * @return 文件类型
 */
 private static String getFileType(String extension) {
 String document = "txt doc pdf ppt pps xlsx xls docx csv";
 String music = "mp3 wav wma mpa ram ra aac aif m4a";
 String video = "avi mpg mpe mpeg asf wmv mov qt rm mp4 flv m4v webm ogv ogg";
 String image = "bmp dib pcp dif wmf gif jpg tif eps psd cdr iff tga pcd mpt png jpeg";
 if (image.contains(extension)) {
  return "image";
 } else if (document.contains(extension)) {
  return "document";
 } else if (music.contains(extension)) {
  return "music";
 } else if (video.contains(extension)) {
  return "video";
 } else {
  return "other";
 }
 }
}

注意,该程序代码中用到了@Value注解获取配置文件中的uploadFile.path及uploadFile.maxsize参数,一般在项目静态配置文件中按如下书写(yml配置文件)。

# 测试环境文件存储路径
uploadFile:
 path: C:\startup\file\
 # 文件大小 /M
 maxSize: 50

3、小程序上传文件接口的实现

wx-miniprogram包定义了小程序CRM webApi的接口,小程序调用webApi实现文件的上传及其他功能。

  • 微信小程序 webApi:对外提供小程序上传文件webApi;
  • 微信小程序服务接口:封装小程序上传文件服务接口;
  • 微信小程序服务实现:小程序上传文件服务的实现,该服务实现中会调用tools包中的UploadFile接口进行文件的上传。

微信小程序CRM webApi:WxMiniCrmController.java

/**
 * 微信小程序Crm webApi
 *
 * @author zhuhuix
 * @date 2020-03-30
 */
@Slf4j
@RestController
@RequestMapping("/api/wx-mini")
@Api(tags = "微信小程序Crm接口")
public class WxMiniCrmController {

 private final WxMiniCrm wxMiniCrm;

 public WxMiniCrmController(WxMiniCrm wxMiniCrm) {
 this.wxMiniCrm = wxMiniCrm;
 }

 @ApiOperation(value = "微信小程序端上传文件")
 @PostMapping(value = "/fileUpload")
 public ResponseEntity fileUpload(HttpServletRequest request) {
 MultipartHttpServletRequest req = (MultipartHttpServletRequest) request;

 MultipartFile multipartFile = req.getFile("file");
 String openId = req.getParameter("openId");
 String realName = req.getParameter("realName");
 String json = req.getParameter("json");

 return ResponseEntity.ok(wxMiniCrm.uploadFile(json, openId,realName, multipartFile));

 }
}

微信小程序CRM服务接口:WxMiniCrm.java

/**
 * 微信小程序CRM服务接口定义
 *
 * @author zhuhuix
 * @date 2020-04-20
 */
public interface WxMiniCrm {

 /**
 * 将微信小程序传入的json对象写入数据库,并同时将文件上传至服务端
 *
 * @param json  微信端传入json对象
 * @param openId 上传人
 * @param realName 文件实际名称
 * @param multipartFile 上传文件
 * @return 返回上传信息
 */
 Result<UploadFile> uploadFile(String json, String openId, String realName,MultipartFile multipartFile);
}

微信小程序CRM服务实现:WxMiniCrmImpl.java

/**
 * 微信小程序CRM实现类
 *
 * @author zhuhuix
 * @date 2020-04-20
 */
@Slf4j
@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class WxMiniCrmImpl implements WxMiniCrm {

 private final UploadFileTool uploadFileTool;

 public WxMiniCrmImpl(UploadFileTool uploadFileTool) {
 this.uploadFileTool = uploadFileTool;
 }

 @Override
 @Transactional(rollbackFor = Exception.class)
 public Result<UploadFile> uploadFile(String json, String openId,String realName, MultipartFile multipartFile) {
 return new Result<UploadFile>().ok(uploadFileTool.upload(openId,realName, multipartFile));
 }
}

4、小程序上传文件接口的查看

访问Swagger2可查看该接口,Swagger2与SpringBoot的集成可参考SpringBoot JWT认证机制项目集成Swagger2

微信小程序语音同步智能识别的实现案例代码解析

五、实际测试

语音测试正常

微信小程序语音同步智能识别的实现案例代码解析

上传文件至后台:

微信小程序语音同步智能识别的实现案例代码解析

上传的日志信息查看:

微信小程序语音同步智能识别的实现案例代码解析

总结

到此这篇关于微信小程序语音同步智能识别的实现案例代码解析的文章就介绍到这了,更多相关微信小程序语音同步智能识别内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
实例:尽可能写友好的Javascript代码
Oct 09 Javascript
JavaScript/jQuery 表单美化插件小结
Feb 14 Javascript
Extjs4实现两个GridPanel之间数据拖拽功能具体方法
Nov 21 Javascript
JS将数字转换成三位逗号分隔的样式(示例代码)
Feb 19 Javascript
验证码在IE中不刷新而谷歌等浏览器正常的解决方案
Mar 18 Javascript
深入浅析JavaScript中数据共享和数据传递
Apr 25 Javascript
js从数组中删除指定值(不是指定位置)的元素实现代码
Sep 13 Javascript
jQuery密码强度验证控件使用详解
Jan 05 Javascript
Vue2.0 UI框架ElementUI使用方法详解
Apr 14 Javascript
Angular4自制一个市县二级联动组件示例
Nov 21 Javascript
使用layui前端框架弹出form表单以及提交的示例
Oct 25 Javascript
JavaScript组合模式---引入案例分析
May 23 Javascript
vue实现户籍管理系统
May 29 #Javascript
JavaScript闭包原理与用法学习笔记
May 29 #Javascript
Jquery+AJAX实现无刷新上传并重命名文件操作示例【PHP后台接收】
May 29 #jQuery
JS组件库AlloyTouch实现图片轮播过程解析
May 29 #Javascript
基于vue实现探探滑动组件功能
May 29 #Javascript
JS实现前端路由功能示例【原生路由】
May 29 #Javascript
JavaScript如何实现图片处理与合成
May 29 #Javascript
You might like
sony ICF-2010 拆解与改装
2021/03/02 无线电
php 安全过滤函数代码
2011/05/07 PHP
Javascript 判断 object 的特定类转载
2007/02/01 Javascript
JavaScript 对象成员的可见性说明
2009/10/16 Javascript
jQuery 方法大全方便学习参考
2010/02/25 Javascript
JS自动缩小超出大小的图片
2012/10/12 Javascript
JS 退出系统并跳转到登录界面的实现代码
2013/06/29 Javascript
js实现Select列表内容自动滚动效果代码
2015/08/20 Javascript
jquery弹出遮掩层效果【附实例代码】
2016/04/28 Javascript
JS只能输入正整数的简单实例
2016/10/07 Javascript
jQuery自定义插件详解及实例代码
2016/12/29 Javascript
javascript 删除数组元素和清空数组的简单方法
2017/02/24 Javascript
运用jQuery写的验证表单(实例讲解)
2017/07/06 jQuery
详解基于vue的移动web app页面缓存解决方案
2017/08/03 Javascript
Node之简单的前后端交互(实例讲解)
2017/11/14 Javascript
浅谈Node模块系统及其模式
2017/11/17 Javascript
详解如何使用node.js的开发框架express创建一个web应用
2018/12/20 Javascript
js验证身份证号码记录的方法
2019/04/26 Javascript
python文件名和文件路径操作实例
2017/09/29 Python
python 3.5实现检测路由器流量并写入txt的方法实例
2017/12/17 Python
Python 保存矩阵为Excel的实现方法
2019/01/28 Python
Python中按值来获取指定的键
2019/03/04 Python
python 使用turtule绘制递归图形(螺旋、二叉树、谢尔宾斯基三角形)
2019/05/30 Python
Python 中的 global 标识对变量作用域的影响
2019/08/12 Python
Django中create和save方法的不同
2019/08/13 Python
如何利用CSS3制作3D效果文字具体实现样式
2013/05/02 HTML / CSS
CSS3绘制圆角矩形的简单示例
2015/09/28 HTML / CSS
详解CSS3的perspective属性设置3D变换距离的方法
2016/05/23 HTML / CSS
美国生日蛋糕店:Bake Me A Wish!
2017/02/08 全球购物
大学本科生的个人自我评价
2013/12/09 职场文书
幼儿园母亲节活动方案
2014/03/10 职场文书
小学校长先进事迹材料
2014/05/13 职场文书
英文投诉信格式
2015/07/03 职场文书
JAVA springCloud项目搭建流程
2022/05/11 Java/Android
Nginx使用ngx_http_upstream_module实现负载均衡功能示例
2022/08/05 Servers