OpenAI 文本转语音 (TTS)

简介

音频 API 提供了一个基于 OpenAI TTS(文本转语音)模型的语音端点,使用户能够

  • 朗读一篇书面博客文章。

  • 生成多种语言的语音。

  • 使用流式传输提供实时音频输出。

先决条件

  1. 创建 OpenAI 账户并获取 API 密钥。您可以在 OpenAI 注册页面 注册,并在 API 密钥页面 生成 API 密钥。

  2. spring-ai-openai 依赖项添加到项目的构建文件中。有关更多信息,请参阅 依赖管理 部分。

自动配置

Spring AI 自动配置、启动模块的工件名称发生了重大变化。请参阅 升级说明 以获取更多信息。

Spring AI 为 OpenAI 文本转语音客户端提供 Spring Boot 自动配置。要启用它,请将以下依赖项添加到项目的 Maven pom.xml 文件中

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>

或添加到 Gradle build.gradle 构建文件中

dependencies {
    implementation 'org.springframework.ai:spring-ai-starter-model-openai'
}
请参阅依赖管理部分,将 Spring AI BOM 添加到您的构建文件中。

语音属性

连接属性

前缀 spring.ai.openai 用作属性前缀,允许您连接到 OpenAI。

财产

描述

默认值

spring.ai.openai.base-url

要连接的 URL

api.openai.com

spring.ai.openai.api-key

API 密钥

-

spring.ai.openai.organization-id

您可以选择指定用于 API 请求的组织。

-

spring.ai.openai.project-id

您可以选择指定用于 API 请求的项目。

-

对于属于多个组织(或通过其旧版用户 API 密钥访问其项目)的用户,您可以选择指定用于 API 请求的组织和项目。这些 API 请求的使用将计入指定组织和项目的使用量。

配置属性

音频语音自动配置的启用和禁用现在通过前缀为 spring.ai.model.audio.speech 的顶级属性进行配置。

要启用,请设置 spring.ai.model.audio.speech=openai(默认启用)

要禁用,请设置 spring.ai.model.audio.speech=none(或任何不匹配 openai 的值)

此更改是为了允许配置多个模型。

前缀 spring.ai.openai.audio.speech 用作属性前缀,允许您配置 OpenAI 文本转语音客户端。

财产 描述 默认值

spring.ai.model.audio.speech

启用音频语音模型

openai

spring.ai.openai.audio.speech.base-url

要连接的 URL

api.openai.com

spring.ai.openai.audio.speech.api-key

API 密钥

-

spring.ai.openai.audio.speech.organization-id

您可以选择指定用于 API 请求的组织。

-

spring.ai.openai.audio.speech.project-id

您可以选择指定用于 API 请求的项目。

-

spring.ai.openai.audio.speech.options.model

用于生成音频的模型 ID。可用模型:gpt-4o-mini-tts(默认,针对速度和成本优化)、gpt-4o-tts(更高质量)、tts-1(旧版,针对速度优化)或 tts-1-hd(旧版,针对质量优化)。

gpt-4o-mini-tts

spring.ai.openai.audio.speech.options.voice

用于合成的语音。对于 OpenAI 的 TTS API,所选模型可用的语音之一: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.25(最慢)到 4.0(最快)。

1.0

您可以覆盖常用的 spring.ai.openai.base-urlspring.ai.openai.api-keyspring.ai.openai.organization-idspring.ai.openai.project-id 属性。如果设置了 spring.ai.openai.audio.speech.base-urlspring.ai.openai.audio.speech.api-keyspring.ai.openai.audio.speech.organization-idspring.ai.openai.audio.speech.project-id 属性,则它们优先于常用属性。这对于您希望为不同的模型和不同的模型端点使用不同的 OpenAI 账户很有用。
所有前缀为 spring.ai.openai.audio.speech.options 的属性都可以在运行时被覆盖。

运行时选项

OpenAiAudioSpeechOptions 类提供了在进行文本转语音请求时使用的选项。启动时,使用 spring.ai.openai.audio.speech 指定的选项,但您可以在运行时覆盖这些选项。

OpenAiAudioSpeechOptions 类实现了 TextToSpeechOptions 接口,提供了可移植和 OpenAI 特定的配置选项。

例如:

OpenAiAudioSpeechOptions speechOptions = OpenAiAudioSpeechOptions.builder()
    .model("gpt-4o-mini-tts")
    .voice(OpenAiAudioApi.SpeechRequest.Voice.ALLOY)
    .responseFormat(OpenAiAudioApi.SpeechRequest.AudioResponseFormat.MP3)
    .speed(1.0)
    .build();

TextToSpeechPrompt speechPrompt = new TextToSpeechPrompt("Hello, this is a text-to-speech example.", speechOptions);
TextToSpeechResponse response = openAiAudioSpeechModel.call(speechPrompt);

手动配置

spring-ai-openai 依赖项添加到您的项目的 Maven pom.xml 文件中

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-openai</artifactId>
</dependency>

或添加到 Gradle build.gradle 构建文件中

dependencies {
    implementation 'org.springframework.ai:spring-ai-openai'
}
请参阅依赖管理部分,将 Spring AI BOM 添加到您的构建文件中。

接下来,创建一个 OpenAiAudioSpeechModel

var openAiAudioApi = new OpenAiAudioApi()
    .apiKey(System.getenv("OPENAI_API_KEY"))
    .build();

var openAiAudioSpeechModel = new OpenAiAudioSpeechModel(openAiAudioApi);

var speechOptions = OpenAiAudioSpeechOptions.builder()
    .responseFormat(OpenAiAudioApi.SpeechRequest.AudioResponseFormat.MP3)
    .speed(1.0)
    .model(OpenAiAudioApi.TtsModel.GPT_4_O_MINI_TTS.value)
    .build();

var speechPrompt = new TextToSpeechPrompt("Hello, this is a text-to-speech example.", speechOptions);
TextToSpeechResponse response = openAiAudioSpeechModel.call(speechPrompt);

// Accessing metadata (rate limit info)
OpenAiAudioSpeechResponseMetadata metadata = (OpenAiAudioSpeechResponseMetadata) response.getMetadata();

byte[] responseAsBytes = response.getResult().getOutput();

实时音频流

语音 API 支持使用分块传输编码进行实时音频流。这意味着在生成并可访问完整文件之前,音频就可以播放。

OpenAiAudioSpeechModel 实现了 StreamingTextToSpeechModel 接口,提供了标准和流式传输功能。

var openAiAudioApi = new OpenAiAudioApi()
    .apiKey(System.getenv("OPENAI_API_KEY"))
    .build();

var openAiAudioSpeechModel = new OpenAiAudioSpeechModel(openAiAudioApi);

OpenAiAudioSpeechOptions speechOptions = OpenAiAudioSpeechOptions.builder()
    .voice(OpenAiAudioApi.SpeechRequest.Voice.ALLOY)
    .speed(1.0)
    .responseFormat(OpenAiAudioApi.SpeechRequest.AudioResponseFormat.MP3)
    .model(OpenAiAudioApi.TtsModel.GPT_4_O_MINI_TTS.value)
    .build();

TextToSpeechPrompt speechPrompt = new TextToSpeechPrompt("Today is a wonderful day to build something people love!", speechOptions);

Flux<TextToSpeechResponse> responseStream = openAiAudioSpeechModel.stream(speechPrompt);

// You can also stream raw audio bytes directly
Flux<byte[]> audioByteStream = openAiAudioSpeechModel.stream("Hello, world!");

迁移指南

如果您正在从已弃用的 SpeechModelSpeechPrompt 类升级,本指南提供了迁移到新共享接口的详细说明。

重大变更摘要

此次迁移包括以下重大变更

  1. 已移除的类:已从 org.springframework.ai.openai.audio.speech 包中移除六个已弃用的类

  2. 包变更:核心 TTS 类已移至 org.springframework.ai.audio.tts

  3. 类型变更:所有 OpenAI TTS 组件中的 speed 参数已从 Float 更改为 Double

  4. 接口层次结构TextToSpeechModel 现在扩展了 StreamingTextToSpeechModel

类映射参考

已弃用(已移除) 新接口

SpeechModel

TextToSpeechModel

StreamingSpeechModel

StreamingTextToSpeechModel

SpeechPrompt

TextToSpeechPrompt

SpeechResponse

TextToSpeechResponse

SpeechMessage

TextToSpeechMessage

Speech (在 org.springframework.ai.openai.audio.speech 中)

Speech (在 org.springframework.ai.audio.tts 中)

分步迁移说明

第 1 步:更新导入

将所有从旧的 org.springframework.ai.openai.audio.speech 包导入的内容替换为新的共享接口

Find:    import org.springframework.ai.openai.audio.speech.SpeechModel;
Replace: import org.springframework.ai.audio.tts.TextToSpeechModel;

