GEMINI LABEN
FLASH36 — 7月21日公開のGemini 3.6 Flashは出力トークンが約17%少なく、3.5 Flashより低価格です。コード編集の余計な書き換えや実行ループも減っていますCYBER — Gemini 3.5 Flash Cyberは脆弱性の発見・検証・修正パッチ作成に絞った軽量モデルですCOMPUTER — Computer UseがGemini APIとGemini Enterpriseの組み込みクライアントサイドツールとして利用できるようになりましたSPARK — Gemini Sparkの日本語提供が7月16日に始まりました。Google AI Ultraプランのユーザーから順次展開されていますPARALLEL — Sparkが複数の参照ソースを並行処理できるようになり、Docs・Sheets・Slidesでの画像追加や編集を代行できる範囲も広がりましたSTUDENT — 日本を含む4か国で18歳以上の学生向け無料アップグレードが提供され、Google AI ProとNotebookLM、2TBのストレージが使えますFLASH36 — 7月21日公開のGemini 3.6 Flashは出力トークンが約17%少なく、3.5 Flashより低価格です。コード編集の余計な書き換えや実行ループも減っていますCYBER — Gemini 3.5 Flash Cyberは脆弱性の発見・検証・修正パッチ作成に絞った軽量モデルですCOMPUTER — Computer UseがGemini APIとGemini Enterpriseの組み込みクライアントサイドツールとして利用できるようになりましたSPARK — Gemini Sparkの日本語提供が7月16日に始まりました。Google AI Ultraプランのユーザーから順次展開されていますPARALLEL — Sparkが複数の参照ソースを並行処理できるようになり、Docs・Sheets・Slidesでの画像追加や編集を代行できる範囲も広がりましたSTUDENT — 日本を含む4か国で18歳以上の学生向け無料アップグレードが提供され、Google AI ProとNotebookLM、2TBのストレージが使えます
記事一覧/API / SDK
API / SDK/2026-03-29上級

Gemini Live API で感情認識音声アプリを構築する

Gemini 3.1 Flash Live の Live API を使い、ユーザーの感情をリアルタイムで分析・応答する音声アプリケーションを構築する方法を、設計パターンから実装まで体系的に解説します。

gemini-api280live-api4voice-appemotion-recognitionreal-time2python103

取り組みの背景 — 感情を理解する音声アプリの時代

Gemini 3.1 Flash Live の登場により、「ユーザーの感情を理解して応答を変える」音声アプリケーションの構築が現実的になりましました。従来の音声AIは発話内容のテキスト解析が中心でしたが、Flash Live は声の高さ・速度・抑揚といった音響特徴から感情を推定する能力を備えています。

前提条件と環境構築

必要な環境

  • Python 3.11 以上
  • Google AI Studio のAPIキー(Gemini Live API プレビューへのアクセス権が必要)
  • pyaudio または sounddevice(マイク入力用)
  • WebSocket 対応ライブラリ

セットアップ

# 必要なライブラリのインストール
pip install google-generativeai pyaudio websockets numpy
 
# 環境変数の設定
export GEMINI_API_KEY="YOUR_GEMINI_API_KEY"

Live API のアーキテクチャ理解

通信モデル

Gemini Live API はWebSocketベースの双方向リアルタイム通信を採用しています。HTTPのリクエスト/レスポンスモデルとは異なり、音声データを連続的にストリーミングしながら、同時に応答を受け取ることができます。

[クライアント] ←WebSocket→ [Gemini Live API]
    │                           │
    ├─ 音声チャンク送信 ──────→ │
    │                           ├─ リアルタイム解析
    ├─ 音声チャンク送信 ──────→ │
    │                           ├─ 感情推定 + テキスト化
    │ ←───── 応答(音声+テキスト)┤
    │                           │

セッションライフサイクル

Live API のセッションは以下のライフサイクルで動作します。

  • 接続(Connect): WebSocket接続を確立し、モデルとセッション設定を送信
  • 設定(Setup): 音声形式、応答モダリティ、声のプリセットを設定
  • ストリーミング(Stream): 音声チャンクの送受信を継続
  • 切断(Disconnect): セッションを終了しリソースを解放

