Azure AI 语音实时翻译 (VoiceLive TS)

azure-ai-voicelive-ts
分类编程
作者Agentic Awesome Skills 社区
许可MIT
评分4.70/5
使用12.6K

@azure/ai-voicelive (JavaScript/TypeScript)

用于在 Node.js 和浏览器环境中构建基于 Azure AI 的双向语音助手的实时语音 AI SDK。

安装

bash
npm install @azure/ai-voicelive @azure/identity

TypeScript 用户

npm install @types/node

当前版本: 1.0.0-beta.3

支持的环境:

  • Node.js LTS 版本 (20+)

  • 现代浏览器 (Chrome, Firefox, Safari, Edge)

环境变量

bash
AZURE_VOICELIVE_ENDPOINT=https://<resource>.cognitiveservices.azure.com

可选:如果不使用 Entra ID,请提供 API 密钥

AZURE_VOICELIVE_API_KEY=<your-api-key>

可选:日志级别

AZURE_LOG_LEVEL=info

身份验证

Microsoft Entra ID (推荐)

typescript
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 密钥

typescript
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);

客户端层级结构

code
VoiceLiveClient
└── VoiceLiveSession (WebSocket 连接)
    ├── updateSession()      → 配置会话选项
    ├── subscribe()          → 事件处理器 (Azure SDK 模式)
    ├── sendAudio()          → 流式传输音频输入
    ├── addConversationItem() → 添加消息/函数输出
    └── sendEvent()          → 发送原始协议事件

快速上手

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

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

// 创建客户端并启动会话
const client = new VoiceLiveClient(endpoint, credential);
const session = await client.startSession("gpt-4o-mini-realtime-preview");

// 配置会话
await session.updateSession({
modalities: ["text", "audio"],
instructions: "你是一个得力的 AI 助手。请自然地回答。",
voice: {
type: "azure-standard",
name: "en-US-AvaNeural",
},
turnDetection: {
type: "server_vad",
threshold: 0.5,
prefixPaddingMs: 300,
silenceDurationMs: 500,
},
inputAudioFormat: "pcm16",
outputAudioFormat: "pcm16",
});

// 订阅事件
const subscription = session.subscribe({
onResponseAudioDelta: async (event, context) => {
// 处理流式音频输出
const audioData = event.delta;
playAudioChunk(audioData);
},
onResponseTextDelta: async (event, context) => {
// 处理流式文本
process.stdout.write(event.delta);
},
onInputAudioTranscriptionCompleted: async (event, context) => {
console.log("用户说道:", event.transcript);
},
});

// 从麦克风发送音频
function sendAudioChunk(audioBuffer: ArrayBuffer) {
session.sendAudio(audioBuffer);
}

会话配置

typescript
await session.updateSession({
  // 模态 (Modalities)
modalities: ["audio", "text"], // 系统指令 instructions: "你是一名客服代表。", // 语音选择 voice: { type: "azure-standard", // 或 "azure-custom", "openai" name: "en-US-AvaNeural", }, // 话轮检测 (VAD) turnDetection: { type: "server_vad", // 或 "azure_semantic_vad" threshold: 0.5, prefixPaddingMs: 300, silenceDurationMs: 500, }, // 音频格式 inputAudioFormat: "pcm16", outputAudioFormat: "pcm16", // 工具 (函数调用) tools: [ { type: "function", name: "get_weather", description: "获取当前天气", parameters: { type: "object", properties: { location: { type: "string" } }, required: ["location"] } } ], toolChoice: "auto", });
code
## 事件处理 (Azure SDK 模式)

SDK 采用了基于订阅的事件处理模式:

typescript
const subscription = session.subscribe({
// 连接生命周期
onConnected: async (args, context) => {
console.log("已连接:", args.connectionId);
},
onDisconnected: async (args, context) => {
console.log("已断开:", args.code, args.reason);
},
onError: async (args, context) => {
console.error("错误:", args.error.message);
},

// 会话事件
onSessionCreated: async (event, context) => {
console.log("会话已创建:", context.sessionId);
},
onSessionUpdated: async (event, context) => {
console.log("会话已更新");
},

// 音频输入事件 (VAD)
onInputAudioBufferSpeechStarted: async (event, context) => {
console.log("语音开始于:", event.audioStartMs);
},
onInputAudioBufferSpeechStopped: async (event, context) => {
console.log("语音结束于:", event.audioEndMs);
},

// 转录事件
onConversationItemInputAudioTranscriptionCompleted: async (event, context) => {
console.log("用户说:", event.transcript);
},
onConversationItemInputAudioTranscriptionDelta: async (event, context) => {
process.stdout.write(event.delta);
},

// 响应事件
onResponseCreated: async (event, context) => {
console.log("响应已开始");
},
onResponseDone: async (event, context) => {
console.log("响应已完成");
},

// 文本流
onResponseTextDelta: async (event, context) => {
process.stdout.write(event.delta);
},
onResponseTextDone: async (event, context) => {
console.log("\n--- 文本完成 ---");
},

// 音频流
onResponseAudioDelta: async (event, context) => {
const audioData = event.delta;
playAudioChunk(audioData);
},
onResponseAudioDone: async (event, context) => {
console.log("音频完成");
},

// 音频转录 (助手所说内容)
onResponseAudioTranscriptDelta: async (event, context) => {
process.stdout.write(event.delta);
},

// 函数调用
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" });
}
},

// 调试通用捕获
onServerEvent: async (event, context) => {
conso
le.log("Event:", event.type);
},
});

