Node.js SDK

本文介绍如何使用阿里云智能语音服务提供的Node.js SDK,包括SDK的安装方法及SDK代码示例。

前提条件

在使用SDK前,请先阅读接口说明,详情请参见接口说明

下载安装

说明
  • SDK支持nodev14及以上版本。

  • 请确认已经安装nodejs&npm环境,并完成基本配置。

  1. 下载并安装SDK。

    通过以下命令完成SDK下载和安装。

    npm install alibabacloud-nls
  2. 导入SDK。

    在代码中使用require或者import导入SDK。

    const Nls = require('alibabacloud-nls')
    //Nls内部含SpeechRecognition, SpeechTranscription, SpeechSynthesizer
    //以下为使用import导入SDK
    //import { SpeechRecognition } from "alibabacloud-nls"
    //import { SpeechTranscription } from "alibabacloud-nls"
    //import { SpeechSynthesizer } from "alibabacloud-nls"

关键接口和参数描述

Node.js中,实现语音合成的功能,围绕SpeechSynthesizer类进行,一般按照如下步骤编写代码(步骤2和步骤3顺序可互换):

  1. 创建SpeechSynthesizer实例,此时会传入语音合成服务地址和认证信息。

  2. 设置语音合成的发音人、采样率、音频格式等属性:创建属性对象或者修改SpeechSynthesizer实例的defaultStartParams方法返回的默认属性对象。

  3. 补充SpeechSynthesizer实例的回调函数on的细节(观察者模式——当连接成功建立、合成语音、发生异常等时,服务器会通过回调on函数通知客户端)。

  4. 调用SpeechSynthesizer实例的start函数开始语音合成。

1. SpeechSynthesizer

SpeechSynthesizer类用于语音合成。

SpeechSynthesizer的构造函数参数说明如下:

参数

类型

参数说明

config

Object

连接配置对象。

config参数说明:

参数

类型

参数说明

url

String

语音合成服务地址。默认值为wss://nls-gateway.cn-shanghai.aliyuncs.com/ws/v1。

您需要配置符合自己实际情况的地址,参见服务地址进行获取。

token

String

访问Token,详情可参见获取Token概述

appkey

String

对应项目Appkey。

示例:

let tts = new Nls.SpeechSynthesizer({
    url: URL,
    appkey: APPKEY,
    token: TOKEN
})

2. 设置语音合成的发音人、采样率、音频格式等属性

可以基于SpeechSynthesizer实例的defaultStartParams方法返回的默认属性对象进行设置,也可以自定义一个属性对象。该属性对象在调用SpeechSynthesizer实例的start函数时需要传入。

参数说明:

参数

类型

是否必需

说明

text

String

待合成文本,文本内容必须采用UTF-8编码,长度不超过300个字符(英文字母之间需要添加空格)。

说明

调用某音色的多情感内容,需要在text中加上ssml-emotion标签,详情请参见<emotion>

只有支持多情感的音色,才能使用<emotion>标签,否则会报错:Illegal ssml text。

voice

String

发音人,默认是xiaoyun

format

String

音频编码格式,支持.pcm、.wav和.mp3格式。默认值:pcm

sample_rate

Integer

音频采样率,默认值:16000 Hz。

volume

Integer

音量,取值范围:0~100。默认值:50。

speech_rate

Integer

语速,取值范围:-500~500,默认值:0。

[-500, 0, 500] 对应的语速倍速区间为 [0.5, 1.0, 2.0]。

  • -500表示默认语速的0.5倍速。

  • 0表示默认语速的1倍速。1倍速是指模型默认输出的合成语速,语速会依据每一个发音人略有不同,大概每秒钟4个字左右。

  • 500表示默认语速的2倍速。

计算方法如下:

  • 0.8倍速(1-1/0.8)/0.002 = -125

  • 1.2倍速(1-1/1.2)/0.001 = 166

说明

  • 小于1倍速时,使用0.002系数。

  • 大于1倍速时,使用0.001系数。

实际算法结果取近似值。

pitch_rate

Integer

语调,取值范围:-500~500,默认值:0。

enable_subtitle

Boolean

开启字级别时间戳。更多使用方法,请参见语音合成时间戳功能介绍

基于defaultStartParams返回的默认属性进行设置

defaultStartParams函数返回一个对象:

{
  voice: voice, // voice的值为调用函数时传入的参数
  format: "wav",
  sample_rate: 16000,
  volume: 50,
  speech_rate: 0,
  pitch_rate: 0,
  enable_subtitle: false
}

可对该对象重新设置,例如:

let param = tts.defaultStartParams();
// 待合成文本
param.text = "举头望明月,低头思故乡";
// 发音人
param.voice = "aixia";
// 语调,范围是-500~500,可选,默认是0
// param.pitch_rate = 100;
// 语速,范围是-500~500,默认是0
// param.speech_rate = 100;
// 设置返回音频的编码格式
// param.format = "wav";
// 设置返回音频的采样率
// param.sample_rate = 16000;
// 是否开启字级别时间戳
// param.enable_subtitle = true;