基本実装: リアルタイム音声会話

Step 1: セッションの確立

import google.generativeai as genai
import os
 
genai.configure(api_key=os.environ["GEMINI_API_KEY"])
 
model = genai.GenerativeModel("gemini-3.1-flash-live")
 
# セッション設定
session_config = {
    "response_modalities": ["AUDIO", "TEXT"],
    "speech_config": {
        "voice_config": {
            "prebuilt_voice_config": {
                "voice_name": "Aoede"
            }
        }
    },
    "system_instruction": """
    あなたは感情に配慮した対話アシスタントです。
    ユーザーの声のトーンや話し方から感情を推定し、
    それに応じた口調と内容で応答してください。
    焦っている場合は簡潔に、落ち込んでいる場合は
    優しく励ますように応答します。
    """
}
 
session = model.start_live_session(config=session_config)
print("Session established")
# 出力: Session established

Step 2: 音声入出力のハンドリング

import pyaudio
import numpy as np
import threading
 
# オーディオ設定
RATE = 16000       # サンプリングレート(16kHz)
CHUNK = 1024       # チャンクサイズ
FORMAT = pyaudio.paInt16
CHANNELS = 1
 
audio = pyaudio.PyAudio()
 
# マイク入力ストリーム
input_stream = audio.open(
    format=FORMAT,
    channels=CHANNELS,
    rate=RATE,
    input=True,
    frames_per_buffer=CHUNK
)
 
# スピーカー出力ストリーム
output_stream = audio.open(
    format=FORMAT,
    channels=CHANNELS,
    rate=RATE,
    output=True,
    frames_per_buffer=CHUNK
)
 
def send_audio(session):
    """マイクからの音声をLive APIに送信"""
    while True:
        data = input_stream.read(CHUNK, exception_on_overflow=False)
        audio_array = np.frombuffer(data, dtype=np.int16)
 
        # 無音検出(閾値以下はスキップ)
        if np.abs(audio_array).mean() < 100:
            continue
 
        session.send_audio(data)
 
def receive_response(session):
    """Live APIからの応答を受信・再生"""
    for response in session.receive():
        if response.audio:
            output_stream.write(response.audio)
        if response.text:
            print(f"[Gemini] {response.text}")
 
# 送受信を別スレッドで並行実行
send_thread = threading.Thread(target=send_audio, args=(session,))
recv_thread = threading.Thread(target=receive_response, args=(session,))
send_thread.start()
recv_thread.start()

感情認識レイヤーの設計パターン

Flash Live の感情認識能力を活用するには、システムプロンプトの設計と応答制御の2つのレイヤーで工夫が必要です。

パターン1: システムプロンプト駆動型

最もシンプルなアプローチです。システムプロンプトに感情対応のルールを記述し、モデルの内部判断に委ねます。

EMOTION_AWARE_PROMPT = """
あなたは共感力の高い対話アシスタントです。
以下のルールに従って応答してください:
 
1. ユーザーが早口で緊張している場合:
   - 落ち着いたトーンで応答する
   - 要点を簡潔に伝える
   - 「大丈夫ですよ」のような安心感を与える表現を使う
 
2. ユーザーが落ち込んでいる場合:
   - 共感を示してから情報を提供する
   - 「つらいですよね」のような受容的な表現を使う
   - 解決策は押し付けず、選択肢として提示する
 
3. ユーザーが楽しそうな場合:
   - テンションを合わせて明るく応答する
   - ユーモアを交えた表現を使う
 
4. ユーザーが怒っている場合:
   - まず謝罪と共感を示す
   - 問題解決に集中した簡潔な応答をする
   - 弁解ではなく具体的な解決策を提示する
"""

パターン2: メタデータ抽出型

モデルに感情のメタデータを構造化して返させ、アプリケーション側で応答ロジックを制御するパターンです。より細かい制御が可能です。

METADATA_EXTRACTION_PROMPT = """
ユーザーの音声に対して、以下の2つを返してください:
 
1. JSON形式の感情メタデータ(テキスト応答の先頭に配置):
{
  "emotion": "happy|sad|angry|anxious|neutral",
  "confidence": 0.0-1.0,
  "energy_level": "high|medium|low"
}
 
2. その後に通常の応答テキスト
 
例:
{"emotion": "anxious", "confidence": 0.8, "energy_level": "high"}
お急ぎのようですね。ご質問にすぐお答えします。
"""
 
import json
 
def process_response_with_emotion(response_text):
    """応答テキストから感情メタデータを抽出"""
    lines = response_text.strip().split("\n", 1)
 
    try:
        emotion_data = json.loads(lines[0])
        reply_text = lines[1] if len(lines) > 1 else ""
        return emotion_data, reply_text
    except json.JSONDecodeError:
        return {"emotion": "neutral", "confidence": 0.5}, response_text
 
# 使用例
emotion, reply = process_response_with_emotion(response.text)
print(f"Detected emotion: {emotion['emotion']} ({emotion['confidence']:.0%})")
print(f"Reply: {reply}")
# 出力例:
# Detected emotion: anxious (80%)
# Reply: お急ぎのようですね。ご質問にすぐお答えします。

パターン3: マルチターン感情トラッキング

会話全体を通じて感情の推移を追跡し、長期的なパターンに基づいて応答を調整するパターンです。

from collections import deque
from datetime import datetime
 
class EmotionTracker:
    """会話中の感情推移を追跡するクラス"""
 
    def __init__(self, window_size=10):
        self.history = deque(maxlen=window_size)
 
    def add(self, emotion_data):
        self.history.append({
            "timestamp": datetime.now().isoformat(),
            **emotion_data
        })
 
    def get_trend(self):
        """感情のトレンドを分析"""
        if len(self.history) < 3:
            return "insufficient_data"
 
        recent = list(self.history)[-3:]
        emotions = [e["emotion"] for e in recent]
 
        # 一貫してネガティブなら、特別な対応が必要
        if all(e in ("sad", "angry", "anxious") for e in emotions):
            return "persistent_negative"
 
        # 改善傾向
        if emotions[-1] in ("happy", "neutral") and emotions[0] in ("sad", "angry"):
            return "improving"
 
        return "stable"
 
    def should_escalate(self):
        """エスカレーション判定"""
        trend = self.get_trend()
        return trend == "persistent_negative"
 
# 使用例
tracker = EmotionTracker()
tracker.add({"emotion": "anxious", "confidence": 0.8, "energy_level": "high"})
tracker.add({"emotion": "angry", "confidence": 0.7, "energy_level": "high"})
tracker.add({"emotion": "angry", "confidence": 0.9, "energy_level": "high"})
 
if tracker.should_escalate():
    print("Escalation recommended: persistent negative emotion detected")
# 出力: Escalation recommended: persistent negative emotion detected

ユースケース別アーキテクチャ

ユースケース1: カスタマーサポート

[顧客の音声] → [Flash Live API]
                    │
                    ├── 感情分析 → [EmotionTracker]
                    │                    │
                    │              escalation判定
                    │                    │
                    │              ├─ 通常 → AIが応答
                    │              └─ 要エスカレ → 人間オペレータに転送
                    │
                    └── テキスト化 → [ナレッジベース検索]
                                        │
                                  [回答生成・音声合成]

ユースケース2: 教育アプリ

[学習者の音声] → [Flash Live API]
                    │
                    ├── 理解度推定(声のトーンから)
                    │       │
                    │       ├─ 理解している → 次のトピックへ
                    │       ├─ 困惑している → 別の説明アプローチ
                    │       └─ 退屈している → インタラクティブな演習へ
                    │
                    └── 質問内容の分析 → [教材データベース]

ユースケース3: ヘルスケア(ウェルネスチェック)

