uni-app 微信小程序 WebSocket 接入讯飞语音合成(流式版)WebAPI 示例

语音合成(流式版)WebAPI 文档

安装库

yarn add crypto-js

JS 完整代码

import CryptoJS from 'crypto-js';

const config = {
    
    
  // 请求地址
  hostUrl: "wss://tts-api.xfyun.cn/v2/tts",
  host: "tts-api.xfyun.cn",
  //在控制台-我的应用-在线语音合成(流式版)获取
  appid: "xxxxx",
  //在控制台-我的应用-在线语音合成(流式版)获取
  apiSecret: "xxxxx",
  //在控制台-我的应用-在线语音合成(流式版)获取
  apiKey: "xxxxx",
  uri: "/v2/tts",
}

const getWebSocketUrl = () => {
    
    
  let url = "wss://tts-api.xfyun.cn/v2/tts";
  let date = new Date().toGMTString();
  let algorithm = "hmac-sha256";
  let headers = "host date request-line";
  let signatureOrigin = `host: ${
      
      config.host}\ndate: ${
      
      date}\nGET /v2/tts HTTP/1.1`;
  let signatureSha = CryptoJS.HmacSHA256(signatureOrigin, config.apiSecret);
  let signature = CryptoJS.enc.Base64.stringify(signatureSha);
  let authorizationOrigin = `api_key="${
      
      config.apiKey}", algorithm="${
      
      algorithm}", headers="${
      
      headers}", signature="${
      
      signature}"`;
  let authorization = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(authorizationOrigin))
  return `${
      
      url}?authorization=${
      
      authorization}&date=${
      
      date}&host=${
      
      config.host}`;
}

const encodeText = (text, type) => {
    
    
  if (type === "unicode") {
    
    
    // 使用CryptoJS处理UTF-16BE编码
    const utf16BE = CryptoJS.enc.Utf16BE.parse(text);
    return CryptoJS.enc.Base64.stringify(utf16BE);
  } else {
    
    
    // 使用CryptoJS的Base64直接编码
    const utf8WordArray = CryptoJS.enc.Utf8.parse(text);
    return CryptoJS.enc.Base64.stringify(utf8WordArray);
  }
}

const writeFile = (path, data) => {
    
    
  const fs = uni.getFileSystemManager()
  return new Promise((resolve, reject) => {
    
    
    fs.writeFile({
    
    
      filePath: path,
      data,
      encoding: 'utf8',
      success: resolve,
      fail: reject
    });
  });
}

const play = (target) => {
    
    
  const innerAudioContext = uni.createInnerAudioContext();
  innerAudioContext.autoplay = true;
  innerAudioContext.src = target;
  innerAudioContext.onPlay(() => {
    
    
    console.log('播放事件');
  })

  innerAudioContext.onError((err) => {
    
    
    console.log('错误事件', err);
  })
}

export const ttsTest = async (msg) => {
    
    
  const wssUrl = getWebSocketUrl()

  const msgData = {
    
    
    "common": {
    
    
      "app_id": config.appid
    },
    "business": {
    
    
      "aue": "lame",
      "auf": "audio/L16;rate=16000",
      "vcn": "xiaoyan",
      "tte": "UTF8"
    },
    "data": {
    
    
      "text": encodeText(msg, 'UTF8'),
      "status": 2
    }
  }

  const socketTask = await uni.connectSocket({
    
    
    url: wssUrl,
    header: {
    
    
      'content-type': 'application/json'
    },
    method: 'GET',
    success: (res) => {
    
    
      console.log('connectSocket success', res)
    },
    fail: (err) => {
    
    
      console.log('connectSocket fail', err)
    },
    complete: (res) => {
    
    
      console.log('connectSocket complete', res)
    }
  });

  socketTask.onMessage(res => {
    
    
    console.log('onMessage', JSON.parse(res.data))
    const {
    
     code, message, sid, data } = JSON.parse(res.data);
    if (code === 0 && data.status === 2) {
    
    
      // 注意:将base64转化成ArrayBuffer
      const dataBuffer = uni.base64ToArrayBuffer(data.audio);
      const target = `${
      
      wx.env.USER_DATA_PATH}/${
      
      new Date().getTime()}.mp3`;
      console.log('target', target)
      try {
    
    
        writeFile(target, dataBuffer)
        // 播放
        play(target)
        socketTask.close(res => {
    
    
          console.log('close', res)
        })
      } catch (e) {
    
    
        console.error(e);
        socketTask.close(res => {
    
    
          console.log('close', res)
        })
      }
    }
  })

  socketTask.onClose(res => {
    
    
    console.log('onClose', res)
  })

  socketTask.onError(err => {
    
    
    console.log('onError', err)
  })

  socketTask.onOpen(data => {
    
    
    console.log('onOpen', data)
	  
    socketTask.send({
    
    
      data: JSON.stringify(msgData),
      success: (res) => {
    
    
        console.log('send', res)
      }
    })
	  
  })

}