はじめに
OpenAI Whisperは、99言語をサポートする最先端のオープンソース音声認識モデルです。このチュートリアルでは、クラウドAPIのコストなしでセルフホスティングできる完全な音声認識APIサービスを構築します。
構築するもの
- 音声文字起こし用のFastAPI RESTサービス
- 多言語音声認識(自動検出または指定)
- 話者分離(誰が何を言ったか)
- WebSocketによるリアルタイムストリーミング転写
- 本番用Dockerデプロイメント
- Python 3.10以上
- FFmpegインストール済み
- GPU推奨(CUDA)、CPUでも動作可
- PythonとREST APIの基本知識
前提条件
ステップ1:プロジェクトセットアップ
プロジェクト構造を作成します:
mkdir whisper-api && cd whisper-api
python -m venv venv
source venv/bin/activate
pip install openai-whisper fastapi uvicorn python-multipart \
pydub torch torchaudio websockets pyannote.audio
whisper-api/
├── app/
│ ├── __init__.py
│ ├── main.py
│ ├── models.py
│ ├── transcriber.py
│ ├── diarizer.py
│ └── ws_stream.py
├── Dockerfile
├── docker-compose.yml
├── requirements.txt
└── tests/
└── test_api.py
ステップ2:コア転写エンジン
app/transcriber.pyを作成します:
import whisper
import torch
from functools import lru_cache
from pathlib import Path
import tempfile
import logging
logger = logging.getLogger(__name__)
class WhisperTranscriber:
"""OpenAI Whisperの音声文字起こしラッパー"""
def __init__(self, model_size: str = "base"):
self.device = "cuda" if torch.cuda.is_available() else "cpu"
logger.info(f"Whisperモデル '{model_size}' を{self.device}で読み込み中")
self.model = whisper.load_model(model_size, device=self.device)
logger.info("モデルの読み込み完了")
def transcribe(
self,
audio_path: str,
language: str | None = None,
task: str = "transcribe",
word_timestamps: bool = False,
) -> dict:
"""音声ファイルを文字起こしする
Args:
audio_path: 音声ファイルパス(FFmpegがサポートする任意のフォーマット)
language: ISO言語コード(Noneで自動検出)
task: 'transcribe' または 'translate'
word_timestamps: 単語レベルのタイムスタンプを含める
"""
options = {
"task": task,
"word_timestamps": word_timestamps,
"verbose": False,
}
if language:
options["language"] = language
result = self.model.transcribe(audio_path, **options)
return {
"text": result["text"].strip(),
"language": result["language"],
"segments": [
{
"id": seg["id"],
"start": round(seg["start"], 2),
"end": round(seg["end"], 2),
"text": seg["text"].strip(),
}
for seg in result["segments"]
],
}
ステップ3:FastAPIアプリケーション
app/main.pyを作成します:
import os
import tempfile
import time
from contextlib import asynccontextmanager
from pathlib import Path
from fastapi import FastAPI, UploadFile, File, Form, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from .transcriber import get_transcriber
MODEL_SIZE = os.getenv("WHISPER_MODEL", "base")
@asynccontextmanager
async def lifespan(app: FastAPI):
get_transcriber(MODEL_SIZE)
yield
app = FastAPI(
title="Whisper 音声認識 API",
version="1.0.0",
lifespan=lifespan,
)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
@app.post("/transcribe")
async def transcribe_audio(
file: UploadFile = File(...),
language: str | None = Form(None),
task: str = Form("transcribe"),
word_timestamps: bool = Form(False),
):
"""音声ファイルを文字起こしする"""
start_time = time.time()
suffix = Path(file.filename or "audio.wav").suffix or ".wav"
with tempfile.NamedTemporaryFile(suffix=suffix, delete=True) as tmp:
content = await file.read()
tmp.write(content)
tmp.flush()
transcriber = get_transcriber(MODEL_SIZE)
result = transcriber.transcribe(
tmp.name, language=language, task=task,
word_timestamps=word_timestamps,
)
duration = round(time.time() - start_time, 2)
return {**result, "duration": duration}
ステップ4:テスト
サーバーを起動してテスト:
# ローカル起動
uvicorn app.main:app --reload
# curlでテスト
curl -X POST http://localhost:8000/transcribe \
-F "file=@会議録音.mp3"
# 日本語を指定
curl -X POST http://localhost:8000/transcribe \
-F "file=@japanese_audio.wav" \
-F "language=ja" \
-F "word_timestamps=true"
# 英語に翻訳
curl -X POST http://localhost:8000/transcribe \
-F "file=@日本語音声.mp3" \
-F "task=translate"
ステップ5:Dockerデプロイメント
FROM python:3.11-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
ffmpeg && rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app/ app/
EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
docker compose up --build
モデルサイズ比較
| モデル | パラメータ数 | VRAM | 相対速度 | 英語WER |
|--------|-------------|------|----------|--------|
| tiny | 39M | ~1 GB | ~32x | ~7.7% |
| base | 74M | ~1 GB | ~16x | ~5.0% |
| small | 244M | ~2 GB | ~6x | ~3.4% |
| medium | 769M | ~5 GB | ~2x | ~2.9% |
| large-v3 | 1550M | ~10 GB | 1x | ~2.0% |
パフォーマンスのヒント
1. GPUを使用: CUDAでCPUの10-30倍高速化
2. 適切なモデル選択: 速度重視ならbase、精度重視ならlarge-v3
3. バッチ処理: Celery/RQでタスクキューイング
4. FP16: GPUではデフォルトでFP16使用、FP32を強制しない
まとめ
これで商用サービスに匹敵するセルフホスト型音声認識APIが完成しました。Whisperの多言語対応は国際的なアプリケーションに最適で、FastAPIラッパーにより/docsで自動ドキュメントが利用できる本番対応のインターフェースが得られます。