suzuna / state suzuna tts v2

Suzuna — STATE TTS Studio v2

概要

Phase 3で実装したTTSスタジオに、AivisSpeech Engine APIで叩ける機能を全て追加する。 500文字制限への対応、スタイル切り替え、パラメーター調整UIを実装する。


追加機能一覧

機能概要
文字数カウンターリアルタイム表示、500文字超えで警告
自動分割・結合500文字超えテキストを自動分割→生成→WAV結合
スタイル切り替え感情スタイル選択(ノーマル/あまあま/せつなめ/ねむたい等)
話速スライダー0.5〜2.0
音高スライダー-0.15〜0.15
抑揚スライダー0.0〜2.0
音量スライダー0.0〜2.0
ユーザー辞書UI固有名詞・読み方の登録・編集・削除

UI構成

┌─ TTSスタジオ ──────────────────────────────────────────────────┐
│                                                                 │
│  ベース音声(AivisSpeech)     スタイル                         │
│  [コハク(ノーマル) ▼]        [ノーマル ▼]                    │
│                                                                 │
│  声モデル(RVC・任意)                                          │
│  [― なし(ベース音声のまま) ▼]                                │
│                                                                 │
│  ピッチ(RVC)  [──●──] +0     話速  [──●──] 1.0x            │
│                                                                 │
│  [詳細パラメーター ▼]                                           │
│  音高   [──●──]  0.00          (-0.15〜+0.15)                 │
│  抑揚   [──●──]  1.00          (0.0〜2.0)                     │
│  音量   [──●──]  1.00          (0.0〜2.0)                     │
│                                                                 │
├─────────────────────────────────────────────────────────────────┤
│  テキスト入力                              234 / 500 文字       │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │ こんにちは!今日もよろしくお願いします。                  │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│  [▶ 生成する]  [📖 辞書登録]                                    │
│                                                                 │
│  ※ 500文字を超えると自動で分割して生成・結合します             │
│                                                                 │
├─ 履歴 ──────────────────────────────────────────────────────────┤
│  ├─ "こんにちは!今日も..."  [▶][💾][🗑]                      │
│  └─ "よろしくお願いします"  [▶][💾][🗑]                       │
└─────────────────────────────────────────────────────────────────┘

文字数カウンター仕様

通常時:   234 / 500 文字   (グレー表示)
警告時:   487 / 500 文字   (--color-warning 橙色)
超過時:   523 / 500 文字 ⚠ 自動分割して生成します
                           (--color-warning + 説明テキスト)
  • テキスト入力と連動してリアルタイム更新
  • 超過時はエラーではなく「自動分割して生成します」と案内
  • 生成ボタンは超過時も押せる(エラーにしない)

500文字超え自動分割・結合パイプライン

分割ロジック

def split_text(text: str, max_chars: int = 500) -> list[str]:
    """
    句読点(。!?\n)を優先して分割する。
    自然な区切りで分割することで音声の繋がりを自然に保つ。
    """
    import re
    # 句読点で分割
    sentences = re.split(r'(?<=[。!?\n])', text)
    chunks = []
    current = ""
    for sentence in sentences:
        if len(current) + len(sentence) <= max_chars:
            current += sentence
        else:
            if current:
                chunks.append(current)
            current = sentence
    if current:
        chunks.append(current)
    return chunks

生成・結合パイプライン

async def generate_tts_with_split(text, speaker_id, params, rvc_config):
    chunks = split_text(text)
    wav_segments = []

    for i, chunk in enumerate(chunks):
        # AivisSpeechでWAV生成
        query = await aivis_audio_query(chunk, speaker_id, params)
        wav_bytes = await aivis_synthesis(query, speaker_id)

        # RVC変換(設定されている場合)
        if rvc_config.model_path:
            wav_bytes = await rvc_convert(wav_bytes, rvc_config)

        wav_segments.append(wav_bytes)

    # WAVを結合
    combined = combine_wav_segments(wav_segments)
    return combined

