收藏本站,收获最前沿的人工智能与编程资讯!!

Spring AI 使用文本转语音(TTS)API

技术文档 12℃ 0

Spring AI 通过 TextToSpeechModel 和 StreamingTextToSpeechModel 接口为文本转语音(TTS)提供了统一的 API。这让你可以编写可在不同 TTS 服务提供商之间通用的可移植代码。

支持的服务提供商

OpenAI 语音合成 API

Eleven Labs 文本转语音 API

通用接口

所有 TTS 服务提供商均实现以下共享接口:

TextToSpeechModel

TextToSpeechModel 接口提供了文本转语音的转换方法:

public interface TextToSpeechModel extends Model, StreamingTextToSpeechModel {

    /**
     * 使用默认配置将文本转换为语音
     */
    default byte[] call(String text) {
        // 默认实现
    }

    /**
     * 使用自定义配置将文本转换为语音
     */
    TextToSpeechResponse call(TextToSpeechPrompt prompt);

    /**
     * 获取该模型的默认配置项
     */
    default TextToSpeechOptions getDefaultOptions() {
        // 默认实现
    }
}

StreamingTextToSpeechModel

StreamingTextToSpeechModel 接口提供了实时音频流传输的方法:

@FunctionalInterface
public interface StreamingTextToSpeechModel extends StreamingModel{

    /**
     * 流式传输带元数据的文本转语音响应
     */
    Fluxstream(TextToSpeechPrompt prompt);

    /**
     * 为指定文本流式传输音频字节数据
     */
    default Fluxstream(String text) {
        // 默认实现
    }
}

TextToSpeechPrompt

TextToSpeechPrompt 类封装了输入文本和配置项:

TextToSpeechPrompt prompt = new TextToSpeechPrompt(
    "Hello, this is a text-to-speech example.",
    options
);

TextToSpeechResponse

TextToSpeechResponse 类包含生成的音频和元数据:

TextToSpeechResponse response = model.call(prompt);
byte[] audioBytes = response.getResult().getOutput();
TextToSpeechResponseMetadata metadata = response.getMetadata();

编写服务提供商无关的代码

共享 TTS 接口的核心优势之一是能够编写无需修改即可适配任意 TTS 服务提供商的代码。实际使用的提供商(OpenAI、ElevenLabs 等)由 Spring Boot 配置决定,你无需更改应用代码即可切换提供商。

基础服务示例

通过共享接口可编写适配任意 TTS 服务提供商的代码:

@Service
public class NarrationService {

    private final TextToSpeechModel textToSpeechModel;

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

    public byte[] narrate(String text) {
        // 适配所有 TTS 服务提供商
        return textToSpeechModel.call(text);
    }

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

该服务可无缝适配 OpenAI、ElevenLabs 或其他任意 TTS 服务提供商,具体实现由 Spring Boot 配置决定。

进阶示例:多服务提供商支持

你可以构建同时支持多个 TTS 服务提供商的应用:

@Service
public class MultiProviderNarrationService {

    private final Mapproviders;

    public MultiProviderNarrationService(Listmodels) {
        // Spring 会自动注入所有可用的 TextToSpeechModel Bean
        this.providers = models.stream()
            .collect(Collectors.toMap(
                model -> model.getClass().getSimpleName(),
                model -> model
            ));
    }

    public byte[] narrateWithProvider(String text, String providerName) {
        TextToSpeechModel model = providers.get(providerName);
        if (model == null) {
            throw new IllegalArgumentException("Unknown provider: " + providerName);
        }
        return model.call(text);
    }

    public SetgetAvailableProviders() {
        return providers.keySet();
    }
}

音频流示例

共享接口同样支持实时音频生成的流式传输:

@Service
public class StreamingNarrationService {

    private final TextToSpeechModel textToSpeechModel;

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

    public FluxstreamNarration(String text) {
        // TextToSpeechModel 继承自 StreamingTextToSpeechModel
        return textToSpeechModel.stream(text);
    }

    public FluxstreamWithMetadata(String text, TextToSpeechOptions options) {
        TextToSpeechPrompt prompt = new TextToSpeechPrompt(text, options);
        return textToSpeechModel.stream(prompt);
    }
}

REST 控制器示例

基于服务提供商无关的 TTS 构建 REST API:

@RestController
@RequestMapping("/api/tts")
public class TextToSpeechController {

