@minto-ai/xunfei-tts
Version:
借助“讯飞在线语音合成API”实现浏览器端“文本转语音
113 lines (95 loc) • 3.48 kB
text/typescript
import type { SerialTaskExecuteContext } from '../handler'
import type { BusinessParams, PrivateCustomEventName, SystemConfig } from '../types'
import { createWebSocket } from '@minto-ai/tools'
import CryptoJS from 'crypto-js'
import { SerialHandler } from '../handler'
import { createEventBus, encodeText } from '../utils'
const $bus = createEventBus<PrivateCustomEventName>()
const defaultBusinessParams: BusinessParams = {
aue: 'raw',
sfl: 1,
auf: 'audio/L16;rate=16000',
vcn: 'xiaoyan',
speed: 50,
volume: 50,
pitch: 50,
bgs: 0,
tte: 'UTF8',
reg: '2',
rdn: '0',
}
class TtsRequest extends SerialHandler<string, string> {
private systemConfig!: SystemConfig
private businessParams!: BusinessParams
private webSockeSet: Set<WebSocket> = new Set()
public initProperty(systemConfig: SystemConfig, businessParams: Partial<BusinessParams>): void {
this.systemConfig = systemConfig
this.businessParams = { ...defaultBusinessParams, ...businessParams }
}
public execute(
context: SerialTaskExecuteContext<string, string>,
): void {
if (context.isLastExecute) {
this.taskCompletedCallback()
return
}
const webSocketInstance = createWebSocket(this.generateRequestUrl())
this.webSockeSet.add(webSocketInstance)
webSocketInstance.addEventListener('open', async () => {
webSocketInstance.send(JSON.stringify(this.generateRequestParams(context.taskItem.original!)))
webSocketInstance.addEventListener('message', (response: any) => {
const { code, data } = JSON.parse(response.data)
const { audio: audioData, status } = data
if (code === 0) {
if (audioData) {
this.forwardToHandler(audioData)
}
}
if (status === 2) {
this.webSockeSet.delete(webSocketInstance)
webSocketInstance.close()
this.taskCompletedCallback()
}
})
})
}
private generateRequestParams(text: string): any {
return {
common: {
app_id: this.systemConfig.APPID,
},
business: {
...this.businessParams,
},
data: {
status: 2,
text: encodeText(text, this.businessParams.tte!),
},
}
}
private generateRequestUrl(): string {
const apiKey = this.systemConfig.API_KEY
const apiSecret = this.systemConfig.API_SECRET
let url = 'wss://tts-api.xfyun.cn/v2/tts'
const { host } = window.location
const date = (new Date() as any).toGMTString()
const algorithm = 'hmac-sha256'
const headers = 'host date request-line'
const signatureOrigin = `host: ${host}\ndate: ${date}\nGET /v2/tts HTTP/1.1`
const signatureSha = CryptoJS.HmacSHA256(signatureOrigin, apiSecret)
const signature = CryptoJS.enc.Base64.stringify(signatureSha)
const authorizationOrigin = `api_key="${apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`
const authorization = btoa(authorizationOrigin)
url = `${url}?authorization=${authorization}&date=${date}&host=${host}`
return url
}
protected onFinish(): void {
$bus.emit('_ttsRequestFinish')
if (this.webSockeSet && this.webSockeSet.size) {
this.webSockeSet.forEach(ws => ws.close())
this.webSockeSet.clear()
}
this.webSockeSet = new Set()
}
}
export default TtsRequest