Spring AI 接入OpenAI实现文字转语音、语音转文字、翻译

AI-peach桃 2024-06-20 13:01:23 阅读 98

AI 大模型在文本、图片等领域非常强悍,人工智能在音频生成等领域也能大展拳脚。本篇文章主要介绍Spring AI 接入 OpenAI TTS大模型实现文字转语音和Whisper大模型实现语音转换文字功能。

由于本人对于TTS、Whisper大模型理解不够深入,这里就不对其实现原理进行讲解,只对Spring AI的使用进行演示。

OpenAI tts(Text-to-Speech) 模型

Text-to-Speech(TTS,文本生成语音,或者称之为语音合成)。

它可以做哪些事?

可以帮助你完成一篇文章的阅读。可以帮助你制作多种语言的视频。可以帮助你使用流媒体提供实时音频输出。

Spring AI 源码分析

Spring AI 提供对 OpenAI 语音 API 的支持。并抽取公共 SpeechModel 接口和 StreamingSpeechModel 接口,可以实现后续其它tts大模型的快速扩展和集成。

OpenAiAudioSpeechModel 类结构

classDiagramModel<|--SpeechModelStreamingModel <|-- StreamingSpeechModelSpeechModel <|.. OpenAiAudioSpeechModelStreamingSpeechModel <|.. OpenAiAudioSpeechModelOpenAiAudioSpeechModel ..> OpenAiAudioApiOpenAiAudioSpeechModel ..> OpenAiAudioSpeechOptionsclass SpeechModel { default byte[] call(String message) + SpeechResponse call(SpeechPrompt request)}class StreamingSpeechModel { default Flux<byte[]> stream(String message) +Flux<SpeechResponse> stream(SpeechPrompt request)}class OpenAiAudioApi { - restClient - webClient}class OpenAiAudioSpeechOptions { - model - input - voice - response_format - speed}

OpenAiAudioApi源码

