mcpField
A
azure-ai-voicelive-ts

azure-ai-voicelive-ts

github.com/sickn33開発48.7k64 回インストール今日更新
リポジトリ

azure-ai-voicelive-ts について

@azure/ai-voicelive は、Node.js とブラウザーで Azure AI を使ったリアルタイム双方向音声アプリを構築する JavaScript/TypeScript SDK です。WebSocket セッションで音声ストリーミング、イベント処理、音声や会話の設定を行えます。

主な機能

  1. 01リアルタイム WebSocket セッションの作成
  2. 02音声入力のストリーミング
  3. 03セッションイベントの購読
  4. 04モダリティと音声オプションの設定
  5. 05関数呼び出しツールの定義

活用シーン

  1. 01リアルタイム音声アシスタントの構築
  2. 02ブラウザーまたは Node.js の音声をセッションに送信
  3. 03接続イベントと会話イベントの処理
  4. 04音声とターン検出の設定

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/sickn33/agentic-awesome-skills --skill azure-ai-voicelive-ts

インストール後、Claude Code で/azure-ai-voicelive-tsを入力して読み込まれたか確認します。

詳細

@azure/ai-voicelive (JavaScript/TypeScript)

Node.js およびブラウザー環境で Azure AI を使用して双方向音声アシスタントを構築するためのリアルタイム音声 AI SDK です。

インストール

npm install @azure/ai-voicelive @azure/identity
# TypeScript users
npm install @types/node

履歴上のサンプル基準バージョン:1.0.0-beta.3。使用前にプレビュー API との互換性を確認し、バージョンを固定してください。

サポート対象環境:

  • Node.js LTS バージョン(20 以降)
  • 最新のブラウザー(Chrome、Firefox、Safari、Edge)

環境変数

AZURE_VOICELIVE_ENDPOINT=https://<resource>.cognitiveservices.azure.com
# Optional: API key if not using Entra ID
AZURE_VOICELIVE_API_KEY=<your-api-key>
# Optional: Logging
AZURE_LOG_LEVEL=info

認証

Microsoft Entra ID(推奨)
import { DefaultAzureCredential } from "@azure/identity";
import { VoiceLiveClient } from "@azure/ai-voicelive";

const credential = new DefaultAzureCredential();
const endpoint = "https://your-resource.cognitiveservices.azure.com";

const client = new VoiceLiveClient(endpoint, credential);
API キー
import { AzureKeyCredential } from "@azure/core-auth";
import { VoiceLiveClient } from "@azure/ai-voicelive";

const endpoint = "https://your-resource.cognitiveservices.azure.com";
const credential = new AzureKeyCredential("your-api-key");

const client = new VoiceLiveClient(endpoint, credential);

クライアントの階層

VoiceLiveClient
└── VoiceLiveSession (WebSocket connection)
    ├── updateSession()      → Configure session options
    ├── subscribe()          → Event handlers (Azure SDK pattern)
    ├── sendAudio()          → Stream audio input
    ├── addConversationItem() → Add messages/function outputs
    └── sendEvent()          → Send raw protocol events

クイックスタート

import { DefaultAzureCredential } from "@azure/identity";
import { VoiceLiveClient } from "@azure/ai-voicelive";

const credential = new DefaultAzureCredential();
const endpoint = process.env.AZURE_VOICELIVE_ENDPOINT!;

// Create client and start session
const client = new VoiceLiveClient(endpoint, credential);
const session = await client.startSession("gpt-4o-mini-realtime-preview");

// Configure session
await session.updateSession({
  modalities: ["text", "audio"],
  instructions: "You are a helpful AI assistant. Respond naturally.",
  voice: {
    type: "azure-standard",
    name: "en-US-AvaNeural",
  },
  turnDetection: {
    type: "server_vad",
    threshold: 0.5,
    prefixPaddingMs: 300,
    silenceDurationMs: 500,
  },
  inputAudioFormat: "pcm16",
  outputAudioFormat: "pcm16",
});

// Subscribe to events
const subscription = session.subscribe({
  onResponseAudioDelta: async (event, context) => {
    // Handle streaming audio output
    const audioData = event.delta;
    playAudioChunk(audioData);
  },
  onResponseTextDelta: async (event, context) => {
    // Handle streaming text
    process.stdout.write(event.delta);
  },
  onConversationItemInputAudioTranscriptionCompleted: async (event, context) => {
    console.log("User said:", event.transcript);
  },
});

// Send audio from microphone
function sendAudioChunk(audioBuffer: ArrayBuffer) {
  return session.sendAudio(audioBuffer);
}

セッションの設定

await session.updateSession({
  // Modalities
  modalities: ["audio", "text"],
  
  // System instructions
  instructions: "You are a customer service representative.",
  
  // Voice selection
  voice: {
    type: "azure-standard",  // or "azure-custom", "openai"
    name: "en-US-AvaNeural",
  },
  
  // Turn detection (VAD)
  turnDetection: {
    type: "server_vad",      // or "azure_semantic_vad"
    threshold: 0.5,
    prefixPaddingMs: 300,
    silenceDurationMs: 500,
  },
  
  // Audio formats
  inputAudioFormat: "pcm16",
  outputAudioFormat: "pcm16",
  
  // Tools (function calling)
  tools: [
    {
      type: "function",
      name: "get_weather",
      description: "Get current weather",
      parameters: {
        type: "object",
        properties: {
          location: { type: "string" }
        },
        required: ["location"]
      }
    }
  ],
  toolChoice: "auto",
});

