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


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 鼠标滚轮事件
Apr 09 Javascript
20个最新的jQuery插件
Jan 13 Javascript
JS定义回车事件(实现代码)
Jul 08 Javascript
使用node.js 制作网站前台后台
Nov 13 Javascript
js实现拖拽效果(构造函数)
Dec 14 Javascript
实用又漂亮的BootstrapValidator表单验证插件
May 30 Javascript
jQuery实现的事件绑定功能基本示例
Oct 11 jQuery
微信小程序使用slider设置数据值及switch开关组件功能【附源码下载】
Dec 09 Javascript
利用js将ajax获取到的后台数据动态加载至网页中的方法
Aug 08 Javascript
jQuery中DOM常见操作实例小结
Aug 01 jQuery
JavaScript实现拖拽盒子效果
Feb 06 Javascript
jQuery实现图片切换效果
Oct 19 jQuery
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
实用函数10
2007/11/08 PHP
php切割页面div内容的实现代码分享
2012/07/31 PHP
PHP常用的文件操作函数经典收藏
2013/04/02 PHP
thinkphp视图模型查询提示ERR: 1146:Table 'db.pr_order_view' doesn't exist的解决方法
2014/10/30 PHP
在Windows系统下使用PHP生成Word文档的教程
2015/07/03 PHP
PHP中使用GD库绘制折线图 折线统计图的绘制方法
2015/11/09 PHP
php+ajax 文件上传代码实例
2019/03/18 PHP
prototype Element学习笔记(Element篇三)
2008/10/26 Javascript
javascript 对象定义方法 简单易学
2009/03/22 Javascript
JavaScript高级程序设计(第3版)学习笔记5 js语句
2012/10/11 Javascript
js获取html文件的思路及示例
2013/09/17 Javascript
JS.GetAllChild(element,deep,condition)使用介绍
2013/09/21 Javascript
文档对象模型DOM通俗讲解
2013/11/01 Javascript
让新消息在网页标题闪烁提示的jQuery代码
2013/11/04 Javascript
jQuery控制TR显示隐藏的几种方法
2014/06/18 Javascript
jquery实现增加删除行的方法
2015/02/03 Javascript
validform表单验证的实现方法
2019/03/08 Javascript
关于JSON解析的实现过程解析
2019/10/08 Javascript
vue实现动态表格提交参数动态生成控件的操作
2020/11/09 Javascript
Vue实现图书管理案例
2021/01/20 Vue.js
[30:55]完美世界DOTA2联赛PWL S2 Magma vs LBZS 第二场 11.18
2020/11/18 DOTA
[06:07]DOTA2-DPC中国联赛3月5日Recap集锦
2021/03/11 DOTA
Python编程中的for循环语句学习教程
2015/10/14 Python
详解Python 模拟实现生产者消费者模式的实例
2017/08/10 Python
Python操作word常见方法示例【win32com与docx模块】
2018/07/17 Python
django重新生成数据库中的某张表方法
2019/08/28 Python
numpy.transpose()实现数组的转置例子
2019/12/02 Python
Python JSON常用编解码方法代码实例
2020/09/05 Python
关于box-sizing的全面理解
2016/07/28 HTML / CSS
欧缇丽加拿大官方网站:Caudalie加拿大
2019/07/18 全球购物
入党自我评价范文
2014/02/02 职场文书
竞选班干部演讲稿500字
2014/08/20 职场文书
2016年感恩母亲节活动总结
2016/04/01 职场文书
关于springboot 配置date字段返回时间戳的问题
2021/07/25 Java/Android
Java 超详细讲解设计模式之中的抽象工厂模式
2022/03/25 Java/Android
基于Apache Hudi在Google云构建数据湖平台的思路详解
2022/04/07 Servers