Skip to content

Repository files navigation

Irodori TTS API

Irodori-TTS-Optimiz を依存バックエンドにした RESTful 音声合成 APIサーバー

必要条件

  • Python 3.12+
  • NVIDIA GPU(Compute Capability 7.5以上推奨)
  • uv パッケージマネージャー
  • CMake 3.5+(sentencepieceビルド用)

セットアップ

git clone https://github.com/kuwacom/Irodori-TTS-API.git
cd Irodori-TTS-API

cp .env.example .env
# .env を編集(モデル・デバイス等)

uv sync

初回の uv sync では PyTorch CUDA版とIrodori-TTSモデル(約3GB)をダウンロードするため時間がかかります。

起動

uv run task start

開発モード(ホットリロード):

uv run task dev

コマンド一覧

uv run task <name> で実行できます。

コマンド 説明
start サーバー起動
dev 開発サーバー起動
test テスト実行
lint Ruff lintチェック
format Ruffフォーマット
fix Ruff自動修正
check lint + テスト

環境変数

.env ファイルで設定します。.env.example をコピーして編集してください。

アプリケーション

変数 デフォルト 説明
HOST 127.0.0.1 バインドアドレス
PORT 8000 ポート番号
RELOAD false ホットリロード(開発用)
LOG_LEVEL INFO ログレベル
CORS_POLICY_ORIGIN * CORS許可オリジン(カンマ区切り)

モデル