public class OpenAiAudioApi { // RestClient 普通的Http调用客户端,同步调用 private final RestClient restClient; // webClient 响应式编程调用客户端,流式调用 private final WebClient webClient; // ------------------------------ 构造方法 ------------------------------------- public OpenAiAudioApi(String openAiToken) { this("https://api.openai.com", openAiToken, RestClient.builder(), WebClient.builder(), RetryUtils.DEFAULT_RESPONSE_ERROR_HANDLER); } public OpenAiAudioApi(String baseUrl, String openAiToken, RestClient.Builder restClientBuilder, ResponseErrorHandler responseErrorHandler) { this.restClient = restClientBuilder.baseUrl(baseUrl).defaultHeaders((headers) -> { headers.setBearerAuth(openAiToken); }).defaultStatusHandler(responseErrorHandler).build(); this.webClient = WebClient.builder().baseUrl(baseUrl).defaultHeaders((headers) -> { headers.setBearerAuth(openAiToken); }).defaultHeaders(ApiUtils.getJsonContentHeaders(openAiToken)).build(); } public OpenAiAudioApi(String baseUrl, String openAiToken, RestClient.Builder restClientBuilder, WebClient.Builder webClientBuilder, ResponseErrorHandler responseErrorHandler) { this.restClient = restClientBuilder.baseUrl(baseUrl).defaultHeaders((headers) -> { headers.setBearerAuth(openAiToken); }).defaultStatusHandler(responseErrorHandler).build(); this.webClient = webClientBuilder.baseUrl(baseUrl).defaultHeaders((headers) -> { headers.setBearerAuth(openAiToken); }).defaultHeaders(ApiUtils.getJsonContentHeaders(openAiToken)).build(); } // ------------------------------ 构造方法 ------------------------------------- // 调用api,将文本转为音频,同步方式 public ResponseEntity<byte[]> createSpeech(SpeechRequest requestBody) { return ((RestClient.RequestBodySpec)this.restClient.post().uri("/v1/audio/speech", new Object[0])).body(requestBody).retrieve().toEntity(byte[].class); } // 调用api,将文本转为音频, 流式方式 public Flux<ResponseEntity<byte[]>> stream(SpeechRequest requestBody) { return ((WebClient.RequestBodySpec)this.webClient.post().uri("/v1/audio/speech", new Object[0])).body(Mono.just(requestBody), SpeechRequest.class).accept(new MediaType[]{MediaType.APPLICATION_OCTET_STREAM}).exchangeToFlux((clientResponse) -> { HttpHeaders headers = clientResponse.headers().asHttpHeaders(); return clientResponse.bodyToFlux(byte[].class).map((bytes) -> { return ((ResponseEntity.BodyBuilder)ResponseEntity.ok().headers(headers)).body(bytes); }); }); } // 调用api,将语音转文本 public ResponseEntity<?> createTranscription(TranscriptionRequest requestBody) { return this.createTranscription(requestBody, requestBody.responseFormat().getResponseType()); } // 调用api,将语音转文本 public <T> ResponseEntity<T> createTranscription(TranscriptionRequest requestBody, Class<T> responseType) { MultiValueMap<String, Object> multipartBody = new LinkedMultiValueMap(); multipartBody.add("file", new ByteArrayResource(requestBody.file()) { public String getFilename() { return "audio.webm"; } }); multipartBody.add("model", requestBody.model()); multipartBody.add("language", requestBody.language()); multipartBody.add("prompt", requestBody.prompt()); multipartBody.add("response_format", requestBody.responseFormat().getValue()); multipartBody.add("temperature", requestBody.temperature()); if (requestBody.granularityType() != null) { Assert.isTrue(requestBody.responseFormat() == OpenAiAudioApi.TranscriptResponseFormat.VERBOSE_JSON, "response_format must be set to verbose_json to use timestamp granularities."); multipartBody.add("timestamp_granularities[]", requestBody.granularityType().getValue()); } return ((RestClient.RequestBodySpec)this.restClient.post().uri("/v1/audio/transcriptions", new Object[0])).body(multipartBody).retrieve().toEntity(responseType); } public ResponseEntity<?> createTranslation(TranslationRequest requestBody) { return this.createTranslation(requestBody, requestBody.responseFormat().getResponseType()); } // // 调用api,将语音翻译 public <T> ResponseEntity<T> createTranslation(TranslationRequest requestBody, Class<T> responseType) { MultiValueMap<String, Object> multipartBody = new LinkedMultiValueMap(); multipartBody.add("file", new ByteArrayResource(requestBody.file()) { public String getFilename() { return "audio.webm"; } }); multipartBody.add("model", requestBody.model()); multipartBody.add("prompt", requestBody.prompt()); multipartBody.add("response_format", requestBody.responseFormat().getValue()); multipartBody.add("temperature", requestBody.temperature()); return ((RestClient.RequestBodySpec)this.restClient.post().uri("/v1/audio/translations", new Object[0])).body(multipartBody).retrieve().toEntity(responseType); }}

OpenAiAudioApi实现了语音转文字、文字转语音、翻译功能,由于代码太长,只保留了方法。在OpenAiAudioApi中还有有请求参数、返回参数的定义,模型的控制参数定义等等。如果在使用时,不知道用哪个值,可以在该类中查找。

tts模型属性

参数与OpenAiAudioSpeechOptions类对应。为更好的使用我们先来了解下控制大模型的一些参数;

属性名 作用 默认值
spring.ai.openai.audio.speech.options.model 要使用的模型的 ID。目前只有 tts-1 tts-1
spring.ai.openai.audio.speech.options.voice 输出的语音,比如男音/女音。可用选项包括:alloy, echo, fable, onyx, nova, shimmer alloy
spring.ai.openai.audio.speech.options.response-format 音频输出的格式。支持的格式包括 mp3、opus、aac、flac、wav 和 pcm mp3
spring.ai.openai.audio.speech.options.speed 语音合成的速度。范围从 0.0(最慢)到 1.0(最快) 1.0

示例(文本转语音)

package org.ivy.controller;import org.springframework.ai.openai.OpenAiAudioSpeechModel;import org.springframework.ai.openai.OpenAiAudioSpeechOptions;import org.springframework.ai.openai.api.OpenAiAudioApi;import org.springframework.ai.openai.audio.speech.SpeechPrompt;import org.springframework.ai.openai.audio.speech.SpeechResponse;import org.springframework.http.MediaType;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.RestController;import reactor.core.publisher.Flux;@RestControllerpublic class AudioController { private final OpenAiAudioSpeechModel openAiAudioSpeechModel; public AudioController(OpenAiAudioSpeechModel openAiAudioSpeechModel) { this.openAiAudioSpeechModel = openAiAudioSpeechModel; } // 同步方式文本生成语音 @GetMapping(value = "tts", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public byte[] speech(@RequestParam(defaultValue = "Hello, this is a text-to-speech example.") String text) { OpenAiAudioSpeechOptions speechOptions = OpenAiAudioSpeechOptions.builder() .withModel("tts-1") // 指定模型, 目前Spring AI支持一种tts-1,可以不配置 .withVoice(OpenAiAudioApi.SpeechRequest.Voice.ALLOY) // 指定生成的音色 .withResponseFormat(OpenAiAudioApi.SpeechRequest.AudioResponseFormat.MP3) // 指定生成音频的格式 .withSpeed(1.0f) // 指定生成速度 .build(); SpeechPrompt speechPrompt = new SpeechPrompt(text, speechOptions); SpeechResponse response = openAiAudioSpeechModel.call(speechPrompt); return response.getResult().getOutput(); // 返回语音byte数组 } // 流式方式文本生成语音 @GetMapping(value = "stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux<byte[]> stream(@RequestParam(defaultValue = "Today is a wonderful day to build something people love!") String text) { OpenAiAudioSpeechOptions speechOptions = OpenAiAudioSpeechOptions.builder() .withResponseFormat(OpenAiAudioApi.SpeechRequest.AudioResponseFormat.MP3) .build(); SpeechPrompt speechPrompt = new SpeechPrompt(text, speechOptions); Flux<SpeechResponse> stream = openAiAudioSpeechModel.stream(speechPrompt); return stream.map(speechResponse -> speechResponse.getResult().getOutput()).flatMapSequential(Flux::just); }}

实现了同步和流式实现文本转语音功能

Postman测试

image.png

将请求返回的二进制数组,通过Postman保存为本地的mp3文件即可听到效果。另外大家自己可以做一个页面,将返回的二进制音频通过播放器的库进行播放,就可以实现一个简单的文本播报功能的网站了,我将打算在我的示例代码中实现,提交到Github上,大家可以参考学习。

Whisper 模型

Whisper 是一种通用的语音识别模型。它是在包含各种音频的大型数据集上训练的,也是一个多任务模型,可以执行多语言语音识别、语音翻译和语言识别。

Whisper 基于编码器-解码器(encoder-decoder)结构的Transformer模型,也称为序列_到序列_模型。这是一种在自然语言处理和语音识别领域广泛使用的深度学习架构。

它可以做什么?

语音转文本,支持99种语言,无论用哪种语言录制的,都能转换为文本。比如:生成视频字幕语音识别。比如:语音助手功能语音翻译。比如:识别的文本从原始语言翻译为其它语言,跨语言交流工具

关于Whisper大模型的其它细节,训练数据、模型架构等等大家自行研究,本文还是主要分析 Spring AI 框架支持接入Whisper模型的源码分析以及实践。

Spring AI 实现源码

Spring AI 为 OpenAI 的转录 API 提供支持。当实现其他转录提供程序时,将提取一个通用 AudioTranscriptionModel 接口。

OpenAiAudioTranscriptionModel 类结构

classDiagramModel <|.. OpenAiAudioTranscriptionModelOpenAiAudioTranscriptionModel ..> OpenAiAudioApiOpenAiAudioTranscriptionModel ..> OpenAiAudioTranscriptionOptionsOpenAiAudioTranscriptionModelclass Model { TRes call(TReq request);}class OpenAiAudioTranscriptionModel { - OpenAiAudioTranscriptionOptions defaultOptions - OpenAiAudioApi audioApi + AudioTranscriptionResponse call(AudioTranscriptionPrompt request)}

OpenAiAudioTranscriptionModel主要负责请求/返回的封装、处理、调用、重试。而audioApi真正调用OpenAI。具体源码在tts已分析,设计OpenAiAudioTranscriptionModelOpenAiAudioSpeechModel 共用 OpenAiAudioApi

Whisper 模型属性

属性 作用 默认值
spring.ai.openai.audio.transcription.options.model 要使用的模型的 ID。目前只有 whisper-1(由我们的开源 Whisper V2 模型提供支持)可用。 whisper-1
spring.ai.openai.audio.transcription.options.response-format 输出的格式,位于以下选项之一中:json、text、srt、verbose_json 或 vtt。 json
spring.ai.openai.audio.transcription.options.prompt An optional text to guide the model’s style or continue a previous audio segment. The prompt should match the audio language. 用于指导模型样式或继续上一个音频片段的可选文本。提示应与音频语言匹配
spring.ai.openai.audio.transcription.options.language 输入音频的语言。以 ISO-639-1 格式提供输入语言将提高准确性和延迟
spring.ai.openai.audio.transcription.options.temperature 采样温度,介于 0 和 1 之间。较高的值(如 0.8)将使输出更具随机性,而较低的值(如 0.2)将使其更加集中和确定。如果设置为 0,模型将使用对数概率自动提高温度,直到达到某些阈值 0
spring.ai.openai.audio.transcription.options.timestamp_granularities 要为此听录填充的时间戳粒度。必须verbose_json设置response_format才能使用时间戳粒度。支持以下任一或两个选项:word 或 segment。注意:分段时间戳没有额外的延迟,但生成字时间戳会产生额外的延迟 segment

示例 (语音转文本)

package org.ivy.controller;import org.springframework.ai.openai.OpenAiAudioTranscriptionModel;import org.springframework.ai.openai.OpenAiAudioTranscriptionOptions;import org.springframework.ai.openai.api.OpenAiAudioApi;import org.springframework.ai.openai.audio.transcription.AudioTranscriptionPrompt;import org.springframework.ai.openai.audio.transcription.AudioTranscriptionResponse;import org.springframework.beans.factory.annotation.Value;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;@RestControllerpublic class TranscriptionController { @Value("classpath:audio.mp3") private org.springframework.core.io.Resource audioResource; private final OpenAiAudioTranscriptionModel openAiTranscriptionModel; public TranscriptionController(OpenAiAudioTranscriptionModel openAiTranscriptionModel) { this.openAiTranscriptionModel = openAiTranscriptionModel; } @GetMapping("audio2Text") public String audio2Text() { var transcriptionOptions = OpenAiAudioTranscriptionOptions.builder() .withResponseFormat(OpenAiAudioApi.TranscriptResponseFormat.TEXT) .withTemperature(0f) .build(); AudioTranscriptionPrompt transcriptionRequest = new AudioTranscriptionPrompt(audioResource, transcriptionOptions); AudioTranscriptionResponse response = openAiTranscriptionModel.call(transcriptionRequest); return response.getResult().getOutput(); }}

将上一小节生成的mp3文件进行反向转换为文本。 由于token限额原因,暂时无法测试,大家可运行代码自行测试下效果。

总结

本篇文章根据官方文章对配置参数进行简单的说明,并提供了简单的实现示例。并未对tts、whisper模型的实现原理进行说明,待个人对这部分知识补齐之后在做补充。

如何系统的去学习大模型LLM ?

作为一名热心肠的互联网老兵,我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。

但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的 AI大模型资料 包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来

😝有需要的小伙伴,可以V扫描下方二维码免费领取🆓

一、全套AGI大模型学习路线

AI大模型时代的学习之旅:从基础到前沿,掌握人工智能的核心技能!

img

二、640套AI大模型报告合集

这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。

img

三、AI大模型经典PDF籍

随着人工智能技术的飞速发展,AI大模型已经成为了当今科技领域的一大热点。这些大型预训练模型,如GPT-3、BERT、XLNet等,以其强大的语言理解和生成能力,正在改变我们对人工智能的认识。 那以下这些PDF籍就是非常不错的学习资源。

img

在这里插入图片描述

四、AI大模型商业化落地方案

img

阶段1:AI大模型时代的基础理解

目标:了解AI大模型的基本概念、发展历程和核心原理。内容: L1.1 人工智能简述与大模型起源L1.2 大模型与通用人工智能L1.3 GPT模型的发展历程L1.4 模型工程L1.4.1 知识大模型L1.4.2 生产大模型L1.4.3 模型工程方法论L1.4.4 模型工程实践L1.5 GPT应用案例

阶段2:AI大模型API应用开发工程

目标:掌握AI大模型API的使用和开发,以及相关的编程技能。内容: L2.1 API接口L2.1.1 OpenAI API接口L2.1.2 Python接口接入L2.1.3 BOT工具类框架L2.1.4 代码示例L2.2 Prompt框架L2.2.1 什么是PromptL2.2.2 Prompt框架应用现状L2.2.3 基于GPTAS的Prompt框架L2.2.4 Prompt框架与ThoughtL2.2.5 Prompt框架与提示词L2.3 流水线工程L2.3.1 流水线工程的概念L2.3.2 流水线工程的优点L2.3.3 流水线工程的应用L2.4 总结与展望

阶段3:AI大模型应用架构实践

目标:深入理解AI大模型的应用架构,并能够进行私有化部署。内容: L3.1 Agent模型框架L3.1.1 Agent模型框架的设计理念L3.1.2 Agent模型框架的核心组件L3.1.3 Agent模型框架的实现细节L3.2 MetaGPTL3.2.1 MetaGPT的基本概念L3.2.2 MetaGPT的工作原理L3.2.3 MetaGPT的应用场景L3.3 ChatGLML3.3.1 ChatGLM的特点L3.3.2 ChatGLM的开发环境L3.3.3 ChatGLM的使用示例L3.4 LLAMAL3.4.1 LLAMA的特点L3.4.2 LLAMA的开发环境L3.4.3 LLAMA的使用示例L3.5 其他大模型介绍

阶段4:AI大模型私有化部署

目标:掌握多种AI大模型的私有化部署,包括多模态和特定领域模型。内容: L4.1 模型私有化部署概述L4.2 模型私有化部署的关键技术L4.3 模型私有化部署的实施步骤L4.4 模型私有化部署的应用场景

学习计划:

阶段1:1-2个月,建立AI大模型的基础知识体系。阶段2:2-3个月,专注于API应用开发能力的提升。阶段3:3-4个月,深入实践AI大模型的应用架构和私有化部署。阶段4:4-5个月,专注于高级模型的应用和部署。
这份完整版的大模型 LLM 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

😝有需要的小伙伴,可以Vx扫描下方二维码免费领取🆓



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。