长春火车站照片安装wordpress 空白
一、AudioModel简介
1、AudioModel
当前,Spring AI Alibaba 支持以下两种通义语音模型的适配,分别是:
- 文本生成语音 SpeechModel,对应于 OpenAI 的 Text-To-Speech (TTS) API
- 录音文件生成文字 DashScopeAudioTranscriptionModel,对应于 OpenAI 的 Transcription API
二、AudioModel使用
Spring AI Alibaba对话模型(Chat Model):https://java2ai.com/docs/1.0.0-M5.1/tutorials/chat-model/
Spring AI Alibaba 支持Model 抽象与通义系列模型的适配,并通过 spring-ai-alibaba-starter AutoConfiguration 自动初始化了默认实例,因此我们可以在应用程序中直接注入 ChatModel、ImageModel 等 bean,当然在需要的时候也可以自定义 Model 实例。
1、文本生成语音
在普通 Controller Bean 中注入 SpeechSynthesisModel 实例,实现“文本生成语音”功能:
- 简单|流式调用
- 自定义 LLMs 参数调用
编写 Controller接口:
@Slf4j
@RestController
@RequestMapping("/dashscope/audio-tts")
public class TTSController {private static final String DEFAULT_TEXT = "你好!我是通义千问,阿里巴巴集团旗下的超大规模语言模型。";private final SpeechSynthesisModel speechSynthesisModel;/*** 使用如下的方式自动注入 SpeechSynthesisModel** @param speechSynthesisModel*/public TTSController(SpeechSynthesisModel speechSynthesisModel) {this.speechSynthesisModel = speechSynthesisModel;}/*** 简单调用*/@GetMapping("/simple/tts")public String simpleTTS(String userInputText) throws IOException {if (StringUtils.isBlank(userInputText)) {userInputText = DEFAULT_TEXT;}SpeechSynthesisResponse speechSynthesisResponse = speechSynthesisModel.call(new SpeechSynthesisPrompt(userInputText));ByteBuffer byteBuffer = speechSynthesisResponse.getResult().getOutput().getAudio();byte[] bytes = byteBuffer.array();// 保存到文件String outputFilePath = "D:\\TempFiles\\audio\\simple_tts_output.mp3";File file = new File(outputFilePath);try (FileOutputStream fos = new FileOutputStream(file)) {fos.write(bytes);} catch (IOException e) {log.error("调用 simpleTTS 保存到文件异常 --> userInputPrompt ={}, e", userInputText, e);throw new IOException(e.getMessage());}return "SUCCESS";}/*** 流式调用*/@GetMapping("/stream/tts")public String streamTTS(HttpServletResponse response, String userInputText) {if (StringUtils.isBlank(userInputText)) {userInputText = DEFAULT_TEXT;}// 指定参数DashScopeSpeechSynthesisOptions speechSynthesisOptions = DashScopeSpeechSynthesisOptions.builder().withModel("cosyvoice-v1").withResponseFormat(DashScopeSpeechSynthesisApi.ResponseFormat.MP3).withVoice("longhua")//.withSpeed(1.0) // 语速,取值范围:0.5~2.0,默认值为 1.0.build();Flux<SpeechSynthesisResponse> speechSynthesisResponseFlux = speechSynthesisModel.stream(new SpeechSynthesisPrompt(userInputText, speechSynthesisOptions));/*** 为什么使用 CountDownLatch?* 异步处理:Flux 是响应式编程的一部分,处理数据是异步的。这意味着数据的处理不会阻塞主线程。* 确保完成:CountDownLatch 用于等待所有异步操作完成。它允许主线程等待,直到所有数据处理完成后再继续执行*/// 创建一个 CountDownLatch,初始计数为 1。CountDownLatch latch = new CountDownLatch(1);String outputFilePath = "D:\\TempFiles\\audio\\stream_tts_output.mp3";File file = new File(outputFilePath);try (FileOutputStream fos = new FileOutputStream(file)) {// 订阅 Flux<SpeechSynthesisResponse>speechSynthesisResponseFlux.doFinally( // 在 Flux 所有数据处理完成后调用 countDown()signal -> latch.countDown()).subscribe(synthesisResponse -> {// 处理每个 SpeechSynthesisResponseByteBuffer byteBuffer = synthesisResponse.getResult().getOutput().getAudio();byte[] bytes = new byte[byteBuffer.remaining()];byteBuffer.get(bytes);try {fos.write(bytes);} catch (IOException e) {log.error("调用 streamTTS 将字节数据写入文件异常 --> e", e);throw new RuntimeException(e);}}, error -> { // 处理错误log.error(" streamTTS 调用异常 --> error", error);latch.countDown(); // 确保在发生错误时也减少计数器});//// 主线程在这里等待所有异步操作完成,直到 CountDownLatch 的计数变为 0,即所有 SpeechSynthesisResponse 处理完成。latch.await();} catch (IOException | InterruptedException e) {log.error("调用 streamTTS 保存到文件异常 --> userInputText ={}, e", userInputText, e);throw new RuntimeException(e);}return "SUCCESS";}
}
2、录音文件生成文字
在普通 Controller Bean 中注入 SpeechSynthesisModel 实例,实现“录音文件生成文字”功能:
- 简单|流式调用
- 自定义 LLMs 参数调用
注意:
不同模型对音频格式,采样率,实时|离线处理,时长控制,语言等音频文件的处理不同,针对音频文件选择正确的处理模型,否则会因为不符合模型的要求(如 WAV 格式传递给 PCM 模型)导致报错。
下面语音模型区别
- sensevoice-v1:
- 这是一个较早期的语音识别模型。
- 可能适用于特定场景或语言,但功能和性能可能不如后续版本强大。
- 对于一些复杂的音频文件(如高噪声、低质量录音),可能会出现识别错误。
- paraformer-realtime-v2:
- 这是一个实时语音转文字模型,支持流式处理。
- 适用于需要实时返回结果的场景(如直播字幕、实时会议记录)。
- 性能优化较好,能够快速响应并生成结果。
- paraformer-v2:
- 这是一个非实时的语音转文字模型,通常用于离线处理。
- 适合对较长音频文件进行高精度转写。
- 相比实时模型,可能需要更多的时间来处理音频。
编写 Controller接口:
@Slf4j
@RestController
@RequestMapping("/dashscope/audio-stt")
public class STTController {private static final String DEFAULT_MODEL_1 = "sensevoice-v1";private static final String DEFAULT_MODEL_2 = "paraformer-realtime-v2";private static final String DEFAULT_MODEL_3 = "paraformer-v2";private static final String AUDIO_RESOURCES_URL = "https://dashscope.oss-cn-beijing.aliyuncs.com/samples/audio/paraformer/hello_world_female2.wav";private final AudioTranscriptionModel transcriptionModel;/*** 使用如下的方式自动注入 AudioTranscriptionModel** @param transcriptionModel*/public STTController(AudioTranscriptionModel transcriptionModel) {this.transcriptionModel = transcriptionModel;}/*** 简单调用*/@GetMapping("/simple/stt")public String stt() throws MalformedURLException {// 音频资源UrlResource audioResource = new UrlResource(AUDIO_RESOURCES_URL);// 指定参数DashScopeAudioTranscriptionOptions transcriptionOptions = DashScopeAudioTranscriptionOptions.builder().withModel(DEFAULT_MODEL_1).build();AudioTranscriptionResponse response = transcriptionModel.call(new AudioTranscriptionPrompt(audioResource, transcriptionOptions));// <|Speech|>hello world,这里是阿里巴巴语音实验室。<|/Speech|><|NEUTRAL|>return response.getResult().getOutput();}/*** 流式调用** @return*/@GetMapping("/stream/stt")public String streamSTT() throws FileNotFoundException, MalformedURLException {CountDownLatch latch = new CountDownLatch(1);StringBuilder stringBuilder = new StringBuilder();// 音频资源String filePath = "D:\\TempFiles\\audio\\count.pcm";FileSystemResource audioResource = new FileSystemResource(new File(filePath));// 指定参数DashScopeAudioTranscriptionOptions transcriptionOptions = DashScopeAudioTranscriptionOptions.builder().withModel(DEFAULT_MODEL_2).withFormat(DashScopeAudioTranscriptionOptions.AudioFormat.PCM)// 设置音频采样率。16kHz/s是常见的语音处理采样率。.withSampleRate(16000)// 不启用话语不流畅移除功能。不流畅内容通常指说话中的停顿、重复等现象。.withDisfluencyRemovalEnabled(false).build();Flux<AudioTranscriptionResponse> response = transcriptionModel.stream(new AudioTranscriptionPrompt(audioResource, transcriptionOptions));// 订阅 Flux<AudioTranscriptionResponse>response.doFinally(signal -> latch.countDown()).subscribe(resp -> stringBuilder.append(resp.getResult().getOutput()));try {latch.await();} catch (InterruptedException e) {log.error("调用 streamSTT 异常 --> e", e);}return stringBuilder.toString();}}
简单调用成功,流式调用失败。
– 求知若饥,虚心若愚。