イベント処理(Azure SDK パターン)

この SDK では、サブスクリプションベースのイベント処理パターンを使用します。

const subscription = session.subscribe({
  // Connection lifecycle
  onConnected: async (args, context) => {
    console.log("Connected:", args.connectionId);
  },
  onDisconnected: async (args, context) => {
    console.log("Disconnected:", args.code, args.reason);
  },
  onError: async (args, context) => {
    console.error("Error:", args.error.message);
  },
  
  // Session events
  onSessionCreated: async (event, context) => {
    console.log("Session created:", context.sessionId);
  },
  onSessionUpdated: async (event, context) => {
    console.log("Session updated");
  },
  
  // Audio input events (VAD)
  onInputAudioBufferSpeechStarted: async (event, context) => {
    console.log("Speech started at:", event.audioStartMs);
  },
  onInputAudioBufferSpeechStopped: async (event, context) => {
    console.log("Speech stopped at:", event.audioEndMs);
  },
  
  // Transcription events
  onConversationItemInputAudioTranscriptionCompleted: async (event, context) => {
    console.log("User said:", event.transcript);
  },
  onConversationItemInputAudioTranscriptionDelta: async (event, context) => {
    process.stdout.write(event.delta);
  },
  
  // Response events
  onResponseCreated: async (event, context) => {
    console.log("Response started");
  },
  onResponseDone: async (event, context) => {
    console.log("Response complete");
  },
  
  // Streaming text
  onResponseTextDelta: async (event, context) => {
    process.stdout.write(event.delta);
  },
  onResponseTextDone: async (event, context) => {
    console.log("\n--- Text complete ---");
  },
  
  // Streaming audio
  onResponseAudioDelta: async (event, context) => {
    const audioData = event.delta;
    playAudioChunk(audioData);
  },
  onResponseAudioDone: async (event, context) => {
    console.log("Audio complete");
  },
  
  // Audio transcript (what assistant said)
  onResponseAudioTranscriptDelta: async (event, context) => {
    process.stdout.write(event.delta);
  },
  
  // Function calling
  onResponseFunctionCallArgumentsDone: async (event, context) => {
    if (event.name === "get_weather") {
      const args = JSON.parse(event.arguments);
      const result = await getWeather(args.location);
      
      await session.addConversationItem({
        type: "function_call_output",
        callId: event.callId,
        output: JSON.stringify(result),
      });
      
      await session.sendEvent({ type: "response.create" });
    }
  },
  
  // Catch-all for debugging
  onServerEvent: async (event, context) => {
    console.log("Event:", event.type);
  },
});

// Clean up when done
await subscription.close();

関数呼び出し

// Define tools in session config
await session.updateSession({
  modalities: ["audio", "text"],
  instructions: "Help users with weather information.",
  tools: [
    {
      type: "function",
      name: "get_weather",
      description: "Get current weather for a location",
      parameters: {
        type: "object",
        properties: {
          location: {
            type: "string",
            description: "City and state or country",
          },
        },
        required: ["location"],
      },
    },
  ],
  toolChoice: "auto",
});

// Handle function calls
const subscription = session.subscribe({
  onResponseFunctionCallArgumentsDone: async (event, context) => {
    if (event.name === "get_weather") {
      const args = JSON.parse(event.arguments);
      const weatherData = await fetchWeather(args.location);
      
      // Send function result
      await session.addConversationItem({
        type: "function_call_output",
        callId: event.callId,
        output: JSON.stringify(weatherData),
      });
      
      // Trigger response generation
      await session.sendEvent({ type: "response.create" });
    }
  },
});

音声のオプション

音声の種類設定例
Azure 標準{ type: "azure-standard", name: "..." }"en-US-AvaNeural"
Azure カスタム{ type: "azure-custom", name: "...", endpointId: "..." }カスタム音声エンドポイント
Azure パーソナル{ type: "azure-personal", speakerProfileId: "..." }パーソナル音声クローン
OpenAI{ type: "openai", name: "..." }"alloy"、"echo"、"shimmer"

サポート対象モデル

モデル説明用途
gpt-4o-realtime-previewリアルタイム音声に対応した GPT-4o高品質な対話型 AI
gpt-4o-mini-realtime-preview軽量版 GPT-4o高速で効率的なインタラクション
phi4-mm-realtimePhi マルチモーダルコスト効率に優れたアプリケーション

ターン検出のオプション

// Server VAD (default)
turnDetection: {
  type: "server_vad",
  threshold: 0.5,
  prefixPaddingMs: 300,
  silenceDurationMs: 500,
}