Find:    import org.springframework.ai.openai.audio.speech.StreamingSpeechModel;
Replace: import org.springframework.ai.audio.tts.StreamingTextToSpeechModel;

Find:    import org.springframework.ai.openai.audio.speech.SpeechPrompt;
Replace: import org.springframework.ai.audio.tts.TextToSpeechPrompt;

Find:    import org.springframework.ai.openai.audio.speech.SpeechResponse;
Replace: import org.springframework.ai.audio.tts.TextToSpeechResponse;

Find:    import org.springframework.ai.openai.audio.speech.SpeechMessage;
Replace: import org.springframework.ai.audio.tts.TextToSpeechMessage;

Find:    import org.springframework.ai.openai.audio.speech.Speech;
Replace: import org.springframework.ai.audio.tts.Speech;

第 2 步:更新类型引用

替换代码中所有类型引用

Find:    SpeechModel
Replace: TextToSpeechModel

Find:    StreamingSpeechModel
Replace: StreamingTextToSpeechModel

Find:    SpeechPrompt
Replace: TextToSpeechPrompt

Find:    SpeechResponse
Replace: TextToSpeechResponse

Find:    SpeechMessage
Replace: TextToSpeechMessage

第 3 步:更新速度参数 (Float → Double)

speed 参数已从 Float 更改为 Double。更新所有出现之处

Find:    .speed(1.0f)
Replace: .speed(1.0)

Find:    .speed(0.5f)
Replace: .speed(0.5)

Find:    Float speed
Replace: Double speed

如果您有序列化数据或配置文件包含 Float 值,您也需要更新它们

// Before
{
  "speed": 1.0
}

// After (no code change needed for JSON, but be aware of type change in Java)
{
  "speed": 1.0
}

第 4 步:更新 Bean 声明

如果您有 Spring Boot 自动配置或手动 Bean 定义

// Before
@Bean
public SpeechModel speechModel(OpenAiAudioApi audioApi) {
    return new OpenAiAudioSpeechModel(audioApi);
}

// After
@Bean
public TextToSpeechModel textToSpeechModel(OpenAiAudioApi audioApi) {
    return new OpenAiAudioSpeechModel(audioApi);
}

代码迁移示例

示例 1:基本的文本转语音转换

之前(已弃用)

import org.springframework.ai.openai.audio.speech.*;

@Service
public class OldNarrationService {

    private final SpeechModel speechModel;

    public OldNarrationService(SpeechModel speechModel) {
        this.speechModel = speechModel;
    }

    public byte[] createNarration(String text) {
        SpeechPrompt prompt = new SpeechPrompt(text);
        SpeechResponse response = speechModel.call(prompt);
        return response.getResult().getOutput();
    }
}

之后(使用共享接口)

import org.springframework.ai.audio.tts.*;
import org.springframework.ai.openai.OpenAiAudioSpeechModel;

@Service
public class NarrationService {

    private final TextToSpeechModel textToSpeechModel;

    public NarrationService(TextToSpeechModel textToSpeechModel) {
        this.textToSpeechModel = textToSpeechModel;
    }

    public byte[] createNarration(String text) {
        TextToSpeechPrompt prompt = new TextToSpeechPrompt(text);
        TextToSpeechResponse response = textToSpeechModel.call(prompt);
        return response.getResult().getOutput();
    }
}

示例 2:使用自定义选项进行文本转语音

之前(已弃用)

import org.springframework.ai.openai.audio.speech.*;
import org.springframework.ai.openai.api.OpenAiAudioApi;

SpeechModel model = new OpenAiAudioSpeechModel(audioApi);

OpenAiAudioSpeechOptions options = OpenAiAudioSpeechOptions.builder()
    .model("tts-1")
    .voice(OpenAiAudioApi.SpeechRequest.Voice.NOVA)
    .speed(1.0f)  // Float value
    .responseFormat(OpenAiAudioApi.SpeechRequest.AudioResponseFormat.MP3)
    .build();

SpeechPrompt prompt = new SpeechPrompt("Hello, world!", options);
SpeechResponse response = model.call(prompt);
byte[] audio = response.getResult().getOutput();

之后(使用共享接口)

import org.springframework.ai.audio.tts.*;
import org.springframework.ai.openai.OpenAiAudioSpeechModel;
import org.springframework.ai.openai.OpenAiAudioSpeechOptions;
import org.springframework.ai.openai.api.OpenAiAudioApi;

TextToSpeechModel model = new OpenAiAudioSpeechModel(audioApi);

