本文介绍如何使用阿里云智能语音服务提供的Go SDK,包括SDK的安装方法及SDK代码示例。
前提条件
在使用SDK前,请先阅读接口说明,详情请参见接口说明。
下载安装
SDK支持Go 1.16及以上版本。
请确认已经安装Golang环境,并完成基本配置。
下载并安装SDK。
通过以下命令完成SDK下载和安装。
go get github.com/aliyun/alibabacloud-nls-go-sdk
导入SDK。
在代码中通过添加以下字段导入SDK。
import ("github.com/aliyun/alibabacloud-nls-go-sdk")
SDK常量
常量 | 含义 |
SDK_VERSION | SDK版本。 |
PCM | PCM音频格式。 |
WAV | WAV音频格式。 |
OPUS | OPUS音频格式。 |
OPU | OPU音频格式。 |
DEFAULT_DISTRIBUTE | 获取Token时使用的默认区域,默认为"cn-shanghai"。 |
DEFAULT_DOMAIN | 获取Token时使用的默认URL,默认为"nls-meta.cn-shanghai.aliyuncs.com"。 |
DEFAULT_VERSION | 获取Token时使用的协议版本,默认为"2019-02-28"。 |
DEFAULT_URL | 默认公有云URL,默认为"wss://nls-gateway-cn-shanghai.aliyuncs.com/ws/v1"。 |
建立连接
使用Akid和Akkey来获取Token时,建议针对Token进行缓存,并根据获取Token时获得的过期时间参数进行及时更新;请勿频繁调用获取Token的接口,否则会造成云端限流。
1.ConnectionConfig
用于建立连接的基础参数。
参数说明:
参数 | 类型 | 参数说明 |
Url | String | 访问的公共云URL,如果不确定,可以使用常量DEFAULT_URL。 |
Token | String | 访问Token,详情可参见获取Token概述。 |
Akid | String | 阿里云账号AccessKey ID。
|
Akkey | String | 阿里云账号AccessKey Secret。
|
Appkey | String | 对应项目Appkey。获取Appkey请前往控制台。 |
2.func NewConnectionConfigWithToken(url string, appkey string, token string) *ConnectionConfig
通过URL、Appkey和Token创建连接参数。
参数说明:
参数 | 类型 | 参数说明 |
Url | String | 访问的公共云URL,如果不确定,可以使用常量DEFAULT_URL。 |
Appkey | String | 对应项目Appkey。获取Appkey请前往控制台。 |
Token | String | 访问Token,详情可参见获取Token概述。 |
返回值:
*ConnectionConfig:连接配置对象指针。
3. func NewConnectionConfigFromJson(jsonStr string) (*ConnectionConfig, error)
通过JSON字符串来创建连接参数。
参数说明:
参数 | 类型 | 参数说明 |
jsonStr | String | 描述连接参数的JSON字符串,有效字段如下:url,token,akid,akkey,appkey。其中必须包含url和appkey,如果包含Token则不需要包含akid和akkey。 |
返回值:
*ConnectionConfig:连接配置对象指针。
实时语音识别
1. SpeechTranscriptionStartParam
实时语音识别参数。
参数 | 类型 | 参数说明 |
Format | String | 音频格式,默认值:PCM。取值为OPUS、OPU和PCM,如果是OPUS或OPU时,您需要自行编码。 |
SampleRate | Integer | 采样率,默认值:16000 Hz。 |
EnableIntermediateResult | Boolean | 是否打开中间结果返回。
|
EnablePunctuationPrediction | Boolean | 是否打开标点预测。
|
EnableInverseTextNormalization | Boolean | ITN(逆文本inverse text normalization)中文数字转换阿拉伯数字。设置为True时,中文数字将转为阿拉伯数字输出,默认值:False。 |
MaxSentenceSilence | Integer | 语音断句检测阈值。静音时长超过该阈值会被认为断句,合法参数范围200~2000毫秒,默认值800毫秒。 |
enable_words | Boolean | 是否开启返回词信息。默认不开启。
|
2. func DefaultSpeechTranscriptionParam() SpeechTranscriptionStartParam
创建一个默认参数。
参数说明:无。
返回值:
SpeechTranscriptionStartParam:默认参数。
3. func NewSpeechTranscription(...) (*SpeechTranscription, error)
创建一个实时语音识别对象。
参数说明:
参数 | 类型 | 参数说明 |
config | *ConnectionConfig | 参见建立连接相关内容。 |
logger | *NlsLogger | 参见SDK日志相关内容。 |
taskfailed | func(string, interface{}) | 识别过程中的错误处理回调参数,interface{}为用户自定义参数。 |
started | func(string, interface{}) | 建连完成回调参数。 |
sentencebegin | func(string, interface{}) | 一句话开始。 |
sentenceend | func(string, interface{}) | 一句话结束。 |
resultchanged | func(string, interface{}) | 识别中间结果回调参数。 |
completed | func(string, interface{}) | 最终识别结果回调参数。 |
closed | func(interface{}) | 连接断开回调参数。 |
param | interface{} | 用户自定义参数。 |
返回值:
*SpeechRecognition:识别对象指针。
error:错误异常。
4. func (st *SpeechTranscription) Start(param SpeechTranscriptionStartParam, extra map[string]interface{}) (chan bool, error)
开始实时语音识别。
参数说明:
参数 | 类型 | 参数说明 |
param | SpeechTranscriptionStartParam | 实时语音识别参数。 |
extra | map[string]interface{} | 额外 |
返回值:
chan bool:同步start完成的管道。
error:错误异常。
5. func (st *SpeechTranscription) Stop() (chan bool, error)
停止实时语音识别。
参数说明:无。
返回值:
chan bool:同步stop完成的管道。
error:错误异常。
6. func (st *SpeechTranscription) Ctrl(param map[string]interface{}) error
发送控制命令,可先查看接口说明。
参数说明:无。
参数
类型
参数说明
param
map[string]interface{}
自定义控制命令,该字典内容会以
key:value
形式合并进请求的payload段中。返回值:
error:错误异常。
7. func (st *SpeechTranscription) Shutdown()
强制停止实时语音识别。
参数说明:无。
返回值:无。
8. func (sr *SpeechTranscription) SendAudioData(data []byte) error
发送音频,音频格式必须和参数中一致。
参数说明:
参数 | 类型 | 参数说明 |
data | []byte | 音频数据。 |
返回值:
error:错误异常。
SDK日志
1.func DefaultNlsLog() *NlsLogger
用于创建全局唯一的默认日志对象,默认日志以NLS为前缀,输出到标准错误。
参数说明:无。
返回值:
NlsLogger:日志对象指针。
2.func NewNlsLogger(w io.Writer, tag string, flag int) *NlsLogger
创建一个新的日志。
参数说明:
参数 | 类型 | 参数说明 |
w | io.Writer | 任意实现io.Writer接口的对象。 |
tag | String | 日志前缀,会打印到日志行首部。 |
flag | Integer | 日志flag,具体请参见Go官方log文档。 |
返回值:
NlsLogger:日志对象指针。
3.func (logger *NlsLogger) SetLogSil(sil bool)
设置日志是否输出到对应的io.Writer。
参数说明:
参数 | 类型 | 参数说明 |
sil | Boolean | 是否禁止日志输出。
|
返回值:无。
4.func (logger *NlsLogger) SetDebug(debug bool)
设置是否打印Debug日志,仅影响通过Debugf或Debugln进行输出的日志。
参数说明:
参数 | 类型 | 参数说明 |
debug | Boolean | 是否允许Debug日志输出。
|
返回值:无。
5. func (logger *NlsLogger) SetOutput(w io.Writer)
设置日志输出方式。
参数说明:
参数 | 类型 | 参数说明 |
w | io.Writer | 任意实现io.Writer接口的对象。 |
返回值:无。
6. func (logger *NlsLogger) SetPrefix(prefix string)
设置日志行的标签。
参数说明:
参数 | 类型 | 参数说明 |
prefix | String | 日志行标签,会输出在日志行行首。 |
返回值:无。
7. func (logger *NlsLogger) SetFlags(flags int)
设置日志属性。
参数说明:
参数 | 类型 | 参数说明 |
flags | Integer | 日志属性,具体请参见Go官方文档。 |
返回值:无。
8. 日志打印
日志打印方法:
方法名 | 方法说明 |
func (l *NlsLogger) Print(v ...interface{}) | 标准日志输出。 |
func (l *NlsLogger) Println(v ...interface{}) | 标注日志输出,行尾自动换行。 |
func (l *NlsLogger) Printf(format string, v ...interface{}) | 带Format的日志输出,Format方式见具体请参见Go官方文档。 |
func (l *NlsLogger) Debugln(v ...interface{}) | Debug信息日志输出,行尾自动换行。 |
func (l *NlsLogger) Debugf(format string, v ...interface{}) | 带Format的Debug信息日志输出。 |
func (l *NlsLogger) Fatal(v ...interface{}) | 致命错误日志输出,输出后自动进程退出。 |
func (l *NlsLogger) Fatalln(v ...interface{}) | 致命错误日志输出,行尾自动换行,输出后自动进程退出。 |
func (l *NlsLogger) Fatalf(format string, v ...interface{}) | 带Format的致命错误日志输出,输出后自动进程退出。 |
func (l *NlsLogger) Panic(v ...interface{}) | 致命错误日志输出,输出后自动进程退出并打印崩溃信息。 |
func (l *NlsLogger) Panicln(v ...interface{}) | 致命错误日志输出,行尾自动换行,输出后自动进程退出并打印崩溃信息。 |
func (l *NlsLogger) Panicf(format string, v ...interface{}) | 带Format的致命错误日志输出,输出后自动进程退出并打印崩溃信息。 |
代码示例
package main
import (
"errors"
"flag"
"fmt"
"log"
"os"
"os/signal"
"sync"
"time"
"github.com/aliyun/alibabacloud-nls-go-sdk"
)
const (
AKID = "Your AKID"
AKKEY = "Your AKKEY"
//online key
APPKEY = "Your APPKEY"
TOKEN = "Your TOKEN"
)
func onTaskFailed(text string, param interface{}) {
logger, ok := param.(*nls.NlsLogger)
if !ok {
log.Default().Fatal("invalid logger")
return
}
logger.Println("TaskFailed:", text)
}
func onStarted(text string, param interface{}) {
logger, ok := param.(*nls.NlsLogger)
if !ok {
log.Default().Fatal("invalid logger")
return
}
logger.Println("onStarted:", text)
}
func onSentenceBegin(text string, param interface{}) {
logger, ok := param.(*nls.NlsLogger)
if !ok {
log.Default().Fatal("invalid logger")
return
}
logger.Println("onSentenceBegin:", text)
}
func onSentenceEnd(text string, param interface{}) {
logger, ok := param.(*nls.NlsLogger)
if !ok {
log.Default().Fatal("invalid logger")
return
}
logger.Println("onSentenceEnd:", text)
}
func onResultChanged(text string, param interface{}) {
logger, ok := param.(*nls.NlsLogger)
if !ok {
log.Default().Fatal("invalid logger")
return
}
logger.Println("onResultChanged:", text)
}
func onCompleted(text string, param interface{}) {
logger, ok := param.(*nls.NlsLogger)
if !ok {
log.Default().Fatal("invalid logger")
return
}
logger.Println("onCompleted:", text)
}
func onClose(param interface{}) {
logger, ok := param.(*nls.NlsLogger)
if !ok {
log.Default().Fatal("invalid logger")
return
}
logger.Println("onClosed:")
}
func waitReady(ch chan bool, logger *nls.NlsLogger) error {
select {
case done := <-ch:
{
if !done {
logger.Println("Wait failed")
return errors.New("wait failed")
}
logger.Println("Wait done")
}
case <-time.After(20 * time.Second):
{
logger.Println("Wait timeout")
return errors.New("wait timeout")
}
}
return nil
}
var lk sync.Mutex
var fail = 0
var reqNum = 0
func testMultiInstance(num int) {
pcm, err := os.Open("tests/test1.pcm")
if err != nil {
log.Default().Fatalln(err)
}
buffers := nls.LoadPcmInChunk(pcm, 320)
param := nls.DefaultSpeechTranscriptionParam()
config, _ := nls.NewConnectionConfigWithAKInfoDefault(nls.DEFAULT_URL, APPKEY, AKID, AKKEY)
var wg sync.WaitGroup
for i := 0; i < num; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
strId := fmt.Sprintf("ID%d ", id)
logger := nls.NewNlsLogger(os.Stderr, strId, log.LstdFlags|log.Lmicroseconds)
logger.SetLogSil(false)
logger.SetDebug(true)
logger.Printf("Test Normal Case for SpeechRecognition:%s", strId)
st, err := nls.NewSpeechTranscription(config, logger,
onTaskFailed, onStarted,
onSentenceBegin, onSentenceEnd, onResultChanged,
onCompleted, onClose, logger)
if err != nil {
logger.Fatalln(err)
return
}
test_ex := make(map[string]interface{})
test_ex["test"] = "hello"
for {
lk.Lock()
reqNum++
lk.Unlock()
logger.Println("ST start")
ready, err := st.Start(param, test_ex)
if err != nil {
lk.Lock()
fail++
lk.Unlock()
st.Shutdown()
continue
}
err = waitReady(ready, logger)
if err != nil {
lk.Lock()
fail++
lk.Unlock()
st.Shutdown()
continue
}
for _, data := range buffers.Data {
if data != nil {
st.SendAudioData(data.Data)
time.Sleep(10 * time.Millisecond)
}
}
logger.Println("send audio done")
ready, err = st.Stop()
if err != nil {
lk.Lock()
fail++
lk.Unlock()
st.Shutdown()
continue
}
err = waitReady(ready, logger)
if err != nil {
lk.Lock()
fail++
lk.Unlock()
st.Shutdown()
continue
}
logger.Println("Sr done")
st.Shutdown()
}
}(i)
}
wg.Wait()
}
func main() {
coroutineId := flag.Int("num", 1, "coroutine number")
flag.Parse()
log.Default().Printf("start %d coroutines", *coroutineId)
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
go func() {
for range c {
lk.Lock()
log.Printf(">>>>>>>>REQ NUM: %d>>>>>>>>>FAIL: %d", reqNum, fail)
lk.Unlock()
os.Exit(0)
}
}()
testMultiInstance(*coroutineId)
}