// Azure Semantic VAD (smarter detection)
turnDetection: {
  type: "azure_semantic_vad",
}

// Azure Semantic VAD (English optimized)
turnDetection: {
  type: "azure_semantic_vad_en",
}

// Azure Semantic VAD (Multilingual)
turnDetection: {
  type: "azure_semantic_vad_multilingual",
}

音声フォーマット

フォーマットサンプルレート用途
pcm1624kHzデフォルト、高品質
pcm16-8000hz8kHz電話
pcm16-16000hz16kHz音声アシスタント
g711_ulaw8kHz電話(米国)
g711_alaw8kHz電話(EU)

主な型のリファレンス

型目的
VoiceLiveClientセッションを作成するメインクライアント
VoiceLiveSessionアクティブな WebSocket セッション
VoiceLiveSessionHandlersイベントハンドラーインターフェイス
VoiceLiveSubscriptionアクティブなイベントサブスクリプション
ConnectionContext接続イベントのコンテキスト
SessionContextセッションイベントのコンテキスト
ServerEventUnionすべてのサーバーイベントのユニオン型

エラー処理

import {
  VoiceLiveError,
  VoiceLiveConnectionError,
  VoiceLiveAuthenticationError,
  VoiceLiveProtocolError,
} from "@azure/ai-voicelive";

const subscription = session.subscribe({
  onError: async (args, context) => {
    const { error } = args;
    
    if (error instanceof VoiceLiveConnectionError) {
      console.error("Connection error:", error.message);
    } else if (error instanceof VoiceLiveAuthenticationError) {
      console.error("Auth error:", error.message);
    } else if (error instanceof VoiceLiveProtocolError) {
      console.error("Protocol error:", error.message);
    }
  },
  
  onServerError: async (event, context) => {
    console.error("Server error:", event.error?.message);
  },
});

ログ記録

import { setLogLevel } from "@azure/logger";

// Enable verbose logging
setLogLevel("info");

// Or via environment variable
// AZURE_LOG_LEVEL=info

ブラウザーでの使用

// Browser requires bundler (Vite, webpack, etc.)
import { VoiceLiveClient } from "@azure/ai-voicelive";
import { InteractiveBrowserCredential } from "@azure/identity";

// Use browser-compatible credential
const credential = new InteractiveBrowserCredential({
  clientId: "your-client-id",
  tenantId: "your-tenant-id",
});

const client = new VoiceLiveClient(endpoint, credential);

// Request microphone access
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const audioContext = new AudioContext({ sampleRate: 24000 });

// Process audio and send to session
// ... (see samples for full implementation)

ベストプラクティス

  1. 環境に適した認証情報を使用する — DefaultAzureCredential はサーバー向けのパターンです。サポートされているブラウザーでの対話型認証を使用し、サービスキーを公開しないでください
  2. 両方のモダリティを設定する — 音声アシスタントには ["text", "audio"] を含めてください
  3. VAD を評価する — 言語、レイテンシ、ノイズの条件に適したサポート対象モードを選択し、テストしてください
  4. すべての種類のエラーを処理する — 接続、認証、プロトコルのエラー
  5. サブスクリプションをクリーンアップする — 完了時に subscription.close() を呼び出してください
  6. 適切な音声フォーマットを使用する — 最高の品質を得るには、24kHz の PCM16 を使用してください

参考リンク

リソースURL
npm パッケージhttps://www.npmjs.com/package/@azure/ai-voicelive
GitHub ソースhttps://github.com/Azure/azure-sdk-for-js/tree/main/sdk/ai/ai-voicelive
サンプルhttps://github.com/Azure/azure-sdk-for-js/tree/main/sdk/ai/ai-voicelive/samples
API リファレンスhttps://learn.microsoft.com/javascript/api/@azure/ai-voicelive

使用する場面

このスキルは、概要で説明されているワークフローまたはアクションを実行する場合に適用できます。

制限事項

  • タスクが上記の説明された範囲に明確に該当する場合にのみ、このスキルを使用してください。
  • 出力を、環境固有の検証、テスト、または専門家によるレビューの代わりとして扱わないでください。
  • 必要な入力、権限、安全上の境界、または成功基準が不足している場合は、作業を中断して確認を求めてください。

スニペットは、アプリケーションヘルパーを省略した、個別の未コンパイル例です。モデル、音声、フォーマットのサポートは、地域や API バージョンによって異なります。イベントの取りこぼしを防ぐため、必要に応じて入力を送信する前にサブスクライブしてください。解析したツール引数を検証し、アクションを個別に承認してください。モデルの出力は信頼できません。マイクの録音や音声のクローンを作成する前に許可を得て、音声と文字起こしの保持方針を定めてください。すべての終了経路で、トラックを停止し、音声コンテキスト、サブスクリプション、基盤となるセッションを閉じてください。AudioContext のサンプルレートを指定しただけでは、キャプチャしたブラウザー音声が PCM16 としてエンコードされるわけではありません。固定したバージョン向けの SDK サンプルを使って、リサンプリングとエンコードを行い、バッファーとバックプレッシャーを適切に制限してください。

コメント