OpenAiAudioSpeechOptions options = OpenAiAudioSpeechOptions.builder()
    .model("tts-1")
    .voice(OpenAiAudioApi.SpeechRequest.Voice.NOVA)
    .speed(1.0)  // Double value
    .responseFormat(OpenAiAudioApi.SpeechRequest.AudioResponseFormat.MP3)
    .build();

TextToSpeechPrompt prompt = new TextToSpeechPrompt("Hello, world!", options);
TextToSpeechResponse response = model.call(prompt);
byte[] audio = response.getResult().getOutput();

示例 3:流式文本转语音

之前(已弃用)

import org.springframework.ai.openai.audio.speech.*;
import reactor.core.publisher.Flux;

StreamingSpeechModel model = new OpenAiAudioSpeechModel(audioApi);
SpeechPrompt prompt = new SpeechPrompt("Stream this text");

Flux<SpeechResponse> stream = model.stream(prompt);
stream.subscribe(response -> {
    byte[] audioChunk = response.getResult().getOutput();
    // Process audio chunk
});

之后(使用共享接口)

import org.springframework.ai.audio.tts.*;
import org.springframework.ai.openai.OpenAiAudioSpeechModel;
import reactor.core.publisher.Flux;

TextToSpeechModel model = new OpenAiAudioSpeechModel(audioApi);
TextToSpeechPrompt prompt = new TextToSpeechPrompt("Stream this text");

Flux<TextToSpeechResponse> stream = model.stream(prompt);
stream.subscribe(response -> {
    byte[] audioChunk = response.getResult().getOutput();
    // Process audio chunk
});

示例 4:使用 Spring Boot 进行依赖注入

之前(已弃用)

@RestController
public class OldSpeechController {

    private final SpeechModel speechModel;

    @Autowired
    public OldSpeechController(SpeechModel speechModel) {
        this.speechModel = speechModel;
    }

    @PostMapping("/narrate")
    public ResponseEntity<byte[]> narrate(@RequestBody String text) {
        SpeechPrompt prompt = new SpeechPrompt(text);
        SpeechResponse response = speechModel.call(prompt);
        return ResponseEntity.ok()
            .contentType(MediaType.parseMediaType("audio/mpeg"))
            .body(response.getResult().getOutput());
    }
}

之后(使用共享接口)

@RestController
public class SpeechController {

    private final TextToSpeechModel textToSpeechModel;

    @Autowired
    public SpeechController(TextToSpeechModel textToSpeechModel) {
        this.textToSpeechModel = textToSpeechModel;
    }

    @PostMapping("/narrate")
    public ResponseEntity<byte[]> narrate(@RequestBody String text) {
        TextToSpeechPrompt prompt = new TextToSpeechPrompt(text);
        TextToSpeechResponse response = textToSpeechModel.call(prompt);
        return ResponseEntity.ok()
            .contentType(MediaType.parseMediaType("audio/mpeg"))
            .body(response.getResult().getOutput());
    }
}

Spring Boot 配置变更

Spring Boot 自动配置属性保持不变。您的 application.propertiesapplication.yml 文件无需更改。

但是,如果您有显式 Bean 引用或限定符,请更新它们

// Before
@Qualifier("speechModel")

// After
@Qualifier("textToSpeechModel")

迁移的优点

  • 可移植性:一次编写代码,轻松在 OpenAI、ElevenLabs 或其他 TTS 提供商之间切换

  • 一致性:与 ChatModel 和其他 Spring AI 抽象采用相同的模式

  • 类型安全:通过正确的接口实现改进类型层次结构

  • 面向未来:新的 TTS 提供商将自动与您现有代码兼容

  • 标准化:所有 TTS 提供商的速度参数均采用一致的 Double 类型

常见迁移问题及解决方案

问题 1:编译错误 - 找不到符号 SpeechModel

错误

error: cannot find symbol SpeechModel

解决方案: 按照第 1 步所述更新您的导入,将 SpeechModel 更改为 TextToSpeechModel

问题 2:类型不匹配 - Float 无法转换为 Double

错误

error: incompatible types: float cannot be converted to Double

解决方案: 从浮点文字中删除 f 后缀(例如,将 1.0f 更改为 1.0)。

问题 3:运行时 Bean 创建错误

错误

NoSuchBeanDefinitionException: No qualifying bean of type 'SpeechModel'

解决方案: 更新您的依赖注入以使用 TextToSpeechModel 而不是 SpeechModel

示例代码

© . This site is unofficial and not affiliated with VMware.