Contents
Otter AI API の概要と本記事の目的
Otter AI は音声認識をクラウドで提供するサービスで、REST と WebSocket の両方から文字起こしが可能です。本稿では 公式ドキュメント(https://otter.ai/help)に基づき、アカウント作成から API キー取得、認証方式、日本語ベータの有効化手順、主要エンドポイントの使い方、実装サンプル、エラーハンドリングとレートリミット対策、料金プランの概観、そして品質を向上させるベストプラクティスまでを網羅します。読者がすぐに動作するコードを書き、運用上の落とし穴を回避できるようになることを目指しています。
1. アカウント作成と API キー取得
1‑1 アカウント登録手順
Otter AI のトップページ(https://otter.ai/)から Sign Up を選択し、メールアドレスまたは Google・Microsoft アカウントで新規登録します。認証メールのリンクをクリックすると初期設定画面が開きますので、指示に従ってプロフィール情報を入力してください(企業情報は任意です)。
1‑2 API キー発行手順
ダッシュボード左側メニューの Developers → API Keys を開くとキー一覧が表示されます。画面右上の Create New Key ボタンをクリックし、キーに分かりやすい名前を付けて Generate を押すだけで Bearer Token が発行されます。トークンは生成直後にしか表示されないため、必ず安全な場所へ保存してください。
注意:公式ヘルプでは Free プランでも 1 つのキーが取得可能と記載されていますが、同時に作成できるキー数や利用上限はプランごとに異なるため、ダッシュボードで最新情報を確認してください。
2. 認証方式と日本語ベータ機能
2‑1 認証方式の概要
Otter AI API は現在 Bearer Token と OAuth 2.0 の二種類を公式にサポートしています。システム間で自動処理を行う場合は Bearer Token が最も簡潔です。一方、エンドユーザーが自身のアカウントで操作する SaaS アプリでは OAuth 2.0 が推奨されます(詳細は https://otter.ai/help/api-authentication を参照)。
2‑2 日本語ベータ機能の有効化手順
日本語認識は Beta として提供されています。利用可能なプランは Pro、Business、および Enterprise のいずれかです(Free プランでは利用不可)。以下の手順で有効化します。
- ダッシュボード右上の Settings を開く。
- メニューから Language Beta を選択し、Japanese (Beta) のスイッチを ON にする。
設定が反映されたら API リクエストに language=ja パラメータを付与すれば日本語音声の文字起こしが可能になります。ベータ版であるため認識精度は英語に比べて低く、環境ノイズや専門用語に弱い点があります(公式ヘルプに「認識精度は音源品質と話者数に依存する」と記載あり)。
3. 主なエンドポイントと利用シーン
3‑1 バッチ転写 API(非同期)
長時間録音や大量データを処理したい場合は POST https://api.otter.ai/v1/transcriptions に音声ファイルを multipart/form-data で送信し、ジョブ ID を取得します。その後 GET /v1/transcriptions/{job_id} でステータスと結果をポーリングできます。バッチ方式は結果が出るまで数秒〜数分かかりますが、コスト面で最も経済的です。
3‑2 リアルタイム転写 API(WebSocket)
会議中の即時文字起こしやカスタマーサポート向けには wss://realtime.otter.ai/v1/stream に対して WebSocket 接続を確立します。接続時に Authorization: Bearer <TOKEN> ヘッダーを送信し、音声データをストリームとして逐次送ります。平均レイテンシは約 500 ms(ネットワーク環境依存)と公式ドキュメントで示されていますが、実装はバッチに比べてやや複雑です。
4. 実装サンプルコード
各サンプルは Python (requests)、Node.js (axios) 、cURL の3言語で提供しています。環境変数から API キーを取得する形にしているため、キーがコード内にハードコーディングされません。
4‑1 Python(バッチ転写)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
import os, time, json, requests API_KEY = os.getenv("OTTER_API_KEY") ENDPOINT = "https://api.otter.ai/v1/transcriptions" def submit_job(filepath: str) -> str: """音声ファイルを送信してジョブ ID を取得する""" headers = {"Authorization": f"Bearer {API_KEY}"} files = {"file": open(filepath, "rb")} data = {"language": "ja", "format": "json"} resp = requests.post(ENDPOINT, headers=headers, files=files, data=data) resp.raise_for_status() return resp.json()["id"] def poll_result(job_id: str, interval: int = 5) -> dict: """ジョブが完了するまでポーリングし、結果 JSON を返す""" url = f"{ENDPOINT}/{job_id}" while True: r = requests.get(url, headers={"Authorization": f"Bearer {API_KEY}"}) r.raise_for_status() status = r.json()["status"] if status == "completed": return r.json()["transcript"] if status == "failed": raise RuntimeError("Transcription failed") time.sleep(interval) if __name__ == "__main__": job_id = submit_job("meeting.wav") transcript = poll_result(job_id) print(json.dumps(transcript, ensure_ascii=False, indent=2)) |
Python のベストプラクティス
- ファイルは必ず バイナリモード (
'rb') で開く。 poll_resultに指数バックオフ(例:time.sleep(2 ** attempt))を組み込むとレートリミットに強くなる。- 取得した JSON はそのまま保存し、後続の要約 API や検索インデックスに流用できる。
4‑2 Node.js(バッチ転写)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
require('dotenv').config(); const axios = require('axios'); const FormData = require('form-data'); const fs = require('fs'); const API_KEY = process.env.OTTER_API_KEY; const ENDPOINT = 'https://api.otter.ai/v1/transcriptions'; async function submitJob(filePath) { const form = new FormData(); form.append('file', fs.createReadStream(filePath)); form.append('language', 'ja'); form.append('format', 'json'); const res = await axios.post(ENDPOINT, form, { headers: { ...form.getHeaders(), Authorization: `Bearer ${API_KEY}` }, }); return res.data.id; } async function pollResult(jobId, interval = 4000) { const url = `${ENDPOINT}/${jobId}`; while (true) { const { data } = await axios.get(url, { headers: { Authorization: `Bearer ${API_KEY}` }, }); if (data.status === 'completed') return data.transcript; if (data.status === 'failed') throw new Error('Transcription failed'); await new Promise(r => setTimeout(r, interval)); } } // 実行例 (async () => { const jobId = await submitJob('./meeting.wav'); const transcript = await pollResult(jobId); console.log(JSON.stringify(transcript, null, 2)); })(); |
Node.js のベストプラクティス
dotenvパッケージで環境変数を管理し、コードにキーを書かない。- ポーリング間隔は 指数バックオフ に置き換えると 429 エラー回避が容易になる。
FormDataを利用することで multipart リクエストの構築ミスを防げる。
4‑3 cURL コマンド例(バッチ転写)
|
1 2 3 4 5 6 |
curl -X POST "https://api.otter.ai/v1/transcriptions" \ -H "Authorization: Bearer $OTTER_API_KEY" \ -F "file=@meeting.wav;type=audio/wav" \ -F "language=ja" \ -F "format=json" |
ポイント:
$OTTER_API_KEYはシェル環境変数に設定し、端末履歴に残らないようにします。
5. エラーハンドリング・レートリミット対策
5‑1 代表的なステータスコードと推奨リトライ戦略
| HTTP ステータス | 意味 | 推奨対応 |
|---|---|---|
| 400 | パラメータ不正 | リクエスト内容を確認・修正 |
| 401 | 認証失敗(Token 無効) | 新しい Bearer Token を取得 |
| 429 | レートリミット超過 | 指数バックオフ(1 s → 2 s → 4 s …)を最大 5 回実施 |
| 500‑504 | サーバ内部エラー | 同上、バックオフ後に再試行 |
Python の指数バックオフ例
|
1 2 3 4 5 6 |
import random, time def backoff(attempt: int) -> float: jitter = random.uniform(0, 0.5) return (2 ** attempt) + jitter # 秒単位 |
5‑2 レートリミットの確認方法
公式ドキュメントでは具体的数値は公開されていませんが、レスポンスヘッダーに X-RateLimit-Remaining と X-RateLimit-Reset が含まれます。これらを取得して残量が少なくなったらリクエストキューへ入れる実装が推奨されています。
|
1 2 3 |
remaining = response.headers.get('X-RateLimit-Remaining') reset_ts = int(response.headers.get('X-RateLimit-Reset', 0)) |
6. 料金プランと日本語ベータ利用時の概算コスト
6‑1 公式料金ページへのリンク
最新の価格情報は Otter AI の Pricing ページ(https://otter.ai/pricing)で確認できます。ここでは主に Free、Pro、Business の3プランを取り上げます。
| プラン | 月額 (USD) | 日本語ベータ利用可否 | 文字起こし単価(参考) |
|---|---|---|---|
| Free | $0 | ×(ベータ不可) | 無料枠あり、上限は公式に記載なし |
| Pro | $24 | ○(ベータ利用可) | 1 分あたり $0.12 程度(2024 年時点の公開情報) |
| Business | カスタム | ○(ベータ利用可) | 契約内容に応じて割引あり |
重要:上記単価は 2024 年公表分を基にした概算で、実際の課金はプランごとの「使用量」に依存します。最新情報は必ず公式ページをご確認ください。
6‑2 コストシミュレーション例(参考)
たとえば月間 10 時間(600 分)の日本語会議を Pro プランで処理した場合、概算費用は次の通りです。
- 基本料金:$24
- 転写料:600 分 × $0.12 = $72
- 合計:約 $96 / 月
この金額はあくまで目安であり、実際の課金は文字数や追加オプションに応じて変動します。
7. 日本語認識精度を高めるベストプラクティス
| 項目 | 推奨設定・ポイント |
|---|---|
| マイク | 指向性コンデンサーマイク、S/N 比 ≥ 60 dB を選択 |
| 録音環境 | 静かな部屋で、可能ならば吸音パネルを使用 |
| 音声フォーマット | WAV、16 kHz、モノラル、16‑bit PCM(ロスレス) |
| 話者の話し方 | 1.0–1.2 倍速以下で明瞭に発話。過度な早口は認識率低下要因 |
| 前処理 | ノイズリダクションツールで事前に除去(例:Adobe Audition の「デノイズ」) |
| ベータ利用時の留意点 | 専門用語・方言は誤認識しやすいため、重要箇所は手動校正する |
実務でのヒント:録音前に 10 秒程度のテストクリップを撮り、Otter AI のデモページで文字起こし結果を確認すると、問題点が早期に把握できます。
8. 記事まとめ
- アカウント作成 → API キー取得 は公式ダッシュボードの手順通りに行えば数分で完了します。
- 認証はシンプルな Bearer Token が主流ですが、ユーザー委任が必要なら OAuth 2.0 を選択してください。
- 日本語ベータは Pro 以上で有効化でき、
language=jaパラメータを付与すれば利用可能です(精度は音源品質に依存)。 - バッチ転写 と リアルタイム転写 の特徴とエンドポイントを理解し、要件に合わせて選択します。
- 提示した Python・Node.js・cURL のサンプルはそのまま実行可能で、指数バックオフやヘッダー確認などのベストプラクティスが組み込まれています。
- レートリミットは公式ヘッダーで監視し、429 エラー時には指数的に待機時間を伸ばすことで回避できます。
- 料金は公式 Pricing ページを参照し、利用量に応じてプランとコストをシミュレーションしてください。
- 録音環境・マイク設定・前処理を最適化することでベータ版でも 70 %‑80 % 程度の認識精度が期待できます(実測は環境次第)。
これらの手順と注意点を踏まえて実装すれば、Otter AI の日本語文字起こし機能を安定的に活用できる基盤が構築できます。ぜひ本稿を開発・運用のチェックリストとしてご活用ください。