変数 デフォルト 説明
DEFAULT_MODEL Aratako/Irodori-TTS-v4.1-Small デフォルトのTTSモデル
CODEC_PRECISION fp32 コーデック精度(fp32 / bf16)。bf16 でVRAM使用量削減
COMPILE_MODEL false torch.compileによる推論高速化(初回コンパイル時間がかかる)
COMPILE_DYNAMIC false torch.compileの動的形状対応(入力サイズ変動に対応)
CODEC_REPO Aratako/Semantic-DACVAE-Japanese-32dim DACVAEコーデックリポジトリ
MODEL_DEVICE cuda モデル配置デバイス
CODEC_DEVICE cpu コーデック配置デバイス
MODEL_PRECISION fp32 モデル精度(fp32 / bf16
CUDA_VISIBLE_DEVICES (空) PyTorchが認識するGPUを制限

推論制御

変数 デフォルト 説明
MAX_PARALLELISM 1 GPU上の同時推論スロット数(1=直列、2以上=並列推論)。VRAM容量に応じて調整
ENABLE_WATERMARK false SilentCipherウォーターマーク(trueで有効化)
MAX_BATCH_SEGMENTS 8 長文分割推論で1バッチあたりに同時処理するセグメント最大数の上限。リクエスト側の maxBatchSegments はこの値を超えられない

VRAM容量と精度・並列度の目安

MAX_PARALLELISM はGPUのVRAM容量とMODEL_PRECISIONの組み合わせで調整が必要です。 以下は目安であり、実際のテキスト長や生成秒数によって変動します。

VRAM 精度 推奨 MAX_PARALLELISM
12GB fp32 1(並列は厳しい)
12GB bf16 2(ギリギリ)
24GB fp32 4〜5

ディレクトリ

変数 デフォルト 説明
MODELS_DIR models HuggingFace Hubキャッシュ
DATA_DIR data 話者データ

制限値

変数 デフォルト 説明
MAX_REF_SECONDS 30.0 参照音声の最大秒数
MAX_GENERATE_SECONDS 30.0 生成音声の最大秒数
MAX_NUM_CANDIDATES 4 候補数の上限
MAX_REQUEST_BODY_SIZE 33554432 リクエストボディ最大サイズ(バイト)

GPUに関する注意点

マルチGPU構成

モデルとコーデックを別々のGPUに配置できます。

MODEL_DEVICE=cuda:0
CODEC_DEVICE=cuda:1

非対応GPUの除外

Compute Capability 7.5未満のGPU(GTX 10xx等)が接続されている環境では、 cuDNNの初期化に失敗するため CUDA_VISIBLE_DEVICES でPyTorchの視界から除外する必要があります。

CUDA_VISIBLE_DEVICES=0
MODEL_DEVICE=cuda:0
CODEC_DEVICE=cuda:0

.env に書いた CUDA_VISIBLE_DEVICES は起動時にOS環境変数へ反映されるため、 PyTorchより前に確実に効きます。

CPU動作

GPUがない・非対応GPUのみの環境ではCPU動作も可能ですが、推論速度は大幅に低下します。

MODEL_DEVICE=cpu
CODEC_DEVICE=cpu

Docker

CPU版・GPU版のDockerイメージで簡単にコンテナ起動できます。

ファイル構成

docker/
  Dockerfile.cpu      -- CPU版(PyTorch CPU-only)
  Dockerfile.gpu      -- GPU版(CUDA 12.8 + cuDNN)
  .dockerignore
docker-compose.yml      -- GPU版(デフォルト)
docker-compose.cpu.yml  -- CPU版

イメージ

GHCRからプルしたイメージを優先して使用します。ローカルビルドは明示的な build コマンド時のみ行われます。

イメージ GHCR
GPU版 ghcr.io/kuwacom/irodori-tts-api:gpu
CPU版 ghcr.io/kuwacom/irodori-tts-api:cpu

タグはブランチ名・セマンティックバージョン・コミットSHAに基づいて自動付与されます:

タグ タイミング
{variant}-latest gpu, cpu mainプッシュ時
{variant}-{branch} gpu-main, cpu-main ブランチプッシュ時
{variant}-v1.0.0 gpu-v1.0.0, cpu-v1.0.0 タグプッシュ時
{variant}-sha-abc1234 gpu-sha-abc1234 全プッシュ時

起動

# GPU版(デフォルト)-- GHCRからpullして起動
docker compose up

# CPU版
docker compose -f docker-compose.cpu.yml up

GPU版は nvidia-container-toolkit が必要です。

ローカルビルド

GHCRイメージを使わずローカルでビルドする場合:

# GPU版
docker compose build gpu
docker compose up gpu --no-pull

# CPU版
docker compose -f docker-compose.cpu.yml build cpu
docker compose -f docker-compose.cpu.yml up cpu --no-pull

または docker build を直接:

# CPU版
docker build -f docker/Dockerfile.cpu -t irodori-tts-api:cpu .

# GPU版
docker build -f docker/Dockerfile.gpu -t irodori-tts-api:gpu .

ボリュームマウント

models/data/ はホストディレクトリをバインドマウントします。初回起動時はモデルがHuggingFace Hubから自動ダウンロードされます。

docker run --gpus all -p 8000:8000 \
  -v ./models:/app/models \
  -v ./data:/app/data \
  ghcr.io/kuwacom/irodori-tts-api:gpu

環境変数の優先順位

Docker Composeでは以下の優先順位で環境変数が決まります(上にあるほど強い):

優先度 ソース 備考
1 docker compose run -e VAR=val 実行時の -e が最強
2 environment: ブロック composeファイル内の静的定義
3 env_file: コンテナに渡されるファイル
4 Dockerfileの ENV イメージに焼き込まれた値

HOST / MODEL_DEVICE / CODEC_DEVICEenvironment: で強制されるため、.env の値より優先されます。これは意図的な設計です(HOST=0.0.0.0 はDockerで必須、デバイス設定はイメージ種別に固定すべきため)。

それ以外の変数(PORT, LOG_LEVEL, MAX_PARALLELISM 等)は .env の値がそのままコンテナに渡ります。

ヘルスチェック

コンテナには /openapi.json へのGETリクエストでヘルスチェックが設定されています。起動完了(モデルのDL・初期化)まで start_period: 120s の間隔があります。

# 手動確認
docker exec <container> python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/openapi.json')"

エンドポイント

話者管理

メソッド パス 説明
POST /v1/speakers 話者登録
GET /v1/speakers 話者一覧
GET /v1/speakers/{speakerId} 話者詳細
DELETE /v1/speakers/{speakerId} 話者削除

音声合成

メソッド パス 説明
POST /v1/synthesize 音声合成

ランタイム設定

メソッド パス 説明
GET /v1/runtime 現在のランタイム設定を取得
PATCH /v1/runtime 並列推論スロット数を動的変更

GET /v1/runtime

現在のランタイム設定を取得する。

レスポンス:

{
  "maxParallelism": 1,
  "maxParallelismLimit": 4
}

PATCH /v1/runtime

並列推論スロット数を動的に変更する。MAX_PARALLELISM 環境変数が上限値(maxParallelismLimit)として機能する。

リクエストボディ:

キー 説明
maxParallelism int 並列推論スロット数(1以上、MAX_PARALLELISM が上限)

レスポンス:

{
  "maxParallelism": 2,
  "maxParallelismLimit": 4
}

上限を超える値を指定した場合は 400 VALIDATION_ERROR を返す。


POST /v1/speakers

話者を登録する。音声ファイルからlatentを抽出し、以降の合成で参照できるようにする。

Content-Type: multipart/form-data

フィールド 必須 説明
audio file 音声ファイル(wav/mp3/flac)
metadata string(JSON) 話者メタデータ

metadata:

キー デフォルト 説明
name string "" 話者名
description string "" 説明
caption string/null null 合成時のデフォルトキャプション(スタイル指示)
maxRefSeconds number 30.0 参照音声の最大秒数
normalizeDb number -16.0 正規化目標 dB
ensureMax boolean true 正規化後にピーククリップ
curl -X POST http://localhost:8000/v1/speakers \
  -F "audio=@voice.wav" \
  -F 'metadata={"name":"female","description":"ナレーション向け"}'
{
  "speakerId": "a1b2c3d4-...",
  "name": "female",
  "status": "created",
  "sha256": "a6f2...",
  "createdAt": "2026-06-25T10:00:00Z"
}

同一音声・同一条件の話者が既に存在する場合は status: "already exists" で既存IDを返します。


GET /v1/speakers

登録済み話者の一覧を返す。

[
  {
    "speakerId": "a1b2c3d4-...",
    "name": "female",
    "createdAt": "2026-06-25T10:00:00Z",
    "lastUsedAt": null
  }
]

GET /v1/speakers/{speakerId}

話者の詳細情報を返す。

{
  "speakerId": "a1b2c3d4-...",
  "name": "female",
  "description": "ナレーション向け",
  "caption": null,
  "sha256": "a6f2...",
  "maxRefSeconds": 30.0,
  "normalizeDb": -16.0,
  "ensureMax": true,
  "codecRepo": "Aratako/Semantic-DACVAE-Japanese-32dim",
  "createdAt": "2026-06-25T10:00:00Z",
  "updatedAt": "2026-06-25T10:00:00Z",
  "lastUsedAt": null
}

DELETE /v1/speakers/{speakerId}

話者を削除する。latentファイルも同時に削除される。

{
  "speakerId": "a1b2c3d4-...",
  "deleted": true
}

POST /v1/synthesize

音声合成を実行する。以下の4パターンをサポート:

パターン speakerId caption 動作
Reference -- 参照音声から話者を再現
VoiceDesign -- キャプションでスタイルを指定
Hybrid 参照音声 + キャプション
Text-only -- -- テキストのみ

Content-Type: application/json

フィールド 必須 デフォルト 説明
text string -- 読み上げ本文
speakerId string null 話者ID
caption string null スタイル指示。speakerId に caption が設定されている場合はリクエストの caption が優先され、未指定時は speaker の caption が使われる
model object 下表 モデル指定
sampling object 下表 サンプリング設定
duration object 下表 音声長制御
guidance object 下表 ガイダンス設定
truncation object 下表 拡散サンプリングの数値的補正
kvCache object 下表 KVキャッシュ関連の挙動
tailTrim object 下表 末尾の無音トリム
decode object 下表 デコード方式
tokenLimits object 下表 トークン長制限
output object 下表 出力設定
longText object/null null 長文分割設定(下表)。指定時はテキストを自動分割してセグメントごとに推論・結合する

model:

キー デフォルト 説明
name string/null null モデル名(null=サーバ設定値)
loraAdapter string/null null LoRAアダプタ名(null=使用しない)

sampling:

キー デフォルト 説明
preset string "custom" balanced / quality / speed / extreme / custom
numSteps int 40 拡散ステップ数
numCandidates int 1 候補数(最大4)
seed int/null null 乱数シード
tScheduleMode string "linear" tスケジュールモード (linear / sway)
swayCoeff float -1.0 sway coefficient

duration:

キー デフォルト 説明
seconds float/null null 生成秒数。nullならモデル内蔵のduration predictorが自動予測
durationScale float 1.0 duration predictorの出力倍率
minSeconds float 0.5 生成秒数の下限

guidance:

キー デフォルト 説明
mode string "independent" CFGガイダンスモード (independent / joint / alternating)
cfgScale float/null null 全CFGスケールを一括指定(null=個別設定を使用)
cfgScaleText float 3.0 テキストCFG
cfgScaleCaption float 3.0 キャプションCFG
cfgScaleSpeaker float 5.0 スピーカーCFG
cfgMinT float 0.5 CFGが有効になるtの下限
cfgMaxT float 1.0 CFGが有効になるtの上限

truncation:

キー デフォルト 説明
factor float/null null truncation factor(null=無効)
rescaleK float/null null rescale k(null=無効)
rescaleSigma float/null null rescale sigma(null=無効)

kvCache:

キー デフォルト 説明
contextKvCache bool true context KVキャッシュを使用
speakerKvScale float/null null speaker KVスケール(null=無効)
speakerKvMinT float/null null speaker KVが有効になるtの下限
speakerKvMaxLayers int/null null speaker KVが適用されるレイヤー数上限
speakerUncondMode string "mask" speaker無条件時のモード (mask / zero)

tailTrim:

キー デフォルト 説明
trimTail bool true 末尾の無音をトリム
tailWindowSize int 20 末尾トリムの窓サイズ
tailStdThreshold float 0.05 末尾トリムの標準偏差しきい値
tailMeanThreshold float 0.1 末尾トリムの平均しきい値

decode:

キー デフォルト 説明
mode string "sequential" デコード方式 (sequential / batch)

tokenLimits:

キー デフォルト 説明
maxTextLen int/null null テキスト最大トークン長(null=モデル上限)
maxCaptionLen int/null null キャプション最大トークン長(null=モデル上限)

output:

キー デフォルト 説明
format string "wav" 出力形式
mode string "buffer" buffer: 音声を直接返す / inline: base64でJSONに埋め込む

longText:

指定時は長文モードが有効になり、テキストが句読点等で自動分割され、各セグメントを個別推論したのち前後無音トリムと無音区間挿入で結合される。sampling, guidance, kvCache, tailTrim 等の全パラメータはそのまま利用可能。

durationScale が 1.0 を前提とした場合のパラメータ感:

  • 30 / 180 / 0.2(デフォルト): 各セグメントを個別に作ってつなげたのと等しい、最も自然な結果になる
  • 30 / 200 / 0.2: 少々早めの読み上げで、詰め込み気味のthe読み上げ感が出る
  • 28 / 200 / 0.2: セグション時間が足りていない感じになり、不自然になりやすい

キャラクターごとのおすすめ設定:

  • ゆっくり話すキャラ: maxSegmentChars: 150, segmentGapSeconds: 0.3
  • 標準的なキャラ: デフォルト値(180, 0.2)そのままでOK
  • 早口・元気なキャラ: maxSegmentChars: 200, segmentGapSeconds: 0.15
  • 落ち着いたナレーション: maxSegmentSeconds: 30, maxSegmentChars: 160, segmentGapSeconds: 0.25

上記はあくまで目安であり、実際のキャラクター特性やテキスト内容によって調整が必要な場合がある。

キー デフォルト 説明
maxSegmentSeconds float 30.0 1セグメントあたりの最大推定秒数
maxSegmentChars int 180 1セグメントの最大文字数
charsPerSecond float 10.0 1秒あたりの発話文字数推定値
minSegmentChars int 4 セグメント最小文字数(これ以下は前セグメントへ結合)
segmentGapSeconds float 0.2 セグメント間無音区間(秒)
segmentTrimSilenceDb float -40.0 セグメント前後無音トリム閾値 (dB)
maxBatchSegments int 8 1バッチで同時処理するセグメント最大数。サーバ設定 (MAX_BATCH_SEGMENTS) を超える場合は上限にクランプされる

inline レスポンスには segments 配列が含まれる。buffer モードでは X-Segments ヘッダーにセグメント数が入る。

キャプション指定 + bufferモードの例:

curl -X POST http://localhost:8000/v1/synthesize \
  -H "Content-Type: application/json" \
  -d '{"text":"こんにちは!","caption":"元気な幼女"}' \
  --output voice.wav

話者参照 + inlineモードの例:

curl -X POST http://localhost:8000/v1/synthesize \
  -H "Content-Type: application/json" \
  -d '{"text":"今日はいい天気ですね。","speakerId":"a1b2c3d4-...","output":{"mode":"inline"}}'

bufferモードのレスポンス: 音声データをそのまま返します(Content-Type: audio/wav

以下のレスポンスヘッダを含みます:

ヘッダ 説明
X-Request-Id リクエストID(UUID)
X-Sample-Rate サンプリングレート
X-Seed 使用したシード値

inlineモードのレスポンス:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "succeeded",
  "model": {
    "checkpoint": "Aratako/Irodori-TTS-v4.1-Small"
  },
  "conditioning": {
    "speakerId": "a1b2c3d4-...",
    "caption": null,
    "mode": "speaker"
  },
  "audios": [
    {
      "index": 0,
      "contents": "UklGRiQAAABXQVZF...",
      "mimeType": "audio/wav",
      "sampleRate": 48000,
      "duration": 3.42
    }
  ],
  "seed": 123456789,
  "timings": {
    "totalToDecodeMs": 9051.4
  },
  "messages": []
}

id はリクエストごとに UUID で生成され、ログにも req_id として出力されます。すべてのレスポンスヘッダに X-Request-Id として付与されます。

ディレクトリ構造

src/configs/      -- 環境変数設定
src/lib/          -- 共通エラー定義
src/middleware/    -- ロギング・エラーハンドラ
src/routes/v1/    -- APIエンドポイント(speakers, synthesize)
src/schemas/      -- Pydanticリクエスト/レスポンスモデル(synthesize, speakers, runtime)
src/services/     -- 話者ストア・TTSランタイム管理
data/             -- speakers.json + latents/*.pt(実行時に生成)
models/           -- HuggingFace Hubキャッシュ(自動生成)

About

Irodori TTS REST API Docker - Irodori TTS の汎用http API 及び docker compose

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages