本文目录导读:

实现一个完整的语音助手涉及语音识别(ASR)、自然语言理解(NLU)、业务逻辑处理、语音合成(TTS) 四个核心环节,在 Java 中,你可以从调用云端 API(快速、准确)或使用本地离线库(延迟低、隐私好)两个方向入手。
下面提供一个基于 百度语音 API(云端)+ 本地命令匹配 的完整入门案例,包含语音录制、识别和动作执行。
整体架构概览
flowchart TD
A[用户说话] --> B[录音(Java AudioSystem)]
B --> C[调用云端API<br>(百度/阿里/讯飞)]
C --> D[返回文本]
D --> E[命令解析<br>(关键词/正则匹配)]
E --> F{匹配到动作?}
F -->|是| G[执行动作<br>(打开网页/控制硬件)]
F -->|否| H[回复“不懂”]
G --> I[语音合成<br>调用TTS API]
H --> I
I --> J[播放语音<br>Java Clip]
环境准备
Maven 依赖(pom.xml):
<dependencies>
<!-- 百度语音识别/合成 SDK -->
<dependency>
<groupId>com.baidu.aip</groupId>
<artifactId>java-sdk</artifactId>
<version>4.16.19</version>
</dependency>
<!-- JSON 解析 -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
</dependencies>
获取百度 API Key:
- 登录 百度AI开放平台
- 创建“语音识别”应用,获取
AppID、API Key、Secret Key。
核心代码实现
1 录音工具类(AudioRecorder.java)
import javax.sound.sampled.*;
import java.io.*;
public class AudioRecorder {
private static final float SAMPLE_RATE = 16000f; // 百度推荐 16kHz
private static final int SAMPLE_SIZE = 16;
private static final int CHANNELS = 1;
private static final int AUDIO_FORMAT = AudioFormat.Encoding.PCM_SIGNED;
// 录音并保存为WAV文件
public static File record(int durationSec) throws Exception {
AudioFormat format = new AudioFormat(SAMPLE_RATE, SAMPLE_SIZE, CHANNELS, true, false);
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
TargetDataLine line = (TargetDataLine) AudioSystem.getLine(info);
line.open(format);
line.start();
System.out.println("🎤 开始录音(" + durationSec + "秒)...");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int totalRead = 0;
long endTime = System.currentTimeMillis() + durationSec * 1000;
while (System.currentTimeMillis() < endTime) {
int bytesRead = line.read(buffer, 0, buffer.length);
baos.write(buffer, 0, bytesRead);
}
line.stop();
line.close();
System.out.println("✅ 录音结束");
// 写入WAV文件(需要添加WAV头)
return writeWavFile(baos.toByteArray(), format);
}
private static File writeWavFile(byte[] audioData, AudioFormat format) throws IOException {
File tempFile = File.createTempFile("voice_", ".wav");
try (AudioInputStream ais = new AudioInputStream(
new ByteArrayInputStream(audioData),
format,
audioData.length / format.getFrameSize())) {
AudioSystem.write(ais, AudioFileFormat.Type.WAVE, tempFile);
}
return tempFile;
}
}
2 语音识别服务(BaiduSpeechService.java)
import com.baidu.aip.speech.AipSpeech;
import com.baidu.aip.speech.AipSpeechClient;
import org.json.JSONObject;
public class BaiduSpeechService {
private AipSpeech client;
public BaiduSpeechService(String appId, String apiKey, String secretKey) {
client = new AipSpeech(appId, apiKey, secretKey);
// 设置连接超时等参数(可选)
client.setConnectionTimeoutInMillis(5000);
}
// 语音文件转文本
public String recognize(File audioFile) {
// 识别本地文件,中文普通话,采样率16000
JSONObject result = client.asr(audioFile.getAbsolutePath(), "wav", 16000, null);
if (result.getInt("err_no") == 0) {
// 成功,取第一条结果
String text = result.getJSONArray("result").getString(0);
System.out.println("🤖 识别结果:" + text);
return text;
} else {
System.err.println("❌ 识别失败:" + result.toString());
return null;
}
}
}
3 命令解析与执行(CommandHandler.java)
import java.awt.*;
import java.net.URI;
public class CommandHandler {
public static void execute(String commandText) {
if (commandText == null) return;
String cmd = commandText.toLowerCase();
// 简单的关键词匹配
if (cmd.contains("天气") || cmd.contains("今天天气")) {
say("今天天气晴朗,气温25度"); // 实际可调用天气API
} else if (cmd.contains("打开百度") || cmd.contains("百度")) {
openWeb("https://www.baidu.com");
say("已打开百度");
} else if (cmd.contains("时间") || cmd.contains("几点了")) {
String time = new java.text.SimpleDateFormat("HH点mm分").format(new java.util.Date());
say("现在时间是" + time);
} else if (cmd.contains("关灯") || cmd.contains("照明")) {
// 可调用串口/网络控制硬件
System.out.println("💡 执行关灯指令(需硬件支持)");
say("已为您关灯");
} else {
say("抱歉,我没有理解这个指令");
}
}
private static void openWeb(String url) {
try {
Desktop.getDesktop().browse(new URI(url));
} catch (Exception e) {
e.printStackTrace();
}
}
// 语音合成(简化:调用百度TTS)
public static void say(String text) {
System.out.println("🔊 回复:" + text);
// 实际可调用 TTS 接口(百度/阿里)生成语音并播放
// 调用 processVoice(text) 播放
}
}
4 主程序入口(VoiceAssistant.java)
public class VoiceAssistant {
public static void main(String[] args) throws Exception {
// 1. 初始化百度语音客户端
BaiduSpeechService speechService = new BaiduSpeechService(
"你的AppID", "你的APIKey", "你的SecretKey"
);
System.out.println("🤖 语音助手启动!说“退出”结束");
while (true) {
// 2. 录音5秒
File audioFile = AudioRecorder.record(5);
// 3. 语音识别
String text = speechService.recognize(audioFile);
// 4. 检查退出指令
if (text != null && text.contains("退出")) {
CommandHandler.say("再见");
break;
}
// 5. 执行命令
CommandHandler.execute(text);
}
// 清理临时文件(可选)
audioFile.deleteOnExit();
}
}
运行与测试
- 替换百度 API 凭证。
- 运行
main()方法。 - 对着麦克风说:“打开百度”、“现在几点了?”、或者“退出”。
- 程序会录音 → 识别 → 执行操作 → 语音回复(当前为文字模拟)。
进阶优化方向(生产级)
| 优化方向 | 具体做法 |
|---|---|
| 连续对话 | 使用 TargetDataLine 实时流式识别(百度 asr 支持流式) |
| 离线识别 | 集成 Vosk(Java 绑定)或 PocketSphinx(准确率稍低) |
| 自然语言理解 | 接入 Rasa/Dialogflow 或使用 LLM(如 OpenAI API)解析意图 |
| 多轮对话 | 维护 ConversationState 上下文对象 |
| 硬件控制 | 通过串口(jSerialComm)控制 Arduino/ESP32 |
| 语音合成 | 百度 TTS / 阿里 Sambert / 本地 FreeTTS |
| 唤醒词 | 集成 Porcupine(Java 版)实现“小度小度”类似唤醒 |
| 日志与错误处理 | 增加录音失败、网络超时等重试机制 |
离线方案示例(Vosk)
如果你希望完全离线,可以使用 Vosk:
<dependency>
<groupId>com.alphacephei</groupId>
<artifactId>vosk</artifactId>
<version>0.3.45</version>
</dependency>
核心代码片段:
import org.vosk.*;
Recognizer recognizer = new Recognizer(model, 16000);
InputStream ais = AudioSystem.getAudioInputStream(new File("test.wav"));
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = ais.read(buffer)) >= 0) {
if (recognizer.acceptWaveForm(buffer, bytesRead)) {
String result = recognizer.getResult();
// 从 JSON 中提取文本
}
}
- 最快启动:百度/阿里云 API(5行代码实现识别,准确率>95%)。
- 完全离线:Vosk + 本地命令匹配(适合小词表场景)。
- 扩展性:建议将语音识别、NLU、业务逻辑解耦为微服务。
上面的案例已经构成了一个可运行的最小闭环,你可以在此基础上替换具体业务逻辑,例如控制智能家居、查询数据库、操作文件等。