会議の録音から議事録を作っているときに、いちばん面倒なのは「誰が話したか」をテキストに乗せる作業ではないでしょうか。文字起こし自体は Gemini に任せれば一瞬なのに、話者の切り替わりだけは録音を聞き返さないと特定できません。私もこの工程で何度も時間を溶かしてきました。
今回は、Gemini API のマルチモーダル音声理解を使って、専用の話者分離ライブラリを入れずに「誰が・いつ・何を話したか」を構造化データとして取り出す方法を整理します。本格的なダイアリゼーションには pyannote のような専用モデルが向いていますが、ちょっとした会議ログやポッドキャストの抜粋を素早く扱いたい用途であれば、Gemini ひとつで十分実用になります。
なぜ Gemini API でも話者分離ができるのか
Gemini 2.5 Pro / Flash は音声を直接モデルに入力できるマルチモーダル設計になっています。専門のダイアリゼーション・モデルではないものの、「声の特徴の違い」「話の流れ」「文脈」をふまえて発話者をある程度区別できます。重要なのは、モデルが純粋に音声の声紋を分析しているわけではなく、声の質感と会話の流れの両方を手がかりにしている点です。そのため、参加者の名前や役割をプロンプトでヒントとして渡せるシナリオでは、想像以上に良い結果になります。
逆に、声がよく似ている話者ばかりの会議や、雑音だらけのフィールド録音では正答率は急激に落ちます。pyannote.audio や AssemblyAI の Speaker Diarization のような専用ツールは、声紋ベクトルを抽出して数学的にクラスタリングするので、こうしたケースでは明確に強くなります。Gemini はあくまで「文脈で補える領域」が得意な相棒、と捉えると判断を誤らずに済みます。
最小構成のコード — 録音ファイルを話者ラベル付き JSON で返す
下記は Python SDK(google-generativeai)でローカルの音声ファイルを読み込み、話者ラベルとタイムスタンプ付きの発話リストを返す最小構成です。Pythonバージョンは 3.10 以上を想定しています。
# pip install google-generativeai>=0.8.0
import os
import json
import google.generativeai as genai
genai.configure(api_key=os.environ["GEMINI_API_KEY"])
AUDIO_PATH = "meeting.m4a" # m4a/mp3/wav/flac/ogg などに対応
# 1) 音声ファイルをアップロード(25MB を超える場合は File API が必須)
audio_file = genai.upload_file(AUDIO_PATH)
# 2) 参加者リストをプロンプトに含めると識別精度が大きく上がる
participants = ["田中(PM)", "佐藤(エンジニア)", "Lee(デザイナー)"]
prompt = f"""
あなたは会議録音のダイアリゼーション担当です。
参加者: {", ".join(participants)}
タスク:
- 音声に含まれる発話を時系列に並べる
- 話者は上記参加者リストの中から選ぶ。判定不能な発話は "unknown" とする
- 各発話に開始時刻(秒)と発言テキストを付ける
- 雑音や相槌は省略する
次のJSONスキーマで返してください(前後に文字を出力しない):
{{
"segments": [
{{ "speaker": "...", "start_sec": 0.0, "text": "..." }}
]
}}
"""
model = genai.GenerativeModel(
"gemini-2.5-pro",
generation_config={
"temperature": 0.2,
"response_mime_type": "application/json",
},
)
response = model.generate_content([prompt, audio_file])
data = json.loads(response.text)
for seg in data["segments"][:5]:
print(f"[{seg['start_sec']:>6.1f}s] {seg['speaker']}: {seg['text']}")response_mime_type を application/json にしておくと、モデルが余計な前置きを吐かずに JSON だけを返すようになります。期待される出力は次のような形です。
[ 0.0s] 田中(PM): お疲れさまです、本日のレビューを始めます。
[ 8.4s] 佐藤(エンジニア): 先週の検証ですが、推論コストは想定より2割低くなりました。
[ 21.7s] Lee(デザイナー): 画面の遷移は前回のレビューを反映済みです。
[ 35.2s] 田中(PM): では、リリース判定の基準を確認しましょう。
[ 47.0s] unknown: (咳払い)
実装上のポイントは、温度を低めに設定すること(出力の揺れが目に見えて減ります)と、音声ファイルが 25MB を超える場合に File API ガイド で扱う前処理を組み込むこと、の2点です。
プロンプトで結果を底上げする3つの工夫
私が実際に運用してみて効いたのは、いずれも「モデルに余計な推測をさせない」方向の工夫でした。
ひとつめは 参加者リストを必ず渡す こと。「Speaker A / B / C」のような匿名ラベルだと、モデルは話の途中で別人にスイッチするとうまく追従できません。役割(PM・エンジニア・営業など)まで渡すと、専門用語の流れから話者を推定する精度が一段上がります。
ふたつめは 判定不能を許容する こと。「全員にラベルを付けろ」と命じると無理やり当てはめて誤答が増えます。unknown を許すと、自信のない短い発話だけが弾かれて全体の信頼度が上がります。
みっつめは 音声を 30 分以内に切る こと。Gemini 2.5 Pro は長い音声も受け付けますが、私の経験上、30 分を超えると話者の取り違えが増え始めます。長尺の会議は議題ごとに分割し、後から JSON を結合する方が実用的です。出力スキーマは JSON モード・構造化出力ガイド と組み合わせると安定します。
専用ダイアリゼーションツールとの使い分け
「結局、pyannote と Gemini はどっちを選ぶべきか」という質問をよくいただきます。私はおおむね次の基準で使い分けています。
- Gemini API が向くケース: 参加者が少数(2〜4名)で名前や役割が事前に分かっている、文脈の理解が重要、まずは1日で動くものを作りたい、コストを Gemini に集約したい
- pyannote / AssemblyAI が向くケース: 参加者が多数(5名以上)で誰が誰か事前に分からない、似た声質の話者が混ざる、長時間の音声を機械的に処理する、声紋ベースのクラスタリング精度が必要
社内ミーティングや少人数のインタビューであれば、Gemini だけで実用品質に届くケースがほとんどです。一方、コールセンターやイベント収録のような大量・多人数の音声は、専用ダイアリゼーションでセグメントを切ってから、各セグメントを Gemini に投げて要約・抽出するハイブリッド構成が安定します。
ダイアリゼーションそのものをさらに掘り下げたい場合は、音声理解の基本ガイド と Python で音声を文字起こしして要約する記事 を組み合わせると、文字起こし→話者分離→要約の一連のパイプラインを自分の環境で組み立てられます。
音声処理を本格的に
全体を振り返って — まずは手元の30分音声で試す
話者分離は「専用ツールを導入しないと無理」と思い込まれがちですが、参加者があらかじめ分かっている会議やインタビューであれば、Gemini API だけで十分実用に届きます。今日まず試すなら、手元にある30分以内の会議録音で上記コードを動かしてみてください。参加者リストを渡したときと渡さなかったときの精度差を見ると、プロンプトの効き方を体感できるはずです。
その上で、要件に合わない部分(多人数・声質が近い・長尺)が見えてきたら、そこだけ pyannote や AssemblyAI に置き換えるという順序が、実装コストを最小化する近道です。