30分钟快速实现小程序语音识别功能
前言
为了参加某个作秀活动,研究了一波如何结合小程序、科大讯飞实现语音录入、识别的实现。科大讯飞开发文档中只给出 Python 的 demo,并没有给出 node.js 的 sdk,但问题不大。本文将从小程序相关代码到对接科大讯飞 api 过程,一步步介绍,半个小时,搭建完成小程序语音识别功能!不能再多了!
,前提是最好掌握有一点点小程序、node.js 甚至是音频相关的知识。狼蚁网站SEO优化话不多说了,来一起看看详细的介绍吧
架构先行
架构比较简单,大伙儿可以先看下图。除了小程序,需要提供 3 个服务,文件上传、音频编码及对接科大讯飞的服务。
node.js 对接科大讯飞的 api,npm 上已经有同学提供了 sdk,有兴趣的同学可以去搜索了解一下,笔者这里是直接调用了科大讯飞的 api 接口。
撸起袖子加油干
1、创建小程序
鹅厂的小程序文档非常详细,在这里笔者就不对如何创建一个小程序的步骤进行详细阐述了。有需要的同学可以查看鹅厂的。
1.1 相关代码
我们摘取小程序里面,语音录入和语音上传部分的代码。
// 根据wx提供的api创建录音管理对象 const recorderManager = wx.getRecorderManager(); // 监听语音识别结束后的行为 recorderManager.onS(recorderResponse => { // tempFilePath 是录制的音频文件 const { tempFilePath } = recorderResponse; // 上传音频文件,完成语音识别翻译 wx.uploadFile({ url: 'http://127.0.0.1:7001/voice', // 该服务在后面搭建。,小程序发布时要求后台服务提供https服务!这里的地址仅为开发环境配置。 filePath: tempFilePath, name: 'file', plete: res => { console.log(res); // 我们期待res,就是翻译后的内容 } }); }); // 开始录音,触发条件可以是按钮或其他,由你自己决定 recorderManager.start({ duration: 5000 // 最长录制时间 // 其他参数可以默认,更多参数可以查看https://developers.weixin.qq./miniprogram/dev/api/media/recorder/RecorderManager.start.html });
2、搭建文件服务器
步骤 1 代码中提到了一个 url 地址大家应该都还记得。
http://127.0.0.1:7001/voice
小程序本身还并没有提供语音识别的功能,所以在这里我们需要借助于“后端”服务的能力,完成我们语音识别翻译的功能。
2.1 egg.js 服务初始化
我们使用 egg.js 的 cli 快速初始化一个工程,你也可以使用 express、koa、kraken 等等框架,框架的选型在此不是重点我们就不做展开阐述了。对 egg.js 不熟悉的同学可以查看。
npm i egg-init -g egg-init voice-server --type=simple cd voice-server npm i
安装完成后,执行以下代码
npm run dev
随后访问浏览器http://127.0.0.1:7001应该可以看到一个Hi, egg 的页面。至此我们的服务初始化完成。
2.2 文件上传接口
a) 修改 egg.js 的文件上传配置
打开 config/config.default.js,添加以下两项配置
module.exports = appInfo => { ... config.multipart = { fileSize: '2gb', // 限制文件大小 whitelist: [ '.aac', '.m4a', '.mp3' ], // 支持上传的文件后缀名 }; config.security = { csrf: { enable: false // 关闭csrf } }; ... }
b) 添加 VoiceController
打开 app/controller 文件夹,新建文件 voice.js。编写 VoiceController 使其继承于 egg.js 的 Controller。具体代码如下
const Controller = require('egg').Controller; const fs = require('fs'); const path = require('path'); const pump = require('mz-modules/pump'); const uuidv1 = require('uuid/v1'); // 依赖于uuid库,用于生成唯一文件名,使用npm i uuid安装即可 // 音频文件上传后存储的路径 const targetPath = path.resolve(__dirname, '..', '..', 'uploads'); class VoiceController extends Controller { constructor(params) { super(params); if (!fs.existsSync(targetPath)) { fs.mkdirSync(targetPath); } } async translate() { const parts = this.ctx.multipart({ autoFields: true }); let stream; const voicePath = path.join(targetPath, uuidv1()); while (!isEmpty((stream = await parts()))) { await pump(stream, fs.createWriteStream(voicePath)); } // 到这里就完成了文件上传。如果你不需要文件落地,也可以在后续的操作中,直接使用stream操作文件流 ... // 音频编码 // 科大讯飞语音识别 ... } }
c) 一步,新增路由规则
写完 controller 之后,我们依据 egg.js 的规则,在 router.js 里面新增一个路由。
module.exports = app => { const { router, controller } = app; router.get('/', controller.home.index); router.get('/voice', controller.voice.translate); };
OK,至此你可以测试一下从小程序录音,录音完成后上传到后台文件服务器的完整流程。如果没问题,那恭喜你你已经完成了 80%的工作了!
3、音频编码服务
在上文中,小程序录音的方法 recorderManager.start 的时候我们提及到了“更多参数”。其中有一个参数是 format,支持 aac 和 mp3 两种(默认是 aac)。然后我们查阅了科大讯飞的 api 文档,音频编码支持“未压缩的 pcm 或 wav 格式”。
什么 aac、pcm、wav?emmm.. OK,我们只是前端,既然格式不对等,那只需要完成 aac -> pcm 转化即可,ffmpeg 立即浮现在笔者的脑海里。一番搜索,命令大概是这样子的
ffmpeg -i uploads/a3f588d0-edf8-11e8-b6f5-2929aef1b7f8.aac -f s16le -ar 8000 -ac 2 -y decoded.pcm
# -i 后面带的是源文件
# -f s16le 指的是编码格式
# -ar 8000 编码码率
# -ac 2 通道
接下来我们使用 node.js 来实现上述命令。
3.1 引入相关依赖包
npm i ffmpeg-static npm i fluent-ffmpeg
3.2 创建一个编码服务
在 app/service 文件夹中,创建 ffmpeg.js 文件。新建 FFmpegService 继承于 egg.js 的 Service
const { Service } = require('egg'); const ffmpeg = require('fluent-ffmpeg'); const ffmpegStatic = require('ffmpeg-static'); const path = require('path'); const fs = require('fs'); ffmpeg.setFfmpegPath(ffmpegStatic.path); class FFmpegService extends Service { async aac2pcm(voicePath) { const mand = ffmpeg(voicePath); // 方便测试,我们将转码后文件落地到磁盘 const targetDir = path.join(path.dirname(voicePath), 'pcm'); if (!fs.existsSync(targetDir)) { fs.mkdirSync(targetDir); } const target = path.join(targetDir, path.basename(voicePath)) + '.pcm'; return new Promise((resolve, reject) => { mand .audioCodec('pcm_s16le') .audioChannels(2) .audioBitrate(8000) .output(target) .on('error', error => { reject(error); }) .on('end', () => { resolve(target); }) .run(); }); } } module.exports = FFmpegService;
3.3 调用 ffmpegService,获得 pcm 文件
回到 app/controller/voice.js 文件中,我们在文件上传完成后,调用 ffmpegService 提供的 aac2pcm 方法,获取到 pcm 文件的路径。
// app/controller/voice.js ... async translate() { ... ... const pcmPath = await this.ctx.service.ffmpeg.aac2pcm(voicePath); ... } ...
4、对接
,需要到并新增应用、开通应用的语音听写服务。
我们再写一个服务,在 app/service 文件夹下创建 xfyun.js 文件,实现 XFYunService 继承于 egg.js 的 Service。
4.1 引入相关依赖
npm i axios // 网络请求库 npm i md5 // 科大讯飞接口中需要md5计算 npm i form-urlencoded // 接口中需要对部分内容进行urlencoded
4.2 XFYunService 实现
const { Service } = require('egg'); const fs = require('fs'); const formUrlencoded = require('form-urlencoded').default; const axios = require('axios'); const md5 = require('md5'); const API_KEY = 'xxxx'; // 在科大讯飞控制台上可以查到服务的APIKey const API_ID = 'xxxxx'; // 同样可以在控制台查到 class XFYunService extends Service { async voiceTranslate(voicePath) { // 继上文,暴力的读取文件 let data = fs.readFileSync(voicePath); // 将内容进行base64编码 data = new Buffer(data).toString('base64'); // 进行url encode data = formUrlencoded({ audio: data }); const params = { engine_type: 'sms16k', aue: 'raw' }; const x_CurTime = Math.floor(new Date().getTime() / 1000) + '', x_Param = new Buffer(JSON.stringify(params)).toString('base64'); return axios({ url: 'http://api.xfyun./v1/service/v1/iat', method: 'POST', data, headers: { 'X-Appid': API_ID, 'X-CurTime': x_CurTime, 'X-Param': x_Param, 'X-CheckSum': md5(API_KEY + x_CurTime + x_Param) } }).then(res => { // 查询成功后,返回response的data return res.data || {}; }); } } module.exports = XFYunService;
4.3 调用 XFYunService,完成语音识别
回到 app/controller/voice.js 文件中,我们在 ffmpeg 转码完成后,调用 XFYunService 提供的 voiceTranslate 方法,完成语音识别。
// app/controller/voice.js ... async translate() { ... ... const result = await this.ctx.service.xfyun.voiceTranslate(pcmPath); this.ctx.body = result; if (+result.code !== 0) { this.ctx.status = 500; } } ...
至此我们完成语音识别的代码编写。主要流程其实很简单,通过小程序录入语音文件,上传到文件服务器之后,通过 ffmpeg 获取到 pcm 文件, 再转发到科大讯飞的 api 接口进行识别。
以上,如有错漏,欢迎指正!
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对狼蚁SEO的支持。
编程语言
- 如何快速学会编程 如何快速学会ug编程
- 免费学编程的app 推荐12个免费学编程的好网站
- 电脑怎么编程:电脑怎么编程网咯游戏菜单图标
- 如何写代码新手教学 如何写代码新手教学手机
- 基础编程入门教程视频 基础编程入门教程视频华
- 编程演示:编程演示浦丰投针过程
- 乐高编程加盟 乐高积木编程加盟
- 跟我学plc编程 plc编程自学入门视频教程
- ug编程成航林总 ug编程实战视频
- 孩子学编程的好处和坏处
- 初学者学编程该从哪里开始 新手学编程从哪里入
- 慢走丝编程 慢走丝编程难学吗
- 国内十强少儿编程机构 中国少儿编程机构十强有
- 成人计算机速成培训班 成人计算机速成培训班办
- 孩子学编程网上课程哪家好 儿童学编程比较好的
- 代码编程教学入门软件 代码编程教程