// 完成后清理
await subscription.close();

code
## 函数调用 (Function Calling)
typescript
// 在会话配置中定义工具
await session.updateSession({
modalities: ["audio", "text"],
instructions: "帮助用户获取天气信息。",
tools: [
{
type: "function",
name: "get_weather",
description: "获取指定地点的当前天气",
parameters: {
type: "object",
properties: {
location: {
type: "string",
description: "城市及州或国家",
},
},
required: ["location"],
},
},
],
toolChoice: "auto",
});

// 处理函数调用
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);

// 发送函数执行结果
await session.addConversationItem({
type: "function_call_output",
callId: event.callId,
output: JSON.stringify(weatherData),
});

// 触发响应生成
await session.sendEvent({ type: "response.create" });
}
},
});

code
## 语音选项

| 语音类型 | 配置 | 示例 |
|------------|--------|---------|
| Azure Standard | { type: "azure-standard", name: "..." } | "en-US-AvaNeural" |
| Azure Custom | { type: "azure-custom", name: "...", endpointId: "..." } | 自定义语音端点 |
| Azure Personal | { 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 多模态 | 高性价比应用 |

话轮检测 (Turn Detection) 选项

typescript // 服务器端 VAD (默认) turnDetection: { type: "server_vad", threshold: 0.5, prefixPaddingMs: 300, silenceDurationMs: 500, }

// Azure 语义 VAD (更智能的检测)
turnDetection: {
type: "azure_semantic_vad",
}

// Azure 语义 VAD (英语优化)
turnDetection: {
type: "azure_semantic_vad_en",
}

// Azure 语义 VAD (多语言)
turnDetection: {
type: "azure_semantic_vad_multilingual",
}

code
## 音频格式

| 格式 | 采样率 | 使用场景 |
|--------|-------------|----------|
| pcm16 | 24kHz | 默认,高质量 |
| pcm16-8000hz | 8kHz | 电话通信 |
| pcm16-16000hz | 16kHz | 语音助手 |
| g711_ulaw | 8kHz | 电话通信 (美国) |
| g711_alaw | 8kHz | 电话通信 (欧洲) |

关键类型参考

| 类型 | 用途 |
|------|---------|
| VoiceLiveClient | 用于创建会话的主客户端 |
| VoiceLiveSession | 活跃的 WebSocket 会话 |
| VoiceLiveSessionHandlers | 事件处理接口 |
| VoiceLiveSubscription | 活跃的事件订阅 |
| ConnectionContext | 连接事件的上下文 |
| SessionContext | 会话事件的上下文 |
| ServerEventUnion | 所有服务器事件的联合类型 |

错误处理

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

const subscription = session.

code
javascript
subscribe({
onError: async (args, context) => {
const { error } = args;

if (error instanceof VoiceLiveConnectionError) {
console.error("连接错误:", error.message);
} else if (error instanceof VoiceLiveAuthenticationError) {
console.error("认证错误:", error.message);
} else if (error instanceof VoiceLiveProtocolError) {
console.error("协议错误:", error.message);
}
},

onServerError: async (event, context) => {
console.error("服务器错误:", event.error?.message);
},
});
code
## 日志记录
typescript
import { setLogLevel } from "@azure/logger";

// 启用详细日志
setLogLevel("info");

// 或通过环境变量设置
// AZURE_LOG_LEVEL=info

code
## 浏览器使用
typescript
// 浏览器环境需要打包工具 (Vite, webpack 等)
import { VoiceLiveClient } from "@azure/ai-voicelive";
import { InteractiveBrowserCredential } from "@azure/identity";

// 使用兼容浏览器的凭据
const credential = new InteractiveBrowserCredential({
clientId: "your-client-id",
tenantId: "your-tenant-id",
});

const client = new VoiceLiveClient(endpoint, credential);

// 请求麦克风权限
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const audioContext = new AudioContext({ sampleRate: 24000 });

// 处理音频并发送至会话
// ... (完整实现请参考示例)
``

最佳实践

1. 始终使用 DefaultAzureCredential —— 切勿在代码中硬编码 API 密钥。
2. 设置两种模态 —— 为语音助手包含
["text", "audio"]
3. 使用 Azure Semantic VAD —— 比基础服务器 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 |

适用场景

此技能适用于执行概览中所描述的工作流或操作。

局限性

  • 仅在任务与上述范围明确匹配时使用此技能。
  • 不要将输出结果视为针对特定环境的验证、测试或专家评审的替代方案。
  • 如果缺少必要的输入、权限、安全边界或成功标准,请停止并请求进一步说明。