阿里云语音识别 Node.js 实践教程

这篇教程会带着大家过一遍如何用 Node.js 调用阿里云的语音识别服务,识别一个本地的音频文件。我会分享一个很方便的脚本,它可以自动搞定临时访问令牌(Token)的获取,然后通过 WebSocket 把音频流传过去做识别。

准备工作

在动手之前,得确保电脑上装了这几个东西:

  1. Node.js: 推荐用 LTS 稳定版。
  2. npm: 装 Node.js 的时候一般会自动装上。

另外,我们还需要一个阿里云账号,并做下面几件事:

  1. 开通语音识别服务: 登录阿里云后台,找到“智能语音交互”服务把它开通。
  2. 创建项目拿 AppKey: 在智能语音交互控制台新建一个项目,拿到它的 AppKey
  3. 获取 AccessKey: 去访问控制(RAM)控制台创建一个 AccessKey,记下 AccessKeyIdAccessKeySecret。这俩密钥很重要,得收好,别给别人看到。

操作步骤

第一步:安装依赖

万事开头第一步,先把项目要用到的包装上。在终端里进到项目目录,跑一下这个命令:

1
npm install

这个命令会装上 alibabacloud-nls(语音服务的SDK)和 @alicloud/pop-core(用来调用阿里云API拿Token)。

第二步:创建 index.js 文件

在项目根目录建一个 index.js 文件,然后把下面的代码贴进去。这是整个识别功能的核心代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
const fs = require('fs');
const path = require('path');
const NLS = require('alibabacloud-nls');
const Core = require('@alicloud/pop-core');

// --- 配置 ---
// 脚本会从环境变量读取凭证,确保你已经按下一步设置好了
const ACCESS_KEY_ID = process.env.ALICLOUD_ACCESS_KEY_ID;
const ACCESS_KEY_SECRET = process.env.ALICLOUD_ACCESS_KEY_SECRET;
const APP_KEY = process.env.NLS_APPKEY;

if (!ACCESS_KEY_ID || !ACCESS_KEY_SECRET || !APP_KEY) {
console.error('错误: 请设置 ALICLOUD_ACCESS_KEY_ID, ALICLOUD_ACCESS_KEY_SECRET 和 NLS_APPKEY 环境变量。');
process.exit(1);
}

// 默认识别 'hello.amr',也可以从命令行参数传文件名
const audioFilePath = process.argv[2] || path.join(__dirname, 'hello.amr');
if (!fs.existsSync(audioFilePath)) {
console.error(`错误: 音频文件没找到: ${audioFilePath}`);
process.exit(1);
}

/**
* 用 @alicloud/pop-core 获取临时的 NLS token
*/
async function fetchNlsToken() {
const client = new Core({
accessKeyId: ACCESS_KEY_ID,
accessKeySecret: ACCESS_KEY_SECRET,
endpoint: 'https://nls-meta.cn-shanghai.aliyuncs.com',
apiVersion: '2019-02-28',
});

const params = {
Domain: 'nls-gateway.cn-shanghai.aliyuncs.com',
Action: 'CreateToken',
};

const requestOption = {
method: 'POST'
};

try {
console.log('正在获取 NLS token...');
const response = await client.request('CreateToken', params, requestOption);
if (response.Token && response.Token.Id) {
console.log('Token 获取成功!');
return response.Token.Id;
} else {
throw new Error(`获取Token失败,响应: ${JSON.stringify(response)}`);
}
} catch (error) {
console.error('获取 NLS token 失败:', error);
throw error;
}
}

/**
* 主识别函数
*/
async function main() {
try {
const token = await fetchNlsToken();
const url = 'wss://nls-gateway.cn-shanghai.aliyuncs.com/ws/v1';

const sr = new NLS.SpeechRecognition({
url: url,
appkey: APP_KEY,
token: token
});

// 设置事件监听
sr.on('started', (msg) => {
console.log('识别开始:', msg);
});

sr.on('failed', (msg) => {
console.error('识别失败:', msg);
});

sr.on('completed', (msg) => {
console.log('识别完成,最终结果:');
try {
const result = JSON.parse(msg);
if (result && result.payload && result.payload.result) {
console.log(result.payload.result);
} else {
console.log(msg);
}
} catch (e) {
console.log(msg);
}
});

sr.on('closed', () => {
console.log('连接关闭');
});

// 开始识别
const startParams = sr.defaultStartParams();
// 根据文件格式设置
const fileExtension = path.extname(audioFilePath).toLowerCase();
if (fileExtension === '.wav') {
startParams.format = 'wav';
startParams.sample_rate = 16000;
} else if (fileExtension === '.pcm') {
startParams.format = 'pcm';
startParams.sample_rate = 16000;
} else {
startParams.format = 'amr';
startParams.sample_rate = 8000;
}
startParams.enable_punctuation_prediction = true;
startParams.enable_inverse_text_normalization = true;

await sr.start(startParams, true, 6000);
console.log('已发送开始请求,准备发送音频...');

// 发送音频流
const audioStream = fs.createReadStream(audioFilePath);
audioStream.on('data', (chunk) => {
sr.sendAudio(chunk);
});

// 音频流结束时,发送结束指令
audioStream.on('end', async () => {
console.log('音频文件发送完毕,正在关闭连接...');
try {
await sr.close();
} catch (error) {
console.error('关闭连接时出错:', error);
}
});

} catch (error) {
console.error('发生错误:', error.message);
}
}

main();

第三步:配置环境变量

为了不把密钥写死在代码里(这是个好习惯),我们把它配置在环境变量里。脚本会自动去读。

打开 PowerShell 终端,执行下面的命令,记得把 '...' 里的内容换成你自己的信息:

1
2
3
4
5
6
7
8
# 设置你的阿里云 AccessKey ID
$env:ALICLOUD_ACCESS_KEY_ID = 'LTAI5t...换成你的...'

# 设置你的阿里云 AccessKey Secret
$env:ALICLOUD_ACCESS_KEY_SECRET = '...换成你的...'

# 设置你在语音服务控制台创建的项目的 AppKey
$env:NLS_APPKEY = '...换成你的...'

注意:

  • 每次关掉 PowerShell 窗口,这些变量就没了,需要重新设一次。
  • AccessKey 千万别泄露出去。

第四步:准备音频文件

项目里自带了一个 hello.amr 文件,可以直接用它来测试。

如果你想用自己的音频文件,可以:

  1. 把文件(比如 my_audio.wav)放到项目根目录。
  2. 运行脚本的时候,把文件名带上,具体看下一步。

提示:脚本会根据文件的后缀名(.amr, .wav, .pcm)来判断采样率,所以文件后缀名要写对。

第五步:运行识别脚本

OK,所有东西都准备好了。在刚刚设置好环境变量的终端里,敲下面的命令开始识别:

1
2
# 识别默认的 hello.amr 文件
node index.js

如果要识别自己的文件,比如 my_audio.wav,就这样运行:

1
2
# 识别指定的音频文件
node index.js my_audio.wav

第六步:查看结果

脚本跑起来后,终端会显示类似下面的日志:

1
2
3
4
5
6
7
8
正在获取 NLS token...
Token 获取成功!
已发送开始请求,准备发送音频...
识别开始: ...
音频文件发送完毕,正在关闭连接...
识别完成,最终结果:
你好
连接关闭

这里的“你好”,就是从 hello.amr 文件里识别出来的文字。


好了,教程就到这里。现在你可以自己动手试试了。如果碰到什么问题,欢迎在评论区留言交流!