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

オーディオ音声モデルを有効にする

開く

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)のいずれかになります。

合金

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();

リアルタイムオーディオのストリーミング

Speech 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!");

移行ガイド

非推奨の SpeechModel および SpeechPrompt クラスからアップグレードする場合、このガイドには、新しい共有インターフェースに移行するための詳細な手順が記載されています。

重大な変更の概要

この移行には、次の重大な変更が含まれます。

  1. 削除されたクラス org.springframework.ai.openai.audio.speech パッケージから 6 つの非推奨クラスが削除されました

  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: 速度パラメーターの更新 (フロート→ ダブル)

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.properties ファイルまたは application.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'

ソリューション : 依存性注入を更新して、SpeechModel ではなく TextToSpeechModel を使用します。

サンプルコード