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段階にする:
- キャラクター選択(コハク、など)
- スタイル選択(ノーマル / あまあま / せつなめ / ねむたい)
ユーザー辞書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が動く
- 話速・音高・抑揚・音量スライダーが追加される
- 詳細パラメーターはアコーディオンで折りたたまれている
- ユーザー辞書の登録・編集・削除が動く