このバージョンはまだ開発中であり、まだ安定しているとは考えられていません。最新のスナップショットバージョンについては、Spring AI 1.1.2 を使用してください。

テキスト読み上げ (TTS) API

Spring AI は、TextToSpeechModel および StreamingTextToSpeechModel インターフェースを通じて、音声合成(TTS)用の統合 API を提供します。これにより、異なる TTS プロバイダー間で動作する移植性の高いコードを作成できます。

サポートされているプロバイダー

共通インターフェース

すべての TTS プロバイダーは、次の共有インターフェースを実装します。

TextToSpeechModel

TextToSpeechModel インターフェースは、テキストを音声に変換するためのメソッドを提供します。

public interface TextToSpeechModel extends Model<TextToSpeechPrompt, TextToSpeechResponse>, StreamingTextToSpeechModel {

    /**
     * Converts text to speech with default options.
     */
    default byte[] call(String text) {
        // Default implementation
    }

    /**
     * Converts text to speech with custom options.
     */
    TextToSpeechResponse call(TextToSpeechPrompt prompt);

    /**
     * Returns the default options for this model.
     */
    default TextToSpeechOptions getDefaultOptions() {
        // Default implementation
    }
}

StreamingTextToSpeechModel

StreamingTextToSpeechModel インターフェースは、リアルタイムでオーディオをストリーミングするためのメソッドを提供します。

@FunctionalInterface
public interface StreamingTextToSpeechModel extends StreamingModel<TextToSpeechPrompt, TextToSpeechResponse> {

    /**
     * Streams text-to-speech responses with metadata.
     */
    Flux<TextToSpeechResponse> stream(TextToSpeechPrompt prompt);

    /**
     * Streams audio bytes for the given text.
     */
    default Flux<byte[]> stream(String text) {
        // Default implementation
    }
}

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) {
        // Works with any TTS provider
        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 Map<String, TextToSpeechModel> providers;

    public MultiProviderNarrationService(List<TextToSpeechModel> models) {
        // Spring will inject all available TextToSpeechModel beans
        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 Set<String> getAvailableProviders() {
        return providers.keySet();
    }
}

ストリーミングオーディオの例

共有インターフェースは、リアルタイムオーディオ生成のためのストリーミングもサポートします。

@Service
public class StreamingNarrationService {

    private final TextToSpeechModel textToSpeechModel;

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

    public Flux<byte[]> streamNarration(String text) {
        // TextToSpeechModel extends StreamingTextToSpeechModel
        return textToSpeechModel.stream(text);
    }

    public Flux<TextToSpeechResponse> streamWithMetadata(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 ResponseEntity<byte[]> synthesize(@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 Flux<byte[]> streamSynthesis(@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

次に、希望するプロバイダーをアクティブ化します。

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

# Use 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) {
        // Use provider's default options for maximum portability
        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;

        // Apply provider-specific optimizations if available
        if (textToSpeechModel instanceof OpenAiAudioSpeechModel) {
            options = OpenAiAudioSpeechOptions.builder()
                .from(baseOptions)
                .model("gpt-4o-tts")  // OpenAI-specific: use high-quality model
                .speed(1.0)
                .build();
        } else if (textToSpeechModel instanceof ElevenLabsTextToSpeechModel) {
            // ElevenLabs-specific options could go here
        }

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

ポータブルコードのベストプラクティス

  1. Depend on Interfaces : 具体的な実装ではなく、常に TextToSpeechModel を注入する

  2. Use Common Options : 移植性を最大限に高めるには、TextToSpeechOptions インターフェース方式を採用する

  3. Handle Metadata Gracefully : プロバイダによって返されるメタデータは異なるため、汎用的に処理する

  4. Test with Multiple Providers : コードが少なくとも 2 つの TTS プロバイダーで動作することを確認する

  5. Document Provider Assumptions : 特定のプロバイダーの行動に依存する場合は、それを明確にドキュメント化します。

プロバイダー固有の機能

共通インターフェースは移植性を提供しますが、各プロバイダはプロバイダ固有のオプションクラス(例: OpenAiAudioSpeechOptionsElevenLabsSpeechOptions)を通じて独自の機能も提供します。これらのクラスは、プロバイダ固有の機能を追加しながら、TextToSpeechOptions インターフェースを実装します。