流程
- 首先小程序后台配置白名单
1.1 路径:开发-开发管理-开发设置-服务器域名-request合法域名
1.2 request合法域名参数:
https://nls-meta.cn-shanghai.aliyuncs.com
https://nls-gateway-cn-shanghai.aliyuncs.com - 引入alitts.js
- 页面使用
3.1 只需替换AccessKeyID、AccessKeySecret 、appkey三个参数即可直接使用
AccessKeyID、AccessKeySecret 、appkey获取地址:
static/js/alitts.js 用于获取阿里云动态token
javascript
// 这个东西我都没执行yarn add crypto竟然能用,可能另一个项目安装了全局共享了,如报错找不到,执行一下yarn add crypto
import crypto from 'crypto'
export class AccessToken {
static encodeText(text) {
let encodedText = encodeURIComponent(text);
return encodedText.replace('+', '%20').replace('*', '%2A').replace('~', '%7E');
}
static encodeDict(dict) {
let keys = Object.keys(dict).sort();
return keys.map(key => `${this.encodeText(key)}=${this.encodeText(dict[key])}`).join('&');
}
static async createToken(accessKeyId, accessKeySecret) {
const parameters = {
AccessKeyId: accessKeyId,
Action: 'CreateToken',
Format: 'JSON',
RegionId: 'cn-shanghai',
SignatureMethod: 'HMAC-SHA1',
SignatureNonce: uuidv4(),
SignatureVersion: '1.0',
Timestamp: new Date().toISOString(),
Version: '2019-02-28'
};
const queryString = this.encodeDict(parameters);
console.log('Normalized request string:', queryString);
const stringToSign = `GET&${this.encodeText('/')}&${this.encodeText(queryString)}`;
console.log('String to sign:', stringToSign);
const hmac = crypto.createHmac('sha1', `${accessKeySecret}&`);
hmac.update(stringToSign);
const signature = hmac.digest('base64');
console.log('Signature:', signature);
const encodedSignature = this.encodeText(signature);
console.log('URL-encoded signature:', encodedSignature);
const fullUrl = `https://nls-meta.cn-shanghai.aliyuncs.com/?Signature=${encodedSignature}&${queryString}`;
console.log('URL:', fullUrl);
let resData = await new Promise((resolve, reject) => {
uni.request({
url: fullUrl,
method: 'GET',
success: res => {
const data = res.data
resolve({
token: data.Token.Id,
expireTime: data.Token.ExpireTime
})
},
fail: error => {
console.log(error)
reject(error)
}
})
})
console.log('res',resData)
if(resData){
return resData
}
// Using fetch for HTTP request
// const response = await fetch(fullUrl);
// if (response.ok) {
// const jsonResponse = await response.json();
// if (jsonResponse.Token) {
// return {
// token: jsonResponse.Token.Id,
// expireTime: jsonResponse.Token.ExpireTime
// };
// }
// }
// console.error(await response.text());
return {
token: null,
expireTime: null
};
}
}
// Sample UUIDv4 function, or you could use a library like `uuid`
function uuidv4() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
使用
javascript
// 阿里云动态token获取函数
import { AccessToken } from "@/static/js/alitts"
// 阿里云动态token
const aliToken = null
// 需要在阿里云管理平台获取
const AccessKeyID = '你的AccessKeyID '
const AccessKeySecret = '你的AccessKeySecret '
// 需要在阿里云tts管理平台创建项目
const appkey = '你的阿里云后台创建项目的key'
export default {
name: "tts",
data() {
return {
isPlay:false,
// tts播放实例
ttsAudio: null,
}
},
onUnload() {
if(this.ttsAudio){
this.ttsAudio.stop()
this.ttsAudio.destroy()
}
},
async onLoad(val) {
// 获取阿里云动态token,tts需要此参数
AccessToken.createToken(AccessKeyID, AccessKeySecret).then(({ token, expireTime }) => {
console.log('阿里云token:', token, 'Expire Time:', expireTime);
aliToken = token
});
// 模拟调用
setTimeout(() => {
this.tts('刘斩仙明天要去江苏,晚上回来又约了朋友撸串,忙死了')
},5000)
},
methods: {
/**
* 文字转语音
* @param {string} text
*/
tts(text) {
uni.request({
url:'https://nls-gateway-cn-shanghai.aliyuncs.com/stream/v1/tts',
method:'POST',
// header:{
// "Content-Type": "application/json"
// },
data:{
appkey: appkey,
token: aliToken,
text: text,
format: 'mp3',
sample_rate: 16000,
volume: 100
},
// dataType:'tts',
responseType:'arraybuffer',
success:ttsRes => {
console.log('阿里云:')
// 语音
const audio = uni.createInnerAudioContext();
// 设置不遵循静音开关播放,否则ios无法外音播放
audio.obeyMuteSwitch = false
uni.setInnerAudioOption({
obeyMuteSwitch: false
})
// 临时路径-此处必须加时间戳或者随机数,否则同样临时路径无法覆盖,小程序bug
const ttsPath = `${wx.env.USER_DATA_PATH}/tts${new Date().getTime()}.mp3`
if(this.ttsAudio){
this.ttsAudio.stop()
this.ttsAudio.destroy()
}
this.ttsAudio = audio
// 将 arrayBuffer 写入临时文件
const fs = uni.getFileSystemManager()
try {
const writeRes = fs.writeFileSync(ttsPath, ttsRes.data, "binary")
console.log('writeRes',writeRes)
} catch(e) {
console.error(e)
}
audio.src = ttsPath
audio.autoplay = false;
audio.onError((res) => {
console.error('音频播放出错', res);
});
// 监听播放完成
audio.onEnded(() => {
console.log('音频播放结束');
this.isPlay = false
// 播放完成后删除临时文件,此处虽然设置同步删除即使执行成功,文件也不会立即删除,还是能访问到,实际删除为异步操作
try {
const unlinkRes = fs.unlinkSync(ttsPath)
console.log('unlinkRes',unlinkRes)
} catch(e) {
console.error(e)
}
});
// 播放音频
audio.onCanplay(() => {
console.log('音频开始播放');
this.ttsAudio.play();
this.isPlay = true
})
}
})
}
},
}
备注:
就想到这些,如果还有需要注意的后续再补充;最近骑电车要带头盔,飘逸的发型压得趴在头上,影响刘斩仙风度翩翩谦谦君子形象,可恶啊!