    private final TextToSpeechModel textToSpeechModel;

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

    @PostMapping(value = "/synthesize", produces = "audio/mpeg")
    public ResponseEntitysynthesize(@RequestBody SynthesisRequest request) {
        byte[] audio = textToSpeechModel.call(request.text());
        return ResponseEntity.ok()
            .contentType(MediaType.parseMediaType("audio/mpeg"))
            .header("Content-Disposition", "attachment; filename=\"speech.mp3\"")
            .body(audio);
    }

    @GetMapping(value = "/stream", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
    public FluxstreamSynthesis(@RequestParam String text) {
        return textToSpeechModel.stream(text);
    }

    record SynthesisRequest(String text) {}
}

基于配置的服务提供商选择

通过 Spring 配置文件或属性切换服务提供商:

# application-openai.yml
spring:
  ai:
    model:
      audio:
        speech: openai
    openai:
      api-key: ${OPENAI_API_KEY}
      audio:
        speech:
          options:
            model: gpt-4o-mini-tts
            voice: alloy

# application-elevenlabs.yml
spring:
  ai:
    model:
      audio:
        speech: elevenlabs
    elevenlabs:
      api-key: ${ELEVENLABS_API_KEY}
      tts:
        options:
          model-id: eleven_turbo_v2_5
          voice-id: your_voice_id

随后激活目标服务提供商:

# 使用 OpenAI
java -jar app.jar --spring.profiles.active=openai

# 使用 ElevenLabs
java -jar app.jar --spring.profiles.active=elevenlabs

使用可移植配置项

为实现最大可移植性,仅使用通用的 TextToSpeechOptions 接口方法:

@Service
public class PortableNarrationService {

    private final TextToSpeechModel textToSpeechModel;

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

    public byte[] createPortableNarration(String text) {
        // 使用服务提供商的默认配置以实现最大可移植性
        TextToSpeechOptions defaultOptions = textToSpeechModel.getDefaultOptions();
        TextToSpeechPrompt prompt = new TextToSpeechPrompt(text, defaultOptions);
        TextToSpeechResponse response = textToSpeechModel.call(prompt);
        return response.getResult().getOutput();
    }
}

使用服务提供商专属功能

当需要使用服务提供商专属功能时,可在保持代码可移植性的前提下实现:

@Service
public class FlexibleNarrationService {

    private final TextToSpeechModel textToSpeechModel;

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

    public byte[] narrate(String text, TextToSpeechOptions baseOptions) {
        TextToSpeechOptions options = baseOptions;

        // 若可用,应用服务提供商专属优化
        if (textToSpeechModel instanceof OpenAiAudioSpeechModel) {
            options = OpenAiAudioSpeechOptions.builder()
                .from(baseOptions)
                .model("gpt-4o-tts")  // OpenAI 专属:使用高质量模型
                .speed(1.0)
                .build();
        } else if (textToSpeechModel instanceof ElevenLabsTextToSpeechModel) {
            // 可在此处配置 ElevenLabs 专属选项
        }

        TextToSpeechPrompt prompt = new TextToSpeechPrompt(text, options);
        TextToSpeechResponse response = textToSpeechModel.call(prompt);
        return response.getResult().getOutput();
    }
}

可移植代码的最佳实践

依赖接口:始终注入 TextToSpeechModel,而非具体实现类

使用通用配置项:遵循 TextToSpeechOptions 接口方法以实现最大可移植性

优雅处理元数据:不同服务提供商返回的元数据不同,采用通用方式处理

多服务提供商测试:确保代码至少适配两种 TTS 服务提供商

记录服务提供商相关假设:若依赖特定服务提供商的行为,需清晰记录

服务提供商专属功能

共享接口提供了可移植性,同时每个服务提供商也通过专属配置项类(如 OpenAiAudioSpeechOptions、ElevenLabsSpeechOptions)提供专属功能。这些类实现了 TextToSpeechOptions 接口,并额外扩展了服务提供商专属能力。

相关推荐