低遅延なリアルタイム文字起こしモデル「Soniox v3」を試す ③共通コンセプト
Soniox v3で、非同期文字起こし・リアルタイムについてそれぞれ見てきた。
これらで共通となるコンセプトについて見ていく。
サポートされている言語
以下に記載がある
Sonioxでは60以上の言語(もちろん日本語含む)に対応しており、サポートされている言語であれば
- サポート対象の言語で文字起こし
- サポート対象の言語「間」の翻訳
が、非同期API・リアルタイムAPIの両方で利用可能。
モデルがサポートしている言語はmodelsエンドポイントで取得できる
また最新(2025年3月)のベンチマークは以下にある。これを見る限りほとんどの言語で他社よりも精度が高いということを謳っている様子。
なお、モデル比較でよく見かけるArtificial Analysis にはSonioxは載ってなかった。
モデル
基本的には以下の2つ。
-
stt-rt-v3: リアルタイム向けモデルの最新 -
stt-async-v3: 非同期向けモデルの最新
v2のプレビュー版もあるようだけど既にDeprecatedで、2025/11/30で& Retired になる。
過去のモデルの変遷を改めて見てみると
- 2025/05: v1(preview)
- 2025/08: v2(preview)
- 2025/10: v3
という感じで結構モデルの更新頻度が高い。
公式のブログを見ると2021年頃からSTT/ASRサービスをやっていて、以前は言語ごとにモデルを作っていたみたいだけど、1つのモデルで全部対応できる、みたいになったのが今のシリーズみたい。
ちょっと古いけどもHuggingFaceで言語モデルも公開されていた。
ここからは主に非同期API・リアルタイムAPIで共通となる設定・機能について。
非同期・リアルタイムのサンプルコードでは、設定用の関数が用意されていて、これを日本語化しつつ、非同期・リアルタイムで共通となる設定箇所を以下に抜粋した。
(snip)
# Soniox STT の設定を取得
def get_config(
audio_url: Optional[str], file_id: Optional[str], translation: Optional[str]
) -> dict:
config = {
# 使用するモデルを選択
# 参考: soniox.com/docs/stt/models
"model": "stt-async-v3",
#
# あらかじめ言語がわかっている場合は、言語ヒントで設定すると、認識精度が大幅に向上する
# 参考: soniox.com/docs/stt/concepts/language-hints
"language_hints": ["en", "es"],
#
# 言語識別を有効化。各トークンに "language" フィールドが含まれる。
# 参考: soniox.com/docs/stt/concepts/language-identification
"enable_language_identification": True,
#
# 話者ダイアライゼーション(話者識別)を有効化。各トークンに "speaker" フィールドが含まれる。
# 参考: soniox.com/docs/stt/concepts/speaker-diarization
"enable_speaker_diarization": True,
#
# コンテキストを設定すると、モデルがドメインを理解し、重要語句の認識や、カスタムの語彙・翻訳設定を適用できる
# 参考: soniox.com/docs/stt/concepts/context
"context": {
"general": [
{"key": "domain", "value": "Healthcare"},
{"key": "topic", "value": "Diabetes management consultation"},
{"key": "doctor", "value": "Dr. Martha Smith"},
{"key": "patient", "value": "Mr. David Miller"},
{"key": "organization", "value": "St John's Hospital"},
],
"text": "Mr. David Miller visited his healthcare provider last month for a routine follow-up related to diabetes care. The clinician reviewed his recent test results, noted improved glucose levels, and adjusted his medication schedule accordingly. They also discussed meal planning strategies and scheduled the next check-up for early spring.",
"terms": [
"Celebrex",
"Zyrtec",
"Xanax",
"Prilosec",
"Amoxicillin Clavulanate Potassium",
],
"translation_terms": [
{"source": "Mr. Smith", "target": "Sr. Smith"},
{"source": "St John's", "target": "St John's"},
{"source": "stroke", "target": "ictus"},
],
},
(snip)
# 翻訳オプション
# 参考: soniox.com/docs/stt/rt/real-time-translation#translation-modes
if translation == "none":
pass
elif translation == "one_way":
# すべての言語をターゲットとなる言語に翻訳
config["translation"] = {
"type": "one_way",
"target_language": "es",
}
elif translation == "two_way":
# language_a から language_b へ、そして language_b から language_a へ再翻訳
config["translation"] = {
"type": "two_way",
"language_a": "en",
"language_b": "es",
}
else:
raise ValueError(f"Unsupported translation: {translation}")
return config
設定は上記のような感じのJSONで定義してリクエストに付与すればいいみたい。
これを踏まえて個別に見ていく。
言語ヒント
サンプルコードだと以下の箇所
# あらかじめ言語がわかっている場合は、言語ヒントで設定すると、認識精度が大幅に向上する
# 参考: soniox.com/docs/stt/concepts/language-hints
"language_hints": ["en", "es"],
基本的にSonioxでは言語の自動識別が行われるので指定する必要はない。多言語が混在しててもOK。ただし、事前に音声に含まれている言語がわかっている場合はそれをヒントとして設定することで、認識精度が向上するらしい。
- ヒントは
language_hintsに対象言語のISOコードをリストで指定すれば良い。 - ただし指定した言語に限定されるわけではなく、あくまでも認識傾向を指定した言語に「寄せる」だけ。
言語ヒントを使うべきユースケースは以下
- あらかじめ音声データに含まれる言語がわかっている
- 特定の言語の精度をあげたい
- 一般的でない言語や言語間で発音が類似している場合
- 特定のターゲットユーザ・ターゲット市場向け
言語識別
サンプルコードだと以下の箇所
# 言語識別を有効化。各トークンに "language" フィールドが含まれる。
# 参考: soniox.com/docs/stt/concepts/language-identification
"enable_language_identification": True,
1つ上でも書いた通り、Sonioxでは言語の識別は自動で行われる。なので、この設定がなくても自動で文字起こしされるが、この設定を追加しておくと、各トークンにlanguageフィールドが追加され言語コードが含まれるようになる。
以下で使用した、マイクからの音声をリアルタイムに文字起こししてトークンをそのまま出力するミニマルなサンプルを使って試してみる。
サンプルの設定はこうなっている。
(snip)
config: dict = {
"api_key": api_key,
"model": "stt-rt-v3",
"audio_format": "pcm_s16le",
"sample_rate": args.sample_rate,
"num_channels": 1,
"enable_language_identification": True,
"enable_speaker_diarization": True,
"enable_endpoint_detection": True,
}
(snip)
enable_language_identificationを無効にする。あとややこしいのでenable_speaker_diarizationは削除した。
(snip)
config: dict = {
"api_key": api_key,
"model": "stt-rt-v3",
"audio_format": "pcm_s16le",
"sample_rate": args.sample_rate,
"num_channels": 1,
"enable_language_identification": False,
"enable_endpoint_detection": True,
}
(snip)
例文として 「こんにちは。」という発話を文字起こし。確定済みトークンだけ。
2025-10-28 20:51:55
{
"tokens": [
{
"text": "こ",
"start_ms": 1440,
"end_ms": 1680,
"confidence": 0.994,
"is_final": true
},
{
"text": "ん",
"start_ms": 1680,
"end_ms": 1740,
"confidence": 1,
"is_final": true
},
{
"text": "に",
"start_ms": 1800,
"end_ms": 1860,
"confidence": 0.999,
"is_final": true
},
{
"text": "ち",
"start_ms": 1860,
"end_ms": 1920,
"confidence": 0.999,
"is_final": true
},
{
"text": "は",
"start_ms": 2100,
"end_ms": 2160,
"confidence": 0.812,
"is_final": true
},
{
"text": "。",
"start_ms": 2280,
"end_ms": 2340,
"confidence": 0.993,
"is_final": true
}
],
"final_audio_proc_ms": 4800,
"total_audio_proc_ms": 4920
}
enable_language_identificationを有効にして再度実行。
2025-10-28 20:52:24
{
"tokens": [
{
"text": "こ",
"start_ms": 1740,
"end_ms": 1800,
"confidence": 0.994,
"is_final": true,
"language": "ja"
},
{
"text": "ん",
"start_ms": 1800,
"end_ms": 1800,
"confidence": 0.999,
"is_final": true,
"language": "ja"
},
{
"text": "に",
"start_ms": 1860,
"end_ms": 1920,
"confidence": 0.998,
"is_final": true,
"language": "ja"
},
{
"text": "ち",
"start_ms": 1920,
"end_ms": 1980,
"confidence": 1,
"is_final": true,
"language": "ja"
},
{
"text": "は",
"start_ms": 2160,
"end_ms": 2220,
"confidence": 0.783,
"is_final": true,
"language": "ja"
},
{
"text": "。",
"start_ms": 2340,
"end_ms": 2400,
"confidence": 0.98,
"is_final": true,
"language": "ja"
},
{
"text": "<end>",
"start_ms": 0,
"end_ms": 0,
"confidence": 0.999,
"is_final": true
}
],
"final_audio_proc_ms": 2880,
"total_audio_proc_ms": 3600
}
languageが追加され、言語(ja)が認識されていることがわかる。
動作原理
Sonioxでは言語識別は「トークン」単位で行われる。上記の例でもわかるように各トークンごとに言語コードがが付与されているのがわかる。ただし単語やトークンだけではなく、文全体での一貫性も踏まえて識別されるようになっている。
これを試すために、「こんにちは、Hello」 と発話してみる。こんにちはの後はポーズをあまり入れずにそのままHelloを続けるような感じで。Helloは英語の発話で。
2025-10-28 21:09:53
{
"tokens": [
{
"text": "こ",
"start_ms": 8880,
"end_ms": 8940,
"confidence": 0.997,
"is_final": true,
"language": "ja"
},
{
"text": "ん",
"start_ms": 8940,
"end_ms": 9000,
"confidence": 1,
"is_final": true,
"language": "ja"
},
{
"text": "に",
"start_ms": 9060,
"end_ms": 9120,
"confidence": 0.999,
"is_final": true,
"language": "ja"
},
{
"text": "ち",
"start_ms": 9120,
"end_ms": 9180,
"confidence": 1,
"is_final": true,
"language": "ja"
},
{
"text": "は、",
"start_ms": 9300,
"end_ms": 9360,
"confidence": 0.711,
"is_final": true,
"language": "ja"
},
{
"text": "h",
"start_ms": 9600,
"end_ms": 9660,
"confidence": 0.711,
"is_final": true,
"language": "ja"
},
{
"text": "ello",
"start_ms": 9840,
"end_ms": 9900,
"confidence": 0.896,
"is_final": true,
"language": "ja"
},
{
"text": "。",
"start_ms": 10080,
"end_ms": 10140,
"confidence": 0.903,
"is_final": true,
"language": "ja"
},
{
"text": "<end>",
"start_ms": 0,
"end_ms": 0,
"confidence": 0.997,
"is_final": true
}
],
"final_audio_proc_ms": 10680,
"total_audio_proc_ms": 11640
}
Helloはきちんと英語で文字起こしされているが、言語識別はjaとなっているのがわかる。
今度はこんにちは と Hello の間に少しポーズをおいてみる。
2025-10-28 21:11:55
{
"tokens": [
{
"text": "こ",
"start_ms": 1860,
"end_ms": 1920,
"confidence": 0.992,
"is_final": true,
"language": "ja"
},
{
"text": "ん",
"start_ms": 1920,
"end_ms": 1980,
"confidence": 1,
"is_final": true,
"language": "ja"
},
{
"text": "に",
"start_ms": 2040,
"end_ms": 2100,
"confidence": 0.999,
"is_final": true,
"language": "ja"
},
{
"text": "ち",
"start_ms": 2160,
"end_ms": 2220,
"confidence": 1,
"is_final": true,
"language": "ja"
},
{
"text": "は",
"start_ms": 2400,
"end_ms": 2460,
"confidence": 0.59,
"is_final": true,
"language": "ja"
},
{
"text": "。",
"start_ms": 2580,
"end_ms": 2640,
"confidence": 0.99,
"is_final": true,
"language": "ja"
},
{
"text": " Hell",
"start_ms": 4440,
"end_ms": 4440,
"confidence": 0.859,
"is_final": true,
"language": "en"
},
{
"text": "o.",
"start_ms": 4740,
"end_ms": 4800,
"confidence": 0.955,
"is_final": true,
"language": "en"
},
{
"text": "<end>",
"start_ms": 0,
"end_ms": 0,
"confidence": 1,
"is_final": true
}
],
"final_audio_proc_ms": 5280,
"total_audio_proc_ms": 5280
}
今度はHelloのチャンクはenとして認識されている。文と文の境界がはっきりするような場合はきちんと言語が個別に認識されるということね。
上記以外に注意すべき点は以下
- 精度向上のためには言語ヒントを使用すべき
- 一般的には、リアルタイムでの言語識別は低遅延という制約があり、モデルは識別に必要な十分なコンテキストを得られないため、以下のようなケースが起こり得る
- 言語識別に一時的に誤判定が起こる
- 音声が追加される→識別に必要なコンテキストが溜まる→言語タグが更新される
- Sonioxもおそらく例外ではないが、その前提においても可能な限りの高い信頼性を謳っている模様。
話者識別(話者ダイアライぜーション)
次は話者識別。音声内に複数の話者がいるようなケースで個別に識別する。
上のミニマルなサンプルコードだと、設定でenable_speaker_diarizationを有効にすれば良い。
(snip)
config: dict = {
"api_key": api_key,
"model": "stt-rt-v3",
"audio_format": "pcm_s16le",
"sample_rate": args.sample_rate,
"num_channels": 1,
"enable_speaker_diarization": True,
"enable_endpoint_detection": True,
}
(snip)
「こんにちは、こんにちは。」という感じで2回繰り返すが、それぞれの声色を変えてみる。
2025-10-28 21:57:36
{
"tokens": [
{
"text": "こ",
"start_ms": 2100,
"end_ms": 2160,
"confidence": 0.997,
"is_final": true,
"speaker": "1"
},
{
"text": "ん",
"start_ms": 2160,
"end_ms": 2160,
"confidence": 0.999,
"is_final": true,
"speaker": "1"
},
{
"text": "に",
"start_ms": 2160,
"end_ms": 2220,
"confidence": 1,
"is_final": true,
"speaker": "1"
},
{
"text": "ち",
"start_ms": 2280,
"end_ms": 2340,
"confidence": 1,
"is_final": true,
"speaker": "1"
},
{
"text": "は",
"start_ms": 2400,
"end_ms": 2460,
"confidence": 0.701,
"is_final": true,
"speaker": "1"
},
{
"text": "。",
"start_ms": 2580,
"end_ms": 2640,
"confidence": 0.982,
"is_final": true,
"speaker": "1"
},
{
"text": "<end>",
"start_ms": 0,
"end_ms": 0,
"confidence": 0.997,
"is_final": true
},
{
"text": " ",
"start_ms": 2880,
"end_ms": 2880,
"confidence": 1,
"is_final": false,
"speaker": "2"
}
],
"final_audio_proc_ms": 3120,
"total_audio_proc_ms": 3360
}
--------------------
(snip)
--------------------
2025-10-28 21:57:36
{
"tokens": [
{
"text": " ",
"start_ms": 2880,
"end_ms": 2880,
"confidence": 1,
"is_final": true,
"speaker": "2"
},
{
"text": "こ",
"start_ms": 2940,
"end_ms": 3000,
"confidence": 0.997,
"is_final": true,
"speaker": "2"
},
{
"text": "ん",
"start_ms": 3000,
"end_ms": 3060,
"confidence": 1,
"is_final": true,
"speaker": "2"
},
{
"text": "に",
"start_ms": 3060,
"end_ms": 3120,
"confidence": 0.998,
"is_final": true,
"speaker": "2"
},
{
"text": "ち",
"start_ms": 3120,
"end_ms": 3180,
"confidence": 0.999,
"is_final": true,
"speaker": "2"
},
{
"text": "は",
"start_ms": 3360,
"end_ms": 3420,
"confidence": 0.98,
"is_final": true,
"speaker": "2"
},
{
"text": "。",
"start_ms": 3480,
"end_ms": 3540,
"confidence": 0.992,
"is_final": true,
"speaker": "2"
},
{
"text": "<end>",
"start_ms": 0,
"end_ms": 0,
"confidence": 1,
"is_final": true
}
],
"final_audio_proc_ms": 4080,
"total_audio_proc_ms": 4080
}
話者識別を有効化すると、各トークンにspeakerが付与され、話者の数だけIDが追加される。今回の場合だと1回目はspeaker1、2回目はspeaker2となっているのがわかる。
注意事項は以下
- 一般的には、リアルタイムでの言語識別は低遅延という制約があり、モデルは識別に必要な十分なコンテキストを得られないため、以下のようなケースが起こり得る
- 非同期に比べて、話者識別の誤判定が起こりやすい
- 音声が追加される→識別に必要なコンテキストが溜まる→スピーカータグが更新される
- Sonioxもおそらく例外ではないが、その前提においても可能な限りの高い信頼性を謳っている
- ライブ会議・カンファレンス・通話・会話AIなどのユースケースが提示されている
- 1回のセッションでサポートされる話者数は最大15
- 声が類似している話者がいる場合は認識精度が低下する可能性がある
- 上にも書いてあるが、非同期のほうが話者識別の精度は高い。それに比べるとリアルタイムは精度が若干低下することを前提にする。
コンテキスト
音声の文脈情報を与えることで、文字起こし・翻訳の精度を向上させるのがコンテキストという機能。以下のようなユースケースが想定されている。
- 専門分野で専門用語が含まれる場合
- 独自のボキャブラリーや翻訳の好みなどを反映したい
Sonixのサンプルコードでは以下のような例となっていて、ヘルスケアに関連した内容になっていることがわかる。
# コンテキストを設定すると、モデルがドメインを理解し、重要語句の認識や、カスタムの語彙・翻訳設定を適用できる
# 参考: soniox.com/docs/stt/concepts/context
"context": {
"general": [
{"key": "domain", "value": "Healthcare"},
{"key": "topic", "value": "Diabetes management consultation"},
{"key": "doctor", "value": "Dr. Martha Smith"},
{"key": "patient", "value": "Mr. David Miller"},
{"key": "organization", "value": "St John's Hospital"},
],
"text": "Mr. David Miller visited his healthcare provider last month for a routine follow-up related to diabetes care. The clinician reviewed his recent test results, noted improved glucose levels, and adjusted his medication schedule accordingly. They also discussed meal planning strategies and scheduled the next check-up for early spring.",
"terms": [
"Celebrex",
"Zyrtec",
"Xanax",
"Prilosec",
"Amoxicillin Clavulanate Potassium",
],
"translation_terms": [
{"source": "Mr. Smith", "target": "Sr. Smith"},
{"source": "St John's", "target": "St John's"},
{"source": "stroke", "target": "ictus"},
],
},
コンテキストは上記の通り context オブジェクトで指定するが、4つのセクションで構成される。
| セクション | 型 | 説明 |
|---|---|---|
general |
JSONオブジェクトの配列 | 構造化されたキー・バリュー情報(ドメイン、トピック、意図など) |
text |
文字列 | 長めの自由形式の背景テキストや関連ドキュメント |
terms |
文字列の配列 | ドメイン固有または一般的でない単語 |
translation_terms |
JSONオブジェクトの配列 | あいまいな用語に対するカスタム翻訳 |
なお、どのセクションも必須ではなくオプション。なので、関連するものだけを定義することも可能。
各セクションの詳細には以下。
-
general- 音声の基本的な文脈情報。モデルの認識のベースとなり、それに応じてボキャブラリーなどが調整される。
- 関連するメタデータ(分野、トピック、意図、参加者の名前、組織、設定、場所など)をkey-valueで指定する。
-
text-
generalのさらに詳しい説明 - たとえば、過去の会話履歴、参照文書、背景情報の要約、会議の議事録、など、非構造化・長文のテキストで指定する。
-
-
terms- 音声データに含まれる特殊な用語を定義することで「文字起こし」の精度を向上させる
- 特定業界・分野の専門用語、ブランド名や製品名などの固有名詞、一般的に使用されることが少ない造語などをリストで指定する。
-
translation_terms-
termsと同じく、音声データに含まれる特殊な用語を定義することで「翻訳」の精度を向上させる - 専門用語、エンティティ名、独自・複数の解釈が可能な用語、比喩表現・慣用句など文字通りの意味とは異なる表現を、翻訳前・翻訳後のマッピングで指定する
-
非同期APIのサンプルコードを試した際に、とある音声アプリ開発サービスについて自分が主催した勉強会の音声を文字起こししたが、これにコンテキストを追加してみる。
なお、サンプルコードに記載されているヘルスケアのコンテキストのまま(つまり音声の内容とは合っていない)場合の文字起こし結果を比較用に再掲しておく。
はい、じゃあ始めます。ちょっとまだ来られてない方もいらっしゃるんですけど。ボイスランチ、JP始めます。皆さん、日曜日。はーい。はい、日曜日にお集まりいただきましてありがとうございます。えーと、今日久しぶりにですね、オフラインということで、えーと今日はですね、スペシャルなゲストをお二人来ていただいておりますということで。はい、えーと今日ちょっとトピックにまいりますけれども、えーとボイスフローのCEOであるブレゼン・リームさんと、あと、えーとセールスフォースの、えーと株式会社ジョーダン・デザインのディレクターであるグレッグ・ベネットさんに来ていただいてまーす。ということで、日本に来ていただいてありがとうございます。はい。で、今日はちょっとこのお二人にまたあとでいろいろと聞こうという、えーとコーナーがありますので、えーとそこでまたいろいろと聞きたいと思います。で、今日のアジェンダなんですけども、えーとちょっと時間過ぎちゃいましたが、まず最初にボイスランチJPについてっていうとこ、あと会場のとこですね、少しご説明させていただいて、1つ目のセッションで、えーとまず私のほうから、えーとボイスフローの2022年の、えーと新機能とかですね、そのへんの話を少しさせていただいて、そのあと、えーと2つ目のセッションで、えーとブレゼンさんとグレッグさんにいろいろカンバセーショナルデザインですね、について何でも聞こうぜみたいなところを予定しております。で、そのあと15時から、えーと15時で一旦は終了という形でさせていただいて、ちょっと一応ボイスランチJP、確か記念撮影は必須ですよね。なのでそれだけさせていただいて、そのあとちょっと1時間ぐらい、あの簡単に、あのお菓子と飲み物を用意してますので、懇親会というのをそのままさせていただこうと思っています。で、えーとボイスランチJPについてなんですけども、えーとボイスランチはボイスUIとか音声関連ですね、そういった技術に、えーと実際に携わってる人、もしくは興味がある人たちのためのグローバルなコミュニティという形になっていて、えーとボイスランチの、えーと日本リージョンという形がボイスランチJPになってますと。で、えーと過去もまあずっとやってますけど、オンラインオフラインでいろんな音声の、えーとデザインだったり技術だったりっていうところで情報とかを共有して、みんなで業界盛り上げていこうぜというようなことでやっております。で、今日の、えーとハッシュタグですね、えーと#ボイスランチJPでいろいろと自由にシェアしてください。で、あと会場ですね、えーと今回、えーとグラニカ様のご厚意で利用させていただいてます。ありがとうございます。で、ぜひこちらもシェアをお願いしたいですと。で、今日と配信のところもいろいろとやっていただいてますので、非常に感謝しております。で、ちょっと今、あのごめんなさい、抜けた。今あの、えーとコロナで、えーと会場に来られる方とかもあまりいないということでされてないんですけれども、あの通常はなんかこうでIoT機器のとかガジェットとかを展示されているようなので、えーとそういったものがあるとき、こん、今度ですね、また体験してみていただければなと思っていますというとこで、あとすいません、えーとトイレがこちら、で、あとタバコ吸われてる方はこちらのところになってますんで、よろしくお願いします。はい、ということで最初の挨拶はこれで。じゃあまず私のほうのセッションからさせていただきますというとこで、ボイスフローアップデート2022というところで、えーと今年の新機能について少しお話をします。えーと自己紹介です。えーと清水と申します。えーと神戸でインフラのエンジニアをやってましたので、えーと普段はKubernetesとかAWSとかTerraformとかをいじってまして、最近ちょっとフリーランスになりました。で、えーとちょっと調べてみたらボイスフローを一番最初に始めたのが2019年の頭ぐらいなんで、大体4年弱ぐらいですね、いろいろと触ってまして。あと、えーと音声関連のコミュニティのとこでは、えーとボイスランチJP、今回のやつですね、えー以外に、えーとAZAG、Amazon Alexa、Japan User Groupとか、あと、えーとボイスフローの、えーと日本語ユーザーグループということでVFJUGというのをやっています。はい、えーと日本語コミュニティのほうはフェイスブックのほうで、えーとやってますので、もしよろしければ見ていただければなと思いますと。あと2年ぐらい前にですね、えーと技術書店のほうで、ここに今日スタッフで来ていただいてる皆さんとですね、一緒にあの同人誌作ろうぜということで、えーと作ったんですけれども、もうこれちょっと2年ぐらい経って中身がだいぶ古くなってしまっているので、すでにちょっと販売は終了しております。今日ちょっと持ってきたかったんですけど、すいません、忘れてしまいました。はい、なんでこういうこともやっていますと。
公式のサンプルコード soniox_async.py のコンテキストを以下のように書き換えてみる。
"context": {
"general": [
{"key": "domain", "value": "音声アプリ開発"},
{"key": "topic", "value": "Voiceflowの2025年の主なアップデート内容"},
{"key": "product", "value": "Voiceflow"},
{"key": "organization", "value": "Voice Lunch JP"},
],
"text": (
"日本における音声アプリ開発者のコミュニティ「Voice Lunch JP」のイベントにおいて、"
"GUIで音声アプリ開発が可能なサービス「Voiceflow」の2022年の主なアップデート内容について"
"発表されている。"
"ゲストは、Voiceflow CEOのブレイデン・リーム氏、Salesforce カンバセーショナルデザインディレクターのグレッグ・ベネット氏。"
),
"terms": [
"Voiceflow",
"Salesforce",
"ブレイデン・リーム",
"グレッグ・ベネット",
"Voice Lunch JP",
"AAJUG",
"VFJUG",
"技術書典",
],
},
文字起こしした結果は以下。
はい、じゃあ始めます。ちょっとまだ来られてない方もいらっしゃるんですけど、Voice Lunch JP始めます。皆さん、日曜日... はーい。はい、日曜日にお集まりいただきましてありがとうございます。えーと、今日は久しぶりにですね、オフラインということで、えーと、今日はですね、スペシャルなゲストをお二人来ていただいておりますということで。はい、えーと、今日ちょっとトピックにまいりますけれども、えーと、VoiceflowのCEOであるブレイデン・リームさんと、あと、えーと、Salesforceの、えーと、カンバセーショナルデザインのディレクターであるグレッグ・ベネットさんに来ていただいてまーす。ということで、日本に来ていただいてありがとうございます。はい。で、今日はちょっとこのお二人にまたあとでいろいろと聞こうという、えーと、コーナーがありますので、えーと、そこでまたいろいろと聞きたいと思います。で、今日のアジェンダなんですけども、えーと、ちょっと時間過ぎちゃいましたが、まず最初にVoice Lunch JPについてっていうとこ、あと会場のとこですね、少しご説明させていただいて、1つ目のセッションで、えーと、まず私のほうから、えーと、Voiceflowの2022年の、えーと、新機能とかですね、そのへんの話を少しさせていただいて、そのあと、えーと、2つ目のセッションで、えーと、ブレイデンさんとグレッグさんにいろいろカンバセーショナルデザインですね、について何でも聞こうぜみたいなところを予定しております。で、そのあと15時から、えーと、15時で一旦は終了という形でさせていただいて、ちょっと一応Voice Lunch JP、確か記念撮影は必須ですよね。なので、それだけさせていただいて、そのあとちょっと1時間ぐらい、あの、簡単に、あの、お菓子と飲み物を用意してますので、懇親会というのをそのままさせていただこうと思っています。で、えーと、Voice Lunch JPについてなんですけども、えーと、Voice LunchはVoice UIとか音声関連ですね、そういった技術に、えーと、実際に携わってる人、もしくは興味がある人たちのためのグローバルなコミュニティという形になっていて、えーと、Voice Lunchの、えーと、日本リージョンという形がVoice Lunch JPになってますと。で、えーと、過去もまあずっとやってますけど、オンラインオフラインでいろんな音声の、えーと、デザインだったり技術だったりっていうところで情報とかを共有して、みんなで業界盛り上げていこうぜというようなことでやっております。で、今日の、えーと、ハッシュタグですね、えーと、#VoiceLunchJPでいろいろと自由にシェアしてください。で、あと会場ですね、えーと、今回、えーと、グラニカ様のご厚意で利用させていただいてます。ありがとうございます。で、ぜひこちらもシェアをお願いしたいですと。で、今日と配信のところもいろいろとやっていただいてますので、非常に感謝しております。で、ちょっと今、あの、ごめんなさい、抜けた。今、あの、えーと、コロナで、えーと、会場に来られる方とかもあまりいないということでされてないんですけれども、あの、通常はなんかこう、で、IoT機器のとかガジェットとかを展示されているようなので、えーと、そういったものがあるとき、こ、今度ですね、また体験してみていただければなと思っていますというとこで、あと、すいません、えーと、トイレがこちら。で、あとタバコ吸われてる方はこちらのところになってますんで、よろしくお願いします。はい、ということで最初の挨拶はこれで。じゃあまず私のほうのセッションからさせていただきますというとこで、VoiceFlowアップデート2022というところで、えーと、今年の新機能について少しお話をします。えーと、自己紹介です。えーと、清水と申します。えーと、神戸でインフラのエンジニアをやってましたので、えーと、普段はKubernetesとかAWSとかTerraformとかをいじってまして、最近ちょっとフリーランスになりました。で、えーと、ちょっと調べてみたらVoiceFlowを一番最初に始めたのが2019年の頭ぐらいなんで、大体4年弱ぐらいですね、いろいろと触ってまして。あと、えーと、音声関連のコミュニティのとこでは、えーと、Voice Lunch JP、今回のやつですね、えー、以外に、えーと、AAJUG、Amazon Alexa、Japan User Groupとか、あと、えーと、VoiceFlowの、えーと、日本語ユーザーグループということでVFJUGっていうのをやっています。はい、えーと、日本語コミュニティのほうはフェイスブックのほうで、えーと、やってますので、もしよろしければ見ていただければなと思いますと。あと2年ぐらい前にですね、えーと、技術書典のほうで、ここに今日スタッフで来ていただいてる皆さんとですね、一緒に、あの、同人誌作ろうぜということで、えーと、作ったんですけれども、もうこれちょっと2年ぐらい経って中身がだいぶ古くなってしまっているので、すでにちょっと販売は終了しております。今日ちょっと持ってきたかったんですけど、すいません、忘れてしまいました。はい、なんでこういうこともやっていますと。
人名や固有名詞などが確かにだいぶ改善されているのがわかる。
ただし、必ずしも設定どおりになるかどうかはやってみないとわからないところで、上記は実は設定をいろいろ試してみて一番良かった結果。設定によっては、"Voiceflow" を "Voice Lunch" と逆に誤認識してしまってたりもしたので、このあたりは音声や話者の発話の質(すまん、自分の滑舌が悪かった・・・)などによっても変わってくるとは思うし、実際に試行錯誤が必要かなと思う。
コンテキストに関するコツや注意は以下。
-
generalセクション-
domainとtopicを必ず記載する。これにより精度が最大化する。 - なお、キーは日本語で
ドメイン・トピックとしても特にエラーは起きないが、体感的には英語で指定したほうが良さそうな印象。 - キーと値のペアは10組以下に留めるのが理想
-
-
termsセクションでは、スペルや大文字小文字が曖昧な固有名詞などを記載すると、一貫性が上がる -
translationセクションでは、名前やブランド名など、翻訳においても表記が同じ、という場合にも使用できる。例:"St John's" → "ST John's" - コンテキストは最大8000トークン(約10000文字)。これを超えるとAPIはエラーを返す。
タイムスタンプ
文字起こしのトークンにはデフォルトでタイムスタンプが記録される。これを使うと、実際の音声と文字起こしのタイミングを正確に同期できるため、たとえば字幕などで活用できる。
上の方で試した結果を再掲。こんな感じで単語もしくはサブワード(日本語の場合はほぼ1文字)でトークンが返されるが、それにタイムスタンプが付与される。
2025-10-28 21:11:55 { "tokens": [ { "text": "こ", "start_ms": 1860, "end_ms": 1920, "confidence": 0.992, "is_final": true, "language": "ja" }, { "text": "ん", "start_ms": 1920, "end_ms": 1980, "confidence": 1, "is_final": true, "language": "ja" }, { "text": "に", "start_ms": 2040, "end_ms": 2100, "confidence": 0.999, "is_final": true, "language": "ja" }, { "text": "ち", "start_ms": 2160, "end_ms": 2220, "confidence": 1, "is_final": true, "language": "ja" }, { "text": "は", "start_ms": 2400, "end_ms": 2460, "confidence": 0.59, "is_final": true, "language": "ja" }, { "text": "。", "start_ms": 2580, "end_ms": 2640, "confidence": 0.99, "is_final": true, "language": "ja" }, { "text": " Hell", "start_ms": 4440, "end_ms": 4440, "confidence": 0.859, "is_final": true, "language": "en" }, { "text": "o.", "start_ms": 4740, "end_ms": 4800, "confidence": 0.955, "is_final": true, "language": "en" }, { "text": "<end>", "start_ms": 0, "end_ms": 0, "confidence": 1, "is_final": true } ], "final_audio_proc_ms": 5280, "total_audio_proc_ms": 5280 }
-
text: 認識されたトークンテキスト。 -
start_ms:音声ストリームにおける対象トークンの開始時刻(ミリ秒単位) -
end_ms: 音声ストリームにおける対象トークンの終了時間(ミリ秒単位)
信頼度スコア
文字起こしのトークンにはデフォルトで認識結果の信頼度スコア(confidence)が記録され、0.0(信頼度が低い)〜1.0(信頼度が高い)となる。
信頼度が低い場合は以下の要因が考えられる。
- 背景ノイズ
- 発音に強い訛りがある
- 発音が不明瞭
- 語句が一般的ではない
これらを改善することができれば、認識精度が向上する可能性がある。
その他
ここまでで一通りの内容をカバーできたと思う。その他参考になりそうなリンクなど。
APIリファレンス
非同期の文字起こしAPI、リアルタイムのWebSocket API以外に、認証やファイルアップロード、モデル情報を取得するAPIなどがある。
デモアプリ
リアルタイム文字起こし・翻訳のリファレンス実装として以下が用意されている。
- Pythonサーバ
- Reactフロントエンド(Webアプリ)
- React Nativeフロントエンド(モバイルアプリ)
これらはGitHubで公開されている
リアルタイムAPIでの構成
リアルタイムAPIを2つの構成案が紹介されている。
1つ目は直接SonioxのWebSocket APIに接続するもの。

referred from https://soniox.com/docs/stt/guides/direct-stream
これは主にブラウザ向けで、Web用に用意されているSDKを使えば、
- 認証用のサーバ(これは自分で用意)、クライアントからリクエストがあれば、一時的なAPIキーを発行(REST API経由)
- マイク入力の取得
- WebSocket接続管理
を行ってくれるらしい。中間に何も挟まずSonioxのWebSocket APIと接続するので、ブラウザ経由で高速なリアルタイム音声認識のユースケースで使用する。
この一時的なAPIキーには期限を指定できるが、一時的なAPIキーはWebSocket接続の確立のためだけに使われ、接続確立後は接続が有効な間は維持される、とあるので、キーそのものの期限なのだろう。接続時間を制限するものではなさそう。
あと、一時的なAPIキーの発行にはクオータがあり、無尽蔵に発行できるというわけではなさそう。これはコンソールで確認できるが、自分の設定では、1分辺り100リクエストまで、となっていた。上限の緩和申請はできそうに見える。
もう一つは中間にWebSocketのプロキシサーバを挟む方式。

referred from https://soniox.com/docs/stt/guides/proxy-stream
中間にプロキシを挟む分、リアルタイム性はやや減少するが、音声データ・文字起こし結果を検査したい、変換したい、保存したい、というようなケースで有用。自前で認証を用意したい場合なんかもいいかもしれない。
どちらの場合もサンプルコードが用意されているので参考になる。
Web SDK
リアルタイムAPIでの構成で出てきたWeb SDKについて。npmパッケージで提供されている様子。SDKのパラメータやサンプルコードなどへのリンクもある。
インテグレーション
他のプラットフォームとのインテグレーションについて。LiveKit / Pipecat / Twilio などのプラットフォームとのインテグレーションが紹介されている。
上記以外に、コミュニティベースでのインテグレーションはここにリストされるみたいで、個人開発者が作成したPython SDKが紹介されていた。
対応しているのは非同期APIのみの様子。
セキュリティとプライバシー
第三者機関の認証やデータの取扱などについて書かれている。
まとめ
Sonioxについて一通り見てきたが、非常に良さげ。
- 実際にリアルタムの文字起こしを試してみた印象だと非常に高速。
- ストリーミング文字起こしは中間認識→最終認識というパターンがほとんどだが、中間→最終にちょっと時間がかかるものが多い印象。それらに比べると非常に速いと思う
- 精度も悪くない
- 英語だと Deepgram / Gradia あたりが低遅延で高精度なようだが、過去試した限り、Deepgramは日本語の精度があまりよくない、Gradiaはそこまで低遅延とは感じなかった。
- それに比べるとSonioxは日本語の精度が良いように思える。コンテキストなどを使えばより精度向上が見込めるのも良い
- ただしこれは時間の経過とともに変わっていくため、適宜検証したうえで判断した方が良さそう。
- 安い
- 自分が調べた中ではおそらく最安レベルではないかと。
- 最初に$200のクレジットが付いてくるのも良い。
v2を試したときには、中間で十分な精度が結構出ていたのだけど、中間→最終の遅延が大きい、短縮はできるけどちょっとややこしい、という感じだったのが、v3で非常に使いやすくなっていて、精度・速度ともに十分ではないかと感じる。
これは実際の開発でも使ってみたいと感じたし、今後も期待したい。