azure-ai-voicelive-ts について
@azure/ai-voicelive は、Node.js とブラウザーで Azure AI を使ったリアルタイム双方向音声アプリを構築する JavaScript/TypeScript SDK です。WebSocket セッションで音声ストリーミング、イベント処理、音声や会話の設定を行えます。
主な機能
- 01リアルタイム WebSocket セッションの作成
- 02音声入力のストリーミング
- 03セッションイベントの購読
- 04モダリティと音声オプションの設定
- 05関数呼び出しツールの定義
活用シーン
- 01リアルタイム音声アシスタントの構築
- 02ブラウザーまたは Node.js の音声をセッションに送信
- 03接続イベントと会話イベントの処理
- 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-realtime | Phi マルチモーダル | コスト効率に優れたアプリケーション |
ターン検出のオプション
// 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",
}
音声フォーマット
| フォーマット | サンプルレート | 用途 |
|---|---|---|
pcm16 | 24kHz | デフォルト、高品質 |
pcm16-8000hz | 8kHz | 電話 |
pcm16-16000hz | 16kHz | 音声アシスタント |
g711_ulaw | 8kHz | 電話(米国) |
g711_alaw | 8kHz | 電話(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)
ベストプラクティス
- 環境に適した認証情報を使用する — DefaultAzureCredential はサーバー向けのパターンです。サポートされているブラウザーでの対話型認証を使用し、サービスキーを公開しないでください
- 両方のモダリティを設定する — 音声アシスタントには
["text", "audio"]を含めてください - VAD を評価する — 言語、レイテンシ、ノイズの条件に適したサポート対象モードを選択し、テストしてください
- すべての種類のエラーを処理する — 接続、認証、プロトコルのエラー
- サブスクリプションをクリーンアップする — 完了時に
subscription.close()を呼び出してください - 適切な音声フォーマットを使用する — 最高の品質を得るには、24kHz の PCM16 を使用してください
参考リンク
使用する場面
このスキルは、概要で説明されているワークフローまたはアクションを実行する場合に適用できます。
制限事項
- タスクが上記の説明された範囲に明確に該当する場合にのみ、このスキルを使用してください。
- 出力を、環境固有の検証、テスト、または専門家によるレビューの代わりとして扱わないでください。
- 必要な入力、権限、安全上の境界、または成功基準が不足している場合は、作業を中断して確認を求めてください。
スニペットは、アプリケーションヘルパーを省略した、個別の未コンパイル例です。モデル、音声、フォーマットのサポートは、地域や API バージョンによって異なります。イベントの取りこぼしを防ぐため、必要に応じて入力を送信する前にサブスクライブしてください。解析したツール引数を検証し、アクションを個別に承認してください。モデルの出力は信頼できません。マイクの録音や音声のクローンを作成する前に許可を得て、音声と文字起こしの保持方針を定めてください。すべての終了経路で、トラックを停止し、音声コンテキスト、サブスクリプション、基盤となるセッションを閉じてください。AudioContext のサンプルレートを指定しただけでは、キャプチャしたブラウザー音声が PCM16 としてエンコードされるわけではありません。固定したバージョン向けの SDK サンプルを使って、リサンプリングとエンコードを行い、バッファーとバックプレッシャーを適切に制限してください。