Java案例如何实现语音助手?

wen python案例 2

本文目录导读:

Java案例如何实现语音助手?

  1. 整体架构概览
  2. 环境准备
  3. 核心代码实现
  4. 运行与测试
  5. 进阶优化方向(生产级)
  6. 离线方案示例(Vosk)

实现一个完整的语音助手涉及语音识别(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

  1. 登录 百度AI开放平台
  2. 创建“语音识别”应用,获取 AppIDAPI KeySecret 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();
    }
}

运行与测试

  1. 替换百度 API 凭证。
  2. 运行 main() 方法。
  3. 对着麦克风说:“打开百度”、“现在几点了?”、或者“退出”。
  4. 程序会录音 → 识别 → 执行操作 → 语音回复(当前为文字模拟)。

进阶优化方向(生产级)

优化方向 具体做法
连续对话 使用 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、业务逻辑解耦为微服务。

上面的案例已经构成了一个可运行的最小闭环,你可以在此基础上替换具体业务逻辑,例如控制智能家居、查询数据库、操作文件等。

抱歉,评论功能暂时关闭!