一、关于百度语音技术
百度语音技术是百度语音开放业界领先的语音识别、语音合成技术能力,广泛应用于泛阅读、在线教育、音频审核、电话客服、快递物流等多种行业和场景,赋能开发者,让您的产品能“听”会“说”。
二、前期准备
1.百度智能云注册
进入百度智能云官网进行注册,地址:https://cloud.baidu.com/
2.创建应用
完成注册后登录百度智能云并进入控制台,然后点击左侧菜单【产品服务】-【语音技术】
再点击“语音技术”菜单下的【应用列表】-【创建应用】
输入“应用名称,勾选“语音技术”、“语音包名”,输入“应用描述”后点击“立即创建”按钮
创建完成后回到“应用列表”,复制该应用的API Key和 Secret Key并保存
另外,在【语音技术】-【概览】界面中可以领取“免费资源”,不同接口会有相应的免费调用次数,如下图:
三、在 Laf 中接入百度语音技术
登录 Laf 云开发平台,在应用列表中选择一个应用后点击【开发】按钮,进入 Laf 应用开发 IDE
1.添加函数
点击左上角【函数列表】处的“+”按钮创建需要使用到的云函数
1)云函数“baidu-api”:用于实现百度语音技术的接口对接
2)云函数“upload-file”:文件上传功能的封装
3)云函数“store-file”:用于将上传的文件存放到 Laf 云存储中,关于 Laf 云存储的详细说明可点击链接 https://doc.laf.run/guide/oss/ 进行了解
2.将上传的文件存放到 Laf 云存储
先在云存储中添加“Bucket”空间,如下图:
云函数“store-file”完整代码如下:
import cloud from '@lafjs/cloud'
import { GetObjectCommand, S3 } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
const s3Client = new S3({
endpoint: process.env.OSS_EXTERNAL_ENDPOINT,
region: process.env.OSS_REGION,
credentials: {
accessKeyId: process.env.OSS_ACCESS_KEY,
secretAccessKey: process.env.OSS_ACCESS_SECRET
},
forcePathStyle: true,
})
const bucketName = 'store-file'
export default async function (ctx: FunctionContext) {
const _body = ctx.body;
if (!_body.type) {
return resultData(-1, '参数type不能为空!');
}
switch (_body.type) {
case 'storeFile':
return await storeFile(_body.param);
default:
return resultData(-1, '请检查参数type是否有误!');
}
}
async function storeFile(param) {
console.log('storeFile', param);
const _param = param;
if (!_param.fileName || !_param.fileBody || !_param.contentType) {
return resultData(-1, '参数fileName、fileBody或contentType不能为空!');
}
try {
const res = await uploadAppFile(_param.fileName, _param.fileBody, _param.contentType);
console.log('文件存储结果:', res)
if (res && res.$metadata && res.$metadata.httpStatusCode == 200) {
const bucket = getInternalBucketName();
const fileUrl = 'https://' + bucket + '.oss.laf.dev/' + _param.fileName;
return resultData(0, '文件存储成功!', {
fileUrl: fileUrl,
fileName: _param.fileName
});
}
return resultData(-1, '文件存储失败!');
}
catch (e) {
return resultData(-1, '出现异常!', e.message);
}
}
function getInternalBucketName() {
const appid = process.env.APP_ID;
return `${appid}-${bucketName}`;
}
async function uploadAppFile(key, body, contentType) {
const bucket = getInternalBucketName();
const res = await s3Client
.putObject({
Bucket: bucket,
Key: key,
ContentType: contentType,
Body: body,
})
return res;
}
async function getAppFileUrl(key) {
const bucket = getInternalBucketName();
const res = await getSignedUrl(s3Client, new GetObjectCommand({
Bucket: bucket,
Key: key,
}));
return res;
}
async function delAppFileUrl(key) {
const bucket = getInternalBucketName()
const res = await s3Client.deleteObject({
Bucket: bucket,
Key: key
});
return res;
}
function resultData(code = -1, msg = '', data = null) {
return { code, msg, data }
}
3.文件上传功能的封装
云函数“upload-file”完整代码如下:
import cloud from '@lafjs/cloud'
const fs = require("fs")
export default async function (ctx: FunctionContext) {
const _body = ctx.body;
const _query = ctx.query;
const _type = _body.type ? _body.type : _query.type;
if (!_type) {
return resultData(-1, '参数type不能为空!');
}
const _files = ctx.files;
switch (_type) {
case 'uploadFile':
return await uploadFile(_files);
default:
return resultData(-1, '请检查参数type是否有误!');
}
}
async function uploadFile(files) {
console.log('uploadFile->files', files);
const _files = files;
if (!_files || _files.length == 0) {
return resultData(-1, '未上传文件!');
}
const fileInfo = _files[0];
if (!fileInfo.filename) {
return resultData(-1, '文件名称为空!');
}
if (!fileInfo.mimetype) {
return resultData(-1, '文件类型为空!');
}
try {
let fileData = await fs.readFileSync(fileInfo.path);
let fileName = 'TempFiles/' + fileInfo.filename;
let _mimetype = fileInfo.mimetype.split('/');
if (fileInfo.filename.split('.').length < 2 && fileInfo.filename.indexOf(_mimetype[1]) < 0) {
if (_mimetype[0] == 'image') {
fileName = fileName + '.' + _mimetype[1];
}
else {
fileInfo.mimetype = 'audio/wave';
fileName = fileName + '.wav';
}
}
const ret = await cloud.invoke('store-file', {
body: {
type: 'storeFile',
param: {
fileName: fileName,
fileBody: fileData,
contentType: fileInfo.mimetype
}
}
});
if (ret.code != 0) {
return resultData(-1, ret.msg);
}
ret.data.fileType = fileInfo.mimetype;
ret.data.fileSize = fileInfo.size;
return ret;
}
catch (e) {
return resultData(-1, '异常错误:' + e.message);
}
}
function resultData(code = -1, msg = '', data = null) {
return { code, msg, data }
}
4.百度语音技术接口对接
由于百度接口存在“鉴权认证机制”,故在调用接口前需要先获取AccessToken
const apiKey = 'your api key'
const secretKey = 'your secret key'
async function getAccessToken() {
let access_token = '';
try {
await cloud.fetch({
url: 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=' + apiKey + '&client_secret=' + secretKey,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
}).then(function (res) {
let d = res.data;
if (res.status == 200 && d.access_token) {
access_token = d.access_token;
}
else {
console.log('获取AccessToken失败!' + d.error_msg);
}
}).catch(function (err) {
console.log('获取AccessToken异常!', err.message);
});
}
catch (e) {
console.log('异常错误:' + e.message);
}
return access_token;
}
1)短文本转语音
在云函数“baidu-api”主入口中添加如下代码:
export default async function (ctx: FunctionContext) {
const _body = ctx.body;
const _query = ctx.query;
const _type = _body.type ? _body.type : _query.type;
if (!_type) {
return resultData(-1, '参数type不能为空!');
}
switch (_type) {
case 'shortTextToVoice':
return await shortTextToVoice(_body.param);
default:
return resultData(-1, '请检查参数type是否有误!');
}
}
function resultData(code = -1, msg = '', data = null) {
return { code, msg, data }
}
短文本转语音(方法“shortTextToVoice”)具体实现如下:
async function shortTextToVoice(param) {
console.log('shortTextToVoice', param);
const _param = param;
if (!_param.text) {
return resultData(-1, '参数text不能为空!');
}
if (_param.text.length > 60) {
return resultData(-1, '不能超过60个汉字或者字母数字!');
}
const access_token = await getAccessToken();
if (!access_token) {
return resultData(-1, 'AccessToken获取失败!');
}
try {
let _text = _param.text;
console.log('shortTextToVoice-->text编码后:', _text);
let _cuid = Math.ceil(Math.random() * 1000000000000);
let obj = null;
await cloud.fetch({
url: 'https://tsn.baidu.com/text2audio',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': '*/*'
},
data: {
'tex': _text,
'tok': access_token,
'cuid': _cuid,
'ctp': '1',
'lan': 'zh',
'spd': _param.spd ? _param.spd : '5',
'pit': _param.pit ? _param.pit : '5',
'vol': _param.vol ? _param.vol : '5',
'per': _param.per ? _param.per : '1',
'aue': _param.aue ? _param.aue : '3'
},
responseType: 'stream',
}).then(function (res) {
let content_type = res.headers['content-type'];
if (res.status == 200 && content_type && content_type.toLowerCase().indexOf('audio') > -1) {
obj = resultData(0, '成功!', res.data);
}
else {
obj = resultData(-1, '语音合成失败,err_detail:' + res.data.err_detail);
}
}).catch(function (err) {
console.log('短文本转语音异常!', err.message);
obj = resultData(-1, '语音合成异常:' + err.message);
});
if (obj.code == 0) {
let fileName = 'TextToVoice/' + _cuid;
let _aue = _param.aue ? _param.aue : '3';
switch (_aue) {
case '4':
case '5':
fileName = fileName + '.pcm';
break;
case '6':
fileName = fileName + '.wav';
break;
default:
fileName = fileName + '.mp3';
break;
}
const ret = await cloud.invoke('store-file', {
body: {
type: 'storeFile',
param: {
fileName: fileName,
fileBody: obj.data,
contentType: 'application/octet-stream'
}
}
});
if (ret.code == 0) {
obj = resultData(0, '语音合成成功!', ret.data);
}
else {
obj = resultData(-1, ret.msg);
}
}
return obj;
}
catch (e) {
return resultData(-1, '异常错误:' + e.message);
}
}
当文本成功转换成语音后,会将音频文件存放到 Laf 云存储中。使用Apipost调用如下:
{
"type": "shortTextToVoice",
"param": {
"text": "今天五月初五端午节,祝大家端午节安康!"
}
}
2)长文本转语音
由于长文本和短文本不一样,当内容过多之后不能实时的返回音频文件,故需要先创建任务,然后再通过任务ID去查询生成的音频文件
在云函数“baidu-api”主入口中增加“长文本转语音-创建任务”和“长文本转语音-查询任务结果”,具体代码如下:
export default async function (ctx: FunctionContext) {
const _body = ctx.body;
const _query = ctx.query;
const _type = _body.type ? _body.type : _query.type;
if (!_type) {
return resultData(-1, '参数type不能为空!');
}
switch (_type) {
case 'shortTextToVoice':
return await shortTextToVoice(_body.param);
case 'longTextToVoice':
return await longTextToVoice(_body.param);
case 'searchTextToVoice':
return await searchTextToVoice(_body.param);
default:
return resultData(-1, '请检查参数type是否有误!');
}
}
长文本转语音-创建任务(方法“longTextToVoice”)具体实现如下:
async function longTextToVoice(param) {
console.log('longTextToVoice', param);
const _param = param;
if (!_param.text || _param.text.length == 0) {
return resultData(-1, '参数text不能为空!');
}
const access_token = await getAccessToken();
if (!access_token) {
return resultData(-1, 'AccessToken获取失败!');
}
try {
let obj = null;
await cloud.fetch({
url: 'https://aip.baidubce.com/rpc/2.0/tts/v1/create?access_token=' + access_token,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
data: {
'text': _param.text,
'format': _param.format ? _param.format : 'mp3-16k',
'voice': _param.voice ? _param.voice : 0,
'lang': 'zh',
'speed': _param.speed ? _param.speed : 5,
'pitch': _param.pitch ? _param.pitch : 5,
'volume': _param.volume ? _param.volume : 5,
'enable_subtitle': _param.enable_subtitle ? _param.enable_subtitle : '0',
}
}).then(function (res) {
let d = res.data;
if (res.status == 200 && d.task_id) {
obj = resultData(0, '长文本转语音成功!', d);
}
else {
obj = resultData(-1, '长文本转语音失败!' + d.error_msg);
}
}).catch(function (err) {
console.log('长文本转语音异常!', err.message);
obj = resultData(-1, '长文本转语音异常:' + err.message);
});
return obj;
}
catch (e) {
return resultData(-1, '异常错误:' + e.message);
}
}
使用Apipost调用结果如下:
{
"type": "longTextToVoice",
"param": {
"text": ["今天五月初五端午节","祝大家端午节安康!"]
}
}
长文本转语音-查询任务结果(方法“searchTextToVoice”)具体实现如下:
async function searchTextToVoice(param) {
console.log('searchTextToVoice', param);
const _param = param;
if (!_param.taskIds || _param.taskIds == 0) {
return resultData(-1, '参数taskIds不能为空!');
}
const access_token = await getAccessToken();
if (!access_token) {
return resultData(-1, 'AccessToken获取失败!');
}
try {
let obj = null;
await cloud.fetch({
url: 'https://aip.baidubce.com/rpc/2.0/tts/v1/query?access_token=' + access_token,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
data: {
'task_ids': _param.taskIds,
}
}).then(function (res) {
let d = res.data;
if (res.status == 200 && d.tasks_info) {
obj = resultData(0, '长文本转语音-查询成功!', d.tasks_info);
}
else {
obj = resultData(-1, '长文本转语音-查询失败!' + d.error_msg);
}
}).catch(function (err) {
console.log('长文本转语音-查询异常!', err.message);
obj = resultData(-1, '长文本转语音-查询异常:' + err.message);
});
return obj;
}
catch (e) {
return resultData(-1, '异常错误:' + e.message);
}
}
使用Apipost调用结果如下:
{
"type": "searchTextToVoice",
"param": {
"taskIds": ["6480b88bcde4bf0001132035"]
}
}
3)音频转写
由于音频文件一般比较大,且上传之后需要时间解析,故需要先单独将音频文件上传,然后通过返回的文件url去调用创建任务接口,最后再通过任务ID去查询生成的文本内容
使用Apipost调用云函数“upload-file”接口结果如下:
在云函数“baidu-api”主入口中增加“音频转写-创建任务”和“音频转写-查询任务结果”,具体代码如下:
export default async function (ctx: FunctionContext) {
const _body = ctx.body;
const _query = ctx.query;
const _type = _body.type ? _body.type : _query.type;
if (!_type) {
return resultData(-1, '参数type不能为空!');
}
switch (_type) {
case 'shortTextToVoice':
return await shortTextToVoice(_body.param);
case 'longTextToVoice':
return await longTextToVoice(_body.param);
case 'searchTextToVoice':
return await searchTextToVoice(_body.param);
case 'createVoiceToText':
return await createVoiceToText(_body.param);
case 'searchVoiceToText':
return await searchVoiceToText(_body.param);
default:
return resultData(-1, '请检查参数type是否有误!');
}
}
长文本转语音-创建任务(方法“longTextToVoice”)具体实现如下:
async function createVoiceToText(param) {
console.log('voiceToText->param', param);
const _param = param;
if (!_param.fileUrl || !_param.fileType || _param.fileType.toLowerCase().indexOf('audio') < 0) {
return resultData(-1, '请上传音频文件!');
}
if (!_param.fileName) {
return resultData(-1, '文件名称不能为空');
}
const _format = ['mp3', 'wav', 'pcm', 'm4a', 'amr'];
let _fileName = _param.fileName.toLowerCase().split('.');
if (_format.indexOf(_fileName[1]) < 0) {
return resultData(-1, '仅支持mp3、wav、pcm、m4a、amr格式的音频文件!');
}
const limitSize = 50 * 1024 * 1024;
if (!_param.fileSize || _param.fileSize > limitSize) {
return resultData(-1, '音频文件大小不能超过50M!');
}
const access_token = await getAccessToken();
if (!access_token) {
return resultData(-1, 'AccessToken获取失败!');
}
try {
let fileFormat = _param.fileName.split('.')[1];
let obj = null;
await cloud.fetch({
url: 'https://aip.baidubce.com/rpc/2.0/aasr/v1/create?access_token=' + access_token,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
data: {
'speech_url': _param.fileUrl,
'format': fileFormat,
'pid': _param && _param.pid ? _param.pid : 80001,
'rate': 16000
}
}).then(function (res) {
let d = res.data;
if (res.status == 200 && d.task_id) {
obj = resultData(0, '音频转写成功!', d);
}
else {
obj = resultData(-1, '音频转写失败!' + d.error_msg);
}
}).catch(function (err) {
console.log('音频转写异常!', err.message);
obj = resultData(-1, '音频转写异常:' + err.message);
});
return obj;
}
catch (e) {
return resultData(-1, '异常错误:' + e.message);
}
}
使用Apipost调用结果如下:
{
"type": "createVoiceToText",
"param": {
"fileUrl": "https://l1ygg3-store-file.oss.laf.dev/TempFiles/96bcdd36-373a-4031-b843-33d45c17dc03.mp3",
"fileName": "TempFiles/96bcdd36-373a-4031-b843-33d45c17dc03.mp3",
"fileType": "audio/mpeg",
"fileSize": 1001504
}
}
长文本转语音-查询任务结果(方法“searchTextToVoice”)具体实现如下:
async function searchVoiceToText(param) {
console.log('searchVoiceToText', param);
const _param = param;
if (!_param.taskIds || _param.taskIds.length == 0) {
return resultData(-1, '参数taskIds不能为空!');
}
const access_token = await getAccessToken();
if (!access_token) {
return resultData(-1, 'AccessToken获取失败!');
}
try {
let obj = null;
await cloud.fetch({
url: 'https://aip.baidubce.com/rpc/2.0/aasr/v1/query?access_token=' + access_token,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
data: {
'task_ids': _param.taskIds,
}
}).then(function (res) {
let d = res.data;
if (res.status == 200 && d.tasks_info) {
obj = resultData(0, '音频转写-查询成功!', d.tasks_info);
}
else {
obj = resultData(-1, '音频转写-查询失败!' + d.error_msg);
}
}).catch(function (err) {
console.log('音频转写-查询异常!', err.message);
obj = resultData(-1, '音频转写-查询异常:' + err.message);
});
return obj;
}
catch (e) {
return resultData(-1, '异常错误:' + e.message);
}
}
使用Apipost调用结果如下:
{
"type": "searchVoiceToText",
"param": {
"taskIds": ["649469dd3157480001d81a28"]
}
}
以上便是 Laf 结合百度语音技术实现文本与语音之间的互转示例。
最后,云函数“baidu-api”完整代码如下:
import cloud from '@lafjs/cloud'
const apiKey = 'your api key'
const secretKey = 'your secret key'
export default async function (ctx: FunctionContext) {
const _body = ctx.body;
const _query = ctx.query;
const _type = _body.type ? _body.type : _query.type;
if (!_type) {
return resultData(-1, '参数type不能为空!');
}
switch (_type) {
case 'shortTextToVoice':
return await shortTextToVoice(_body.param);
case 'longTextToVoice':
return await longTextToVoice(_body.param);
case 'searchTextToVoice':
return await searchTextToVoice(_body.param);
case 'createVoiceToText':
return await createVoiceToText(_body.param);
case 'searchVoiceToText':
return await searchVoiceToText(_body.param);
default:
return resultData(-1, '请检查参数type是否有误!');
}
}
async function shortTextToVoice(param) {
console.log('shortTextToVoice', param);
const _param = param;
if (!_param.text) {
return resultData(-1, '参数text不能为空!');
}
if (_param.text.length > 60) {
return resultData(-1, '不能超过60个汉字或者字母数字!');
}
const access_token = await getAccessToken();
if (!access_token) {
return resultData(-1, 'AccessToken获取失败!');
}
try {
let _text = _param.text;
console.log('shortTextToVoice-->text编码后:', _text);
let _cuid = Math.ceil(Math.random() * 1000000000000);
let obj = null;
await cloud.fetch({
url: 'https://tsn.baidu.com/text2audio',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': '*/*'
},
data: {
'tex': _text,
'tok': access_token,
'cuid': _cuid,
'ctp': '1',
'lan': 'zh',
'spd': _param.spd ? _param.spd : '5',
'pit': _param.pit ? _param.pit : '5',
'vol': _param.vol ? _param.vol : '5',
'per': _param.per ? _param.per : '1',
'aue': _param.aue ? _param.aue : '3'
},
responseType: 'stream',
}).then(function (res) {
let content_type = res.headers['content-type'];
if (res.status == 200 && content_type && content_type.toLowerCase().indexOf('audio') > -1) {
obj = resultData(0, '成功!', res.data);
}
else {
obj = resultData(-1, '语音合成失败,err_detail:' + res.data.err_detail);
}
}).catch(function (err) {
console.log('短文本转语音异常!', err.message);
obj = resultData(-1, '语音合成异常:' + err.message);
});
if (obj.code == 0) {
let fileName = 'TextToVoice/' + _cuid;
let _aue = _param.aue ? _param.aue : '3';
switch (_aue) {
case '4':
case '5':
fileName = fileName + '.pcm';
break;
case '6':
fileName = fileName + '.wav';
break;
default:
fileName = fileName + '.mp3';
break;
}
const ret = await cloud.invoke('store-file', {
body: {
type: 'storeFile',
param: {
fileName: fileName,
fileBody: obj.data,
contentType: 'application/octet-stream'
}
}
});
if (ret.code == 0) {
obj = resultData(0, '语音合成成功!', ret.data);
}
else {
obj = resultData(-1, ret.msg);
}
}
return obj;
}
catch (e) {
return resultData(-1, '异常错误:' + e.message);
}
}
async function longTextToVoice(param) {
console.log('longTextToVoice', param);
const _param = param;
if (!_param.text || _param.text.length == 0) {
return resultData(-1, '参数text不能为空!');
}
const access_token = await getAccessToken();
if (!access_token) {
return resultData(-1, 'AccessToken获取失败!');
}
try {
let obj = null;
await cloud.fetch({
url: 'https://aip.baidubce.com/rpc/2.0/tts/v1/create?access_token=' + access_token,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
data: {
'text': _param.text,
'format': _param.format ? _param.format : 'mp3-16k',
'voice': _param.voice ? _param.voice : 0,
'lang': 'zh',
'speed': _param.speed ? _param.speed : 5,
'pitch': _param.pitch ? _param.pitch : 5,
'volume': _param.volume ? _param.volume : 5,
'enable_subtitle': _param.enable_subtitle ? _param.enable_subtitle : '0',
}
}).then(function (res) {
let d = res.data;
if (res.status == 200 && d.task_id) {
obj = resultData(0, '长文本转语音成功!', d);
}
else {
obj = resultData(-1, '长文本转语音失败!' + d.error_msg);
}
}).catch(function (err) {
console.log('长文本转语音异常!', err.message);
obj = resultData(-1, '长文本转语音异常:' + err.message);
});
return obj;
}
catch (e) {
return resultData(-1, '异常错误:' + e.message);
}
}
async function searchTextToVoice(param) {
console.log('searchTextToVoice', param);
const _param = param;
if (!_param.taskIds || _param.taskIds == 0) {
return resultData(-1, '参数taskIds不能为空!');
}
const access_token = await getAccessToken();
if (!access_token) {
return resultData(-1, 'AccessToken获取失败!');
}
try {
let obj = null;
await cloud.fetch({
url: 'https://aip.baidubce.com/rpc/2.0/tts/v1/query?access_token=' + access_token,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
data: {
'task_ids': _param.taskIds,
}
}).then(function (res) {
let d = res.data;
if (res.status == 200 && d.tasks_info) {
obj = resultData(0, '长文本转语音-查询成功!', d.tasks_info);
}
else {
obj = resultData(-1, '长文本转语音-查询失败!' + d.error_msg);
}
}).catch(function (err) {
console.log('长文本转语音-查询异常!', err.message);
obj = resultData(-1, '长文本转语音-查询异常:' + err.message);
});
return obj;
}
catch (e) {
return resultData(-1, '异常错误:' + e.message);
}
}
async function createVoiceToText(param) {
console.log('voiceToText->param', param);
const _param = param;
if (!_param.fileUrl || !_param.fileType || _param.fileType.toLowerCase().indexOf('audio') < 0) {
return resultData(-1, '请上传音频文件!');
}
if (!_param.fileName) {
return resultData(-1, '文件名称不能为空');
}
const _format = ['mp3', 'wav', 'pcm', 'm4a', 'amr'];
let _fileName = _param.fileName.toLowerCase().split('.');
if (_format.indexOf(_fileName[1]) < 0) {
return resultData(-1, '仅支持mp3、wav、pcm、m4a、amr格式的音频文件!');
}
const limitSize = 50 * 1024 * 1024;
if (!_param.fileSize || _param.fileSize > limitSize) {
return resultData(-1, '音频文件大小不能超过50M!');
}
const access_token = await getAccessToken();
if (!access_token) {
return resultData(-1, 'AccessToken获取失败!');
}
try {
let fileFormat = _param.fileName.split('.')[1];
let obj = null;
await cloud.fetch({
url: 'https://aip.baidubce.com/rpc/2.0/aasr/v1/create?access_token=' + access_token,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
data: {
'speech_url': _param.fileUrl,
'format': fileFormat,
'pid': _param && _param.pid ? _param.pid : 80001,
'rate': 16000
}
}).then(function (res) {
let d = res.data;
if (res.status == 200 && d.task_id) {
obj = resultData(0, '音频转写成功!', d);
}
else {
obj = resultData(-1, '音频转写失败!' + d.error_msg);
}
}).catch(function (err) {
console.log('音频转写异常!', err.message);
obj = resultData(-1, '音频转写异常:' + err.message);
});
return obj;
}
catch (e) {
return resultData(-1, '异常错误:' + e.message);
}
}
async function searchVoiceToText(param) {
console.log('searchVoiceToText', param);
const _param = param;
if (!_param.taskIds || _param.taskIds.length == 0) {
return resultData(-1, '参数taskIds不能为空!');
}
const access_token = await getAccessToken();
if (!access_token) {
return resultData(-1, 'AccessToken获取失败!');
}
try {
let obj = null;
await cloud.fetch({
url: 'https://aip.baidubce.com/rpc/2.0/aasr/v1/query?access_token=' + access_token,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
data: {
'task_ids': _param.taskIds,
}
}).then(function (res) {
let d = res.data;
if (res.status == 200 && d.tasks_info) {
obj = resultData(0, '音频转写-查询成功!', d.tasks_info);
}
else {
obj = resultData(-1, '音频转写-查询失败!' + d.error_msg);
}
}).catch(function (err) {
console.log('音频转写-查询异常!', err.message);
obj = resultData(-1, '音频转写-查询异常:' + err.message);
});
return obj;
}
catch (e) {
return resultData(-1, '异常错误:' + e.message);
}
}
async function getAccessToken() {
let access_token = '';
try {
await cloud.fetch({
url: 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=' + apiKey + '&client_secret=' + secretKey,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
}).then(function (res) {
let d = res.data;
if (res.status == 200 && d.access_token) {
access_token = d.access_token;
}
else {
console.log('获取AccessToken失败!' + d.error_msg);
}
}).catch(function (err) {
console.log('获取AccessToken异常!', err.message);
});
}
catch (e) {
console.log('异常错误:' + e.message);
}
return access_token;
}
function resultData(code = -1, msg = '', data = null) {
return { code, msg, data }
}