其实调用第三方接口完成一个智能语音系统是非常简单的,像阿里、科大讯飞、微软都有相关接口,直接根据官方文档集成就可以,但想要离线的就要麻烦一点了,主要是想不花钱,现在人工智能基本是python的天下,不得不感慨,再不学python感觉自己要被淘汰了。
言归正传,首先说一下标题中的ASR+LLM+TTS,ASR就是语音识别,LLM就是大语言模型,TTS就是文字转语音,要想把这几个功能做好对电脑性能要求还是蛮高的,本次方案是一个新的尝试也是减少对性能的消耗
1.先看效果
生成的音频效果放百度网盘 通过网盘分享的文件:result.wav 链接: pan.baidu.com/s/19ImtqunH… 提取码: hm67 听完之后是不是感觉效果很好,但是。。。后面再说吧
2.如何做
2.1ASR功能
添加依赖
xml
代码解读
复制代码
<!-- 获取音频信息 --> <dependency> <groupId>org</groupId> <artifactId>jaudiotagger</artifactId> <version>2.0.3</version> </dependency> <!-- 语音识别 --> <dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna</artifactId> <version>5.7.0</version> </dependency> <dependency> <groupId>com.alphacephei</groupId> <artifactId>vosk</artifactId> <version>0.3.32</version> </dependency>
代码实现,需要提前下载模型,去vosk官网下载:VOSK Models (alphacephei.com)中文模型一个大的一个小的,小的识别速度快准确率低,大的识别速度慢准确率高
提前预加载模型,提升识别速度
整理了一份好像面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题
需要全套面试笔记【点击此处即可】免费获取
java
代码解读
复制代码
private static final Model model = loadModel(); private static Model loadModel() { try { String path=System.getProperty("user.dir"); return new Model(path+"\vosk-model-small-cn-0.22"); } catch (Exception e) { throw new RuntimeException("Failed to load model", e); } }
语音转文字方法实现
ini
代码解读
复制代码
public String voiceToText(String filePath) { File file = new File(filePath); LibVosk.setLogLevel(LogLevel.DEBUG); String msg = null; int sampleRate = 0; RandomAccessFile rdf = null; /** * "r": 以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException。 * "rw": 打开以便读取和写入。 * "rws": 打开以便读取和写入。相对于 "rw","rws" 还要求对“文件的内容”或“元数据”的每个更新都同步写入到基础存储设备。 * "rwd" : 打开以便读取和写入,相对于 "rw","rwd" 还要求对“文件的内容”的每个更新都同步写入到基础存储设备。 */ try { rdf = new RandomAccessFile(file, "r"); sampleRate=toInt(read(rdf)); System.out.println(file.getName() + " SampleRate:" + sampleRate); // 采样率、音频采样级别 8000 = 8KHz rdf.close(); } catch (FileNotFoundException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } try ( InputStream ais = AudioSystem.getAudioInputStream(file); Recognizer recognizer = new Recognizer(model, 16000)) { int bytes; byte[] b = new byte[1024]; while ((bytes = ais.read(b)) >= 0) { recognizer.acceptWaveForm(b, bytes); } String result=recognizer.getResult(); JSONObject jsonObject = JSONObject.parseObject(result); msg=jsonObject.getString("text"); } catch (UnsupportedAudioFileException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } return msg; }
2.2LLM问答功能
这个就要请出神奇的羊驼ollama(链接:Ollama),下载即用非常简单,可以运行大部分主流大语言模型,在官网models选择要加载的模型在控制台运行对应的命令即可
添加依赖
xml
代码解读
复制代码
<dependency> <groupId>io.springboot.ai</groupId> <artifactId>spring-ai-ollama-spring-boot-starter</artifactId> <version>1.0.3</version> </dependency>
加入配置
yaml
代码解读
复制代码
spring: ai: ollama: base-url: http://10.3.0.178:11434 //接口地址 默认端口11434 chat: options: model: qwen2 //模型名称 enabled: true
代码实现,引入OllamaChatClient,然后调用call方法
ini
代码解读
复制代码
@Resource private OllamaChatClient ollamaChatClient; //msg为提问的信息 String ask=ollamaChatClient.call(msg);
2.3TTS功能
添加依赖
xml
代码解读
复制代码
<dependency> <groupId>com.hynnet</groupId> <artifactId>jacob</artifactId> <version>1.18</version> </dependency>
代码实现
java
代码解读
复制代码
public boolean localTextToSpeech(String text, int volume, int speed,String outPath) { try { // 调用dll朗读方法 ActiveXComponent ax = new ActiveXComponent("Sapi.SpVoice"); // 音量 0 - 100 ax.setProperty("Volume", new Variant(volume)); // 语音朗读速度 -10 到 +10 ax.setProperty("Rate", new Variant(speed)); // 输入的语言内容 Dispatch dispatch = ax.getObject(); // 本地执行朗读 // Dispatch.call(dispatch, "Speak", new Variant(text)); //开始生成语音文件,构建文件流 ax = new ActiveXComponent("Sapi.SpFileStream"); Dispatch sfFileStream = ax.getObject(); //设置文件生成格式 ax = new ActiveXComponent("Sapi.SpAudioFormat"); Dispatch fileFormat = ax.getObject(); // 设置音频流格式 Dispatch.put(fileFormat, "Type", new Variant(22)); // 设置文件输出流格式 Dispatch.putRef(sfFileStream, "Format", fileFormat); // 调用输出文件流打开方法,创建一个音频文件 Dispatch.call(sfFileStream, "Open", new Variant(outPath), new Variant(3), new Variant(true)); // 设置声音对应输出流为输出文件对象 Dispatch.putRef(dispatch, "AudioOutputStream", sfFileStream); // 设置音量 Dispatch.put(dispatch, "Volume", new Variant(volume)); // 设置速度 Dispatch.put(dispatch, "Rate", new Variant(speed)); // 执行朗读 Dispatch.call(dispatch, "Speak", new Variant(text)); // 关闭输出文件 Dispatch.call(sfFileStream, "Close"); Dispatch.putRef(dispatch, "AudioOutputStream", null); // 关闭资源 sfFileStream.safeRelease(); fileFormat.safeRelease(); // 关闭朗读的操作 dispatch.safeRelease(); ax.safeRelease(); return true; } catch (Exception e) { e.printStackTrace(); return false; } }
到此为止功能就全部实现了,在不联网的情况下也可以免费使用,但这个TTS生成出来的语音太机器了,所以在上面的示例中我说但是,因为机器音实在太难受了,所以用了另一个方案,但这个方案需要联网,暂时看是不需要收费 ,这个大家就看原作者介绍吧(ikfly/java-tts: java-tts 文本转语音 (github.com))
最终实现效果来看还是能接受的吧,整个过程速度还比较快,python的语音相关项目也看了很多,如果部署一个python的TTS服务,效果可能还会好点,但是我试过的速度都有点慢啊,还是容我再继续研究一下吧