[利用者の音声] → [Flash Live API]
                    │
                    ├── 感情トレンド分析
                    │       │
                    │       ├─ 安定 → 通常の対話継続
                    │       ├─ 改善傾向 → ポジティブフィードバック
                    │       └─ 持続的ネガティブ → 専門家への相談を提案
                    │
                    └── 日次レポート生成 → [ダッシュボード]

パフォーマンス最適化

レイテンシの最小化

Live API で自然な会話体験を実現するには、エンドツーエンドのレイテンシを200ms以下に抑えることが理想です。

  • 音声チャンクサイズ: 小さいチャンク(512〜1024サンプル)で送信し、認識の応答性を確保する
  • バッファリング戦略: 入力バッファを最小限にし、ネットワーク遅延に対しては出力バッファで吸収する
  • リージョン選択: APIエンドポイントは地理的に近いリージョンを選択する

音声品質の確保

# ノイズゲート: 環境ノイズを除去
def apply_noise_gate(audio_chunk, threshold=200):
    """閾値以下の音声を無音に置換"""
    audio_array = np.frombuffer(audio_chunk, dtype=np.int16)
    mask = np.abs(audio_array) < threshold
    audio_array[mask] = 0
    return audio_array.tobytes()
 
# 音量正規化: 入力レベルを一定に保つ
def normalize_volume(audio_chunk, target_rms=3000):
    """RMS値を基準に音量を正規化"""
    audio_array = np.frombuffer(audio_chunk, dtype=np.int16).astype(np.float32)
    current_rms = np.sqrt(np.mean(audio_array ** 2))
    if current_rms > 0:
        gain = target_rms / current_rms
        audio_array = np.clip(audio_array * gain, -32768, 32767)
    return audio_array.astype(np.int16).tobytes()

セキュリティとプライバシーの考慮事項

音声データは個人情報の中でも特にセンシティブなカテゴリに属します。実装時には以下の点に注意してください。

  • 音声データの保存: Live API は基本的にストリーミング処理であり、サーバー側に音声データを永続保存しない設計にする
  • 感情データの取り扱い: 感情分析結果は匿名化して保存し、個人と紐付けない
  • ユーザーへの開示: 感情分析を行っていることをユーザーに明示し、同意を得る
  • データの暗号化: WebSocket通信はTLS(wss://)で暗号化する

まとめ

Gemini 3.1 Flash Live の Live API は、音声AIアプリケーションの構築に新しい次元を加えます。音響的な感情理解、128,000トークンのコンテキスト維持、リアルタイムストリーミングの3つの特徴を組み合わせることで、カスタマーサポート・教育・ヘルスケアなど多様な分野で感情対応型の音声アプリを実現できます。

本記事で紹介した3つの設計パターン(プロンプト駆動型・メタデータ抽出型・マルチターントラッキング)と3つのアーキテクチャを参考に、まずはプロトタイプから構築を始めてみてください。

シェア

お読みいただきありがとうございます

Gemini Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

API / SDK2026-07-15
自動採用された出力こそ抜き取る — 限られたレビュー予算で静かな品質劣化に気づく設計
信頼度ゲートが見ているのは、モデルが迷った出力だけです。静かな劣化は自動採用された側に沈みます。1日30分というレビュー予算を前提に、二項分布で検出日数を見積もり、層別抜き取りと累積監視で気づく速さを上げた設計と実測を共有します。
API / SDK2026-07-14
Gemini Code Execution の計算結果とモデルの文章がずれる — 実行結果だけを信頼する検証ゲートの実装
Gemini の Code Execution は実際に走らせた計算結果と、それを説明する自然文を別々に返します。文章側の数値を鵜呑みにすると幻覚を掴みます。実行結果だけを真実として抽出し照合する検証ゲートの実装を、動くコードで解説します。
API / SDK2026-07-13
responseSchema で $ref が使えず詰まったら — responseJsonSchema で再帰スキーマを本番で扱う
Gemini の responseSchema は OpenAPI サブセットで $ref/$defs が使えず、共有定義も再帰も表現できません。responseJsonSchema へ移行し、多言語フィールドの再利用とカテゴリ木の再帰を本番で扱う実装をまとめました。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →