Kokoro-TTS導入・活用ガイド:Linux上でオフラインAI Text-to-Speech環境を自前構築する

Artificial Intelligence tutorial - IT technology blog
Artificial Intelligence tutorial - IT technology blog

背景とKokoro-TTSをセルフホストすべき理由

半年ほど前、私たちのチームが運用するコールセンターボットとニュース読み上げ自動化システムは、ElevenLabsやAzure SpeechのAPI利用料だけで毎月2,400ドル以上を消費していました。跳ね上がる請求額もさることながら、さらに深刻だったのは1リクエストあたり1.2秒〜1.8秒という不安定なネットワークレイテンシと、顧客データの外部流出リスクでした。この課題を抜本的に解決するには、Linux上でオンプレミスのTTSクラスタを自前構築するほかありませんでした。

当初はBarkを試行しましたが、RAMの消費が激しく、CPU上でのRTF(Real-Time Factor)は4.0まで跳ね上がりました。次にCoqui XTTS-v2へ移行したところ品質は非常に良好だったものの、最低4GBのVRAMが必要で、リアルタイムの対話フローに対して音声生成速度が追いつきませんでした。最終的にすべての課題を解決してくれたのがKokoro-TTSでした。このモデルはパラメータ数がわずか8,200万(82M)しかありません。驚くほど自然な音声を生成でき、高価なGPUを必要とせず通常のCPU環境でもスムーズに動作します。

音声パイプラインを完全に手元でコントロールし、クラウドサービスへの依存を脱却したいなら、Kokoro-TTSは現時点で最もコストパフォーマンスの高い選択肢です。

Linux環境のセットアップとKokoro-TTSのインストール

本記事では検証環境としてUbuntu 22.04 LTSを使用します(Debian 12でも同様の手順で構築可能です)。Kokoroは音素化(Phonemization)の処理にespeak-ngを利用するため、まずは基盤となるC/C++関連パッケージを導入する必要があります。

1. システム依存パッケージのインストール

sudo apt-get update && sudo apt-get install -y \
    python3-pip \
    python3-venv \
    espeak-ng \
    ffmpeg \
    libsndfile1

2. Python仮想環境の作成とライブラリのインストール

システムのグローバルなPython環境に直接インストールするのは避け、venvで隔離環境を作成しましょう。

mkdir -p /opt/kokoro-service && cd /opt/kokoro-service
python3 -m venv venv
source venv/bin/activate

# サーバーコストを抑えるためCPU版PyTorchをインストール
pip install --upgrade pip
pip install torch torchaudio --index-url https://download.pytorch.org/whl/cpu

# Kokoro、soundfile、音声アレイ結合用のnumpyをインストール
pip install kokoro soundfile numpy

もしサーバーにNVIDIA GPU(T4やRTX 3060など)が搭載されている場合は、PyTorchのインストールコマンドをCUDA対応版(例:cu121)に差し替えてください。推論速度が5〜8倍程度向上します。

FastAPIによるREST APIサービスの構築

ライブラリの準備が完了したら、音声生成スクリプトを作成し、FastAPIを使ってREST APIとしてラップします。これにより、社内の各マイクロサービスからHTTP POST経由で手軽に呼び出せるようになります。

1. Pythonでの基本的な音声合成テスト

動作確認用のテストファイル test_speech.py を作成します。

import soundfile as sf
from kokoro import KPipeline

# パイプラインを初期化(アメリカ英語: 'a'、イギリス英語: 'b')
pipeline = KPipeline(lang_code='a')

text = "Kokoro is an efficient text to speech model running entirely on premise."

# サンプルボイスaf_heart(女性、温かみのある表現力豊かな声)を使用
generator = pipeline(text, voice='af_heart', speed=1.0, split_pattern=r'\n+')

for i, (gs, ps, audio) in enumerate(generator):
    sf.write(f'output_{i}.wav', audio, 24000)
    print(f"output_{i}.wav を出力しました | サンプル数: {len(audio)}")

python test_speech.py を実行します。初回の実行時には、約330MBのチェックポイントファイルがHugging Faceからキャッシュディレクトリ ~/.cache/huggingface/hub へ自動的にダウンロードされます。

2. FastAPIによるAPIサービスの実装

Webサーバーに必要な追加パッケージをインストールします。

pip install fastapi uvicorn pydantic

分割生成された音声配列を結合し、1つのWAVファイルとして返却する app.py を作成します。

import io
import numpy as np
import soundfile as sf
from fastapi import FastAPI, HTTPException
from fastapi.responses import Response
from pydantic import BaseModel
from kokoro import KPipeline

app = FastAPI(title="Kokoro TTS Private API")

# アプリ起動時にモデルをメモリへ1回だけロード
pipeline = KPipeline(lang_code='a')

class TTSRequest(BaseModel):
    text: str
    voice: str = "af_heart"
    speed: float = 1.0

@app.post("/v1/audio/speech")
def generate_speech(req: TTSRequest):
    clean_text = req.text.strip()
    if not clean_text:
        raise HTTPException(status_code=400, detail="Text cannot be empty")
    
    try:
        generator = pipeline(clean_text, voice=req.voice, speed=req.speed)
        segments = 
        
        if not segments:
            raise HTTPException(status_code=500, detail="Failed to synthesize audio")
        
        full_audio = np.concatenate(segments)
        
        buffer = io.BytesIO()
        sf.write(buffer, full_audio, 24000, format='WAV')
        buffer.seek(0)
        
        return Response(content=buffer.read(), media_type="audio/wav")
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@app.get("/health")
def health_check():
    return {"status": "ok", "model": "Kokoro-82M"}

3. Systemdによるバックグラウンドプロセスの常駐化

プロセスのクラッシュ時やサーバー再起動時にサービスが自動復旧するよう、/etc/systemd/system/kokoro-tts.service にUnitファイルを作成します。

[Unit]
Description=Kokoro TTS Offline API Service
After=network.target

[Service]
User=ubuntu
WorkingDirectory=/opt/kokoro-service
ExecStart=/opt/kokoro-service/venv/bin/uvicorn app:app --host 0.0.0.0 --port 8080 --workers 1
Restart=always
RestartSec=5
Environment="PYTHONUNBUFFERED=1"

[Install]
WantedBy=multi-user.target

--workers 1 の指定に注目してください。リソースの限られたCPU環境やGPU運用では、ワーカー数を1に維持することでモデルの複製によるRAM/VRAMの枯渇を防ぐことができます。

サービスを有効化して起動します。

sudo systemctl daemon-reload
sudo systemctl enable kokoro-tts
sudo systemctl start kokoro-tts

パフォーマンステストと実測評価

構築したシステムが負荷にどの程度耐えられるか、実際のパフォーマンスを計測・評価します。

1. cURLを用いたレスポンスレイテンシの検証

以下のテストコマンドを実行し、ファイル取得までの総所要時間を計測します。

time curl -X POST "http://localhost:8080/v1/audio/speech" \
     -H "Content-Type: application/json" \
     -d '{"text": "Your order number 1024 has been processed successfully.", "voice": "af_heart", "speed": 1.0}' \
     --output order_success.wav

月額12ユーロのHetzner VPS(4 vCPU、x86_64)での検証結果では、10単語の文章から3.2秒の音声ファイルを生成するのにかかった時間はわずか260msでした。RTF(Real-Time Factor)は約0.08を記録しており、実際の再生速度の約12倍という圧倒的なスピードで音声を生成できています。

2. ハードウェアリソースの消費量

稼働中のプロセスを監視します。

# リアルタイムログを確認
journalctl -u kokoro-tts -f

# RAMおよびCPU使用量を確認
ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%mem | grep uvicorn

6か月間の継続運用において、UvicornプロセスのRAM消費量はCPUモードで約480MB〜550MBの範囲で安定しており、メモリリークの兆候は一切見られませんでした。本番環境へ投入する際は、前段にNginxリバースプロキシを配置し、IPごとのレートリミット(例:最大15リクエスト/分)や1リクエストあたりのペイロード文字数制限(500文字未満など)を設定して、CPUキューの詰まりを防ぐ構成をおすすめします。

Share: