本文介紹如何使用阿里云智能語音服務提供的微信小程序SDK,包括SDK的安裝方法及SDK代碼示例。
前提條件
在使用SDK前,請先閱讀接口說明,詳情請參見接口說明。
下載安裝
微信基礎庫要求2.4.4及以上版本。
請確認已經安裝微信小程序開發環境,并完成基本配置。具體可參見微信開發者工具。
需要提前將如下URL添加到微信小程序后臺服務器域名中:
request合法域名:
https://nls-meta.cn-shanghai.aliyuncs.com
socket合法域名:
wss://nls-gateway.cn-shanghai.aliyuncs.com
下載并安裝SDK。
通過Github下載對應SDK代碼,或直接下載alibabacloud-nls-wx-sdk-master.zip。
導入SDK。
您可將下載好的代碼放入工程合適目錄下,然后根據目錄位置通過require進行導入。
獲取Token
getToken
獲取Token并以akid和akkey為key緩存對應Token,如果緩存的Token過期則自動刷新并獲取。緩存機制請參見微信小程序文檔的數據緩存部分。
參數說明:無。
返回值:String類型的Token。
getTokenInner
直接獲取Token,不帶任何緩存機制,適用于用戶自定義緩存方式。
頻繁調用該接口會被服務端拒絕訪問。
參數說明:無。
返回值:String類型的Token。
語音合成
Class: SpeechSynthesizer
SpeechSynthesizer類用于進行語音合成。
構造函數參數說明:
參數 | 類型 | 參數說明 |
config | Object | 連接配置對象。 |
config object說明:
參數 | 類型 | 參數說明 |
url | String | 服務URL地址。 |
token | String | 訪問Token,詳情可參見獲取Token概述。 |
appkey | String | 對應項目Appkey。 |
defaultStartParams(voice)
返回一個默認的推薦參數,其中voice為您自行提供,采樣率為16000 Hz,格式為WAV,音量50,語速語調皆為0,不開啟字幕。您在拿到默認對象后可以根據自身需求,結合接口說明中的參數列表來添加和修改參數。
參數說明:
參數
類型
參數說明
voice
String
發音人。
返回值:
object類型對象,字段如下:
{ "voice": voice, "format": "wav", "sample_rate": 16000, "volume": 50, "speech_rate": 0, "pitch_rate": 0, "enable_subtitle": false }
on(which, handler)
設置事件回調。
參數說明:
參數 | 類型 | 參數說明 |
which | String | 事件名稱。 |
handler | Function | 回調函數。 |
支持的回調事件如下:
事件名稱 | 事件說明 | 回調函數參數個數 | 回調函數參數說明 |
meta | 字幕回調。 | 1 | String類型,字幕信息。 |
data | 合成音頻回調。 | 1 | Arraybuffer類型,合成音頻數據。 |
completed | 語音合成完成。 | 1 | String類型,完成信息。 |
closed | 連接關閉。 | 0 | 無。 |
failed | 錯誤。 | 1 | String類型,錯誤信息。 |
返回值:無。
async start(param)
根據param發起一次一句話識別,param可以參考defaultStartParams方法的返回,具體參數見接口說明。
參數說明:
參數 | 類型 | 參數說明 |
param | Object | 語音合成參數。 |
返回值: Promise對象,當started事件發生后觸發resolve,并攜帶started信息;當任何錯誤發生后觸發reject,并攜帶異常信息。
代碼示例
以下代碼示例僅供參考,代碼中使用微信小程序自帶錄音功能,實際使用時,需要考慮微信小程序的限制,以及前端頁面設計和具體業務功能。
// pages/tts/tts.js
const app = getApp()
const AKID = "Your AKID"
const AKKEY = "Your AKKEY"
const SpeechSynthesizer = require("../../utils/tts")
const formatTime = require("../../utils/util").formatTime
const sleep = require("../../utils/util").sleep
const getToken = require("../../utils/token").getToken
const fs = wx.getFileSystemManager()
Page({
/**
* 頁面的初始數據
*/
data: {
ttsStart: false,
ttsText: ""
},
/**
* 生命周期函數--監聽頁面加載
*/
onLoad: async function (options) {
try {
this.data.token = await getToken(AKID, AKKEY)
} catch (e) {
console.log("error on get token:", JSON.stringify(e))
return
}
let tts = new SpeechSynthesizer({
url: app.globalData.URL,
appkey:app.globalData.APPKEY,
token:this.data.token
})
tts.on("meta", (msg)=>{
console.log("Client recv metainfo:", msg)
})
tts.on("data", (msg)=>{
console.log(`recv size: ${msg.byteLength}`)
//console.log(dumpFile.write(msg, "binary"))
if (this.data.saveFile) {
try {
fs.appendFileSync(
this.data.saveFile,
msg,
"binary"
)
console.log(`append ${msg.byteLength}`)
} catch (e) {
console.error(e)
}
} else {
console.log("save file empty")
}
})
tts.on("completed", async (msg)=>{
console.log("Client recv completed:", msg)
await sleep(500)
fs.close({
fd : this.data.saveFd,
success: (res)=> {
let ctx = wx.createInnerAudioContext()
ctx.autoplay = true
ctx.src = this.data.saveFile
ctx.onPlay(() => {
console.log('start playing..')
})
ctx.onError((res) => {
console.log(res.errMsg)
console.log(res.errCode)
fs.unlink({
filePath: this.data.saveFile,
success: (res)=>{
console.log(`remove ${this.data.saveFile} done`)
this.data.saveFile = null
this.data.saveFd = null
},
failed: (res)=>{
console.log("remove failed:" + res.errMsg)
}
})
})
ctx.onEnded((res)=>{
console.log("play done...")
fs.unlink({
filePath: this.data.saveFile,
success: (res)=>{
console.log(`remove ${this.data.saveFile} done`)
this.data.saveFile = null
this.data.saveFd = null
},
failed: (res)=>{
console.log("remove failed:" + res.errMsg)
}
})
})
},
fail : (res)=>{
console.log("saved file error:" + res.errMsg)
}
})
})
tts.on("closed", () => {
console.log("Client recv closed")
})
tts.on("failed", (msg)=>{
console.log("Client recv failed:", msg)
})
this.data.tts = tts
},
/**
* 生命周期函數--監聽頁面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函數--監聽頁面顯示
*/
onShow: function () {
},
/**
* 生命周期函數--監聽頁面隱藏
*/
onHide: function () {
},
/**
* 生命周期函數--監聽頁面卸載
*/
onUnload: function () {
},
/**
* 頁面相關事件處理函數--監聽用戶下拉動作
*/
onPullDownRefresh: function () {
},
/**
* 頁面上拉觸底事件的處理函數
*/
onReachBottom: function () {
},
/**
* 用戶點擊右上角分享
*/
onShareAppMessage: function () {
},
textInput: function(e) {
this.setData({
ttsText:e.detail.value
})
},
onTtsStart: function() {
if (!this.data.ttsText || !this.data.tts) {
console.log("text empty")
wx.showToast({
title: "文本為空",
icon: "error",
duration: 1000,
mask: true
})
return
}
if (this.data.ttsStart) {
wx.showToast({
title: "正在合成請稍候",
icon: "error",
duration: 1000,
mask: true
})
return
} else {
this.data.ttsStart = true
}
console.log("try to synthesis:" + this.data.ttsText)
let save = formatTime(new Date()) + ".wav"
let savePath = wx.env.USER_DATA_PATH + "/" + save
console.log(`save to ${savePath}`)
fs.open({
filePath:savePath,
flag : "a+",
success: async (res)=> {
console.log(`open ${savePath} done`)
this.data.saveFd = res.fd
this.data.saveFile = savePath
let param = this.data.tts.defaultStartParams()
param.text = this.data.ttsText
param.voice = "aixia"
try {
await this.data.tts.start(param)
console.log("tts done")
this.data.ttsStart = false
} catch(e) {
console.log("tts start error:" + e)
}
},
fail: (res)=> {
console.log(`open ${savePath} failed: ${res.errMsg}`)
}
})
}
})