def combine_wav_segments(segments: list[bytes]) -> bytes:
    """
    soundfileを使ってWAVバイナリを結合する。
    サンプリングレートはAivisSpeechのデフォルト(44100Hz)に統一。
    """
    import soundfile as sf
    import numpy as np
    import io

    arrays = []
    sr = None
    for seg in segments:
        data, rate = sf.read(io.BytesIO(seg))
        arrays.append(data)
        sr = rate

    combined = np.concatenate(arrays)
    buf = io.BytesIO()
    sf.write(buf, combined, sr, format='WAV')
    return buf.getvalue()

フロントへの進捗通知

分割数が多い場合(3チャンク以上)はUIに進捗を表示する。

生成中... (1/4)
生成中... (2/4)
生成中... (3/4)
結合中...
完了!

スタイル切り替え仕様

AivisSpeechのスタイルはスピーカーIDで管理されている。 同一キャラクターの異なるスタイルは異なるスピーカーIDを持つ。

// スピーカー一覧の取得
GET /aivis/speakers
response: {
  speakers: [
    {
      id: 0,
      name: "コハク(ノーマル)",
      character: "コハク",
      style: "ノーマル"
    },
    {
      id: 1,
      name: "コハク(あまあま)",
      character: "コハク",
      style: "あまあま"
    }
  ]
}

UI上はキャラクター選択とスタイル選択を2段階にする:

  1. キャラクター選択(コハク、など)
  2. スタイル選択(ノーマル / あまあま / せつなめ / ねむたい)

ユーザー辞書UI

固有名詞(鈴菜、えなどりなど)の読み方を登録する。

┌─ ユーザー辞書 ────────────────────────────────────┐
│  [+ 新規登録]                                      │
│                                                    │
│  鈴菜      すずな    [編集][削除]                  │
│  えなどり  えなどり  [編集][削除]                  │
│                                                    │
│  ┌─ 新規登録 ──────────────────────────────────┐  │
│  │ 表記: [          ]  読み: [          ]       │  │
│  │ [登録する]                                   │  │
│  └──────────────────────────────────────────────┘  │
└────────────────────────────────────────────────────┘

バックエンドAPI

GET  /aivis/dictionary          → 辞書一覧取得
POST /aivis/dictionary          → 単語登録
PUT  /aivis/dictionary/{id}     → 単語更新
DELETE /aivis/dictionary/{id}   → 単語削除

APIスキーマ変更

POST /tts(変更)

interface TTSRequest {
  text: string
  aivis_speaker_id: number
  rvc_model_path?: string
  pitch_shift: number

  // 追加パラメーター
  speed_scale: number       // 話速  0.5〜2.0  default: 1.0
  pitch_scale: number       // 音高  -0.15〜0.15  default: 0.0
  intonation_scale: number  // 抑揚  0.0〜2.0  default: 1.0
  volume_scale: number      // 音量  0.0〜2.0  default: 1.0
}

変更ファイル

ファイル種別内容
python/routers/tts.py変更分割生成・WAV結合・パラメーター追加
python/routers/aivis.py新規ユーザー辞書API・スピーカー2段階取得
src/pages/TTSPage.tsx変更文字数カウンター・スタイル選択・詳細パラメーター・辞書UI
src/lib/api.ts変更TTSRequest型更新・辞書API追加

完了条件

  • 文字数カウンターがリアルタイム表示される
  • 500文字超えで警告バッジ + 案内テキスト表示
  • 500文字超え時に自動分割→生成→WAV結合が動く
  • 分割数3以上で進捗表示(1/4, 2/4…)
  • キャラクター選択 + スタイル選択の2段階UIが動く
  • 話速・音高・抑揚・音量スライダーが追加される
  • 詳細パラメーターはアコーディオンで折りたたまれている
  • ユーザー辞書の登録・編集・削除が動く