自定义属性对象

let param = {};
// 待合成文本
param.text = line;
// 发音人
param.voice = "aixia";
// 语调,范围是-500~500,可选,默认是0
// param.pitch_rate = 100;
// 语速,范围是-500~500,默认是0
// param.speech_rate = 100;
// 设置返回音频的编码格式
// param.format = "wav";
// 设置返回音频的采样率
// param.sample_rate = 16000;
// 是否开启字级别时间戳
// param.enable_subtitle = true;

3. 回调函数on

on函数源码如下:

on(which, handler) {
  this._event.on(which, handler)
}

语音合成任务开启后,服务端会回调该函数,将语音合成过程中的一些信息返回给客户端。

参数

类型

参数说明

which

String

事件名称。

handler

Function

回调函数。

其中,which参数对应的事件如下:

事件名称

事件说明

回调函数参数个数

回调函数参数说明

meta

字幕回调。

1

String类型,字幕信息。

data

合成音频回调。

1

Buffer类型,合成音频数据。

completed

语音合成完成。

1

String类型,完成信息。

closed

连接关闭。

0

无。

failed

错误。

1

String类型,错误信息。

示例:

let tts = new Nls.SpeechSynthesizer({
  url: URL,
  appkey:APPKEY,
  token:TOKEN
})

tts.on("meta", (msg)=>{
  console.log("Client recv metainfo:", msg)
})

tts.on("data", (msg)=>{
  console.log(`recv size: ${msg.length}`)
  console.log(dumpFile.write(msg, "binary"))
})

tts.on("completed", (msg)=>{
  console.log("Client recv completed:", msg)
})

tts.on("closed", () => {
  console.log("Client recv closed")
})

tts.on("failed", (msg)=>{
  console.log("Client recv failed:", msg)
})

4. 任务开启:start

start函数如下,根据传入的param的信息,开始语音合成,服务器会通过调用回调函数on返回语音合成的结果等信息。

async start(param, enablePing, pingInterval)

参数说明:

参数

类型

参数说明

param

Object

语音合成参数。

enablePing

Boolean

是否自动向云端发送ping请求,默认false。

  • true:发送。

  • false:不发送。

pingInterval

Number

ping请求间隔时间,默认6000,单位为毫秒。

返回值: Promise对象,当错误发生后携带异常信息。

代码示例

"use strict"

require('log-timestamp')(`${process.pid}`)
const fs = require("fs")
const Nls = require("alibabacloud-nls")
const sleep = (waitTimeInMs) => new Promise(resolve => setTimeout(resolve, waitTimeInMs))
const util = require("util")
const readline = require("readline")
const args = process.argv.slice(2)
//const Memwatch = require("node-memwatch-new")

const URL = "wss://nls-gateway-cn-shanghai.aliyuncs.com/ws/v1"
const APPKEY = "Your Appkey"      //获取Appkey请前往控制台:https://nls-portal.console.aliyun.com/applist
const TOKEN = "Your Token"      //获取Token具体操作,请参见:https://help.aliyun.com/document_detail/450514.html

let b1 = []
let loadIndex = 0
//let hd = new Memwatch.HeapDiff()
let needDump = true

async function runOnce(line) {
  console.log(`speak: ${line}`)
  loadIndex++

  //let dumpFile = fs.createWriteStream(`${process.pid}.wav`, {flags:"w"})
  let tts = new Nls.SpeechSynthesizer({
    url: URL,
    appkey:APPKEY,
    token:TOKEN
  })

  tts.on("meta", (msg)=>{
    console.log("Client recv metainfo:", msg)
  })

  tts.on("data", (msg)=>{
    console.log(`recv size: ${msg.length}`)
    //console.log(dumpFile.write(msg, "binary"))
  })

  tts.on("completed", (msg)=>{
    console.log("Client recv completed:", msg)
  })

  tts.on("closed", () => {
    console.log("Client recv closed")
  })

  tts.on("failed", (msg)=>{
    console.log("Client recv failed:", msg)
  })

  let param = tts.defaultStartParams()
  // 待合成文本
  param.text = line
  // 发音人
  param.voice = "aixia"
  // 语调,范围是-500~500,可选,默认是0
  // param.pitch_rate = 100
  // 语速,范围是-500~500,默认是0
  // param.speech_rate = 100
  // 设置返回音频的编码格式
  // param.format = "wav"
  // 设置返回音频的采样率
  // param.sample_rate = 16000
  // 是否开启字级别时间戳
  // param.enable_subtitle = true
  try {
    await tts.start(param, true, 6000)
  } catch(error) {
    console.log("error on start:", error)
    return
  } finally {
    //dumpFile.end()
  }
  console.log("synthesis done")
  await sleep(2000)
}

async function test() {
  console.log("load test case:", args[0])
  const fileStream = fs.createReadStream(args[0])
  const rl = readline.createInterface({
    input: fileStream,
    crlfDelay: Infinity
  })

  for await (const line of rl) {
    b1.push(line)
  }

  while (true) {
    for (let text of b1) {
      await runOnce(text)
    }
  }
}

test()