mcpField
A
add-voice

add-voice

github.com/cursor开发14.5k323 次安装今天更新
代码仓库

关于 add-voice

add-voice 是一项为现有应用集成 Grok Speech to Speech 的技能,适用于需要双向语音交互的应用开发者。它说明实时 WebSocket 会话、客户端音频处理和安全认证的实现方式。

主要功能

  1. 01建立实时双向语音会话
  2. 02通过临时令牌保护客户端
  3. 03采集并发送麦克风音频
  4. 04接收并播放音频响应
  5. 05支持函数工具调用

适用场景

  1. 01为应用添加语音模式
  2. 02将语音交互接入聊天界面
  3. 03替换现有语音级联流程
  4. 04用实时转录显示会话文本

MCP 相关

技能说明可在会话中配置 `mcp` 工具,也支持 `web_search`、`x_search`、`file_search` 和自定义函数。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/cursor/plugins --skill add-voice

安装后在 Claude Code 中输入/add-voice确认已加载。

详细介绍

添加语音

将 Grok 语音对语音功能添加到现有应用。在 /add-voice、输入 语音模式,或明确表示“添加 Grok 语音”时运行。

目标

实现可用的双工路径:用户应用的麦克风输入、音频输出、wss://api.x.ai/v1/realtime?model=grok-voice-latest、安全的身份验证。Cursor 没有原生麦克风;请接入应用(或示例客户端),而不是 IDE。

协议优先

与语言无关的事件循环。默认使用 TypeScript 示例。 仅在客户端 API 不同时提供简短的 Python 对照示例(例如 ws 与 websockets)。

文档

步骤

  1. 梳理应用

    • 技术栈:无、OpenAI Realtime、STT→LLM→TTS 级联、仅 TTS/STT。
    • 客户端:Web / Node / iOS / Android / 服务端。
    • 如果存在级联或 OpenAI Realtime:将其替换为下面的单一双工循环(URL、模型、语音、事件差异);仅当产品仍需要在 Agent 之外进行单次聆听或说话时,才保留独立的 /v1/stt 或 /v1/tts。
  2. 身份验证

    • 服务端:Bearer XAI_API_KEY。
    • 浏览器/移动端:后端调用 POST https://api.x.ai/v1/realtime/client_secrets,客户端使用临时令牌(Bearer 或浏览器 sec-websocket-protocol:xai-client-secret.<token>)。
    • 切勿将长期有效的密钥放入客户端包中。不要在聊天中粘贴密钥。
  3. 连接 + 会话

    • URL:wss://api.x.ai/v1/realtime?model=grok-voice-latest
    • 连接打开时:发送 session.update,设置 voice(默认为 eve)、instructions、turn_detection: { type: "server_vad" }(或设为 null 以启用按住说话),除非应用已统一使用其他采样率,否则使用 24 kHz PCM。
    • 设置 audio.input.transcription.model: "grok-transcribe",否则不会收到用户转录文本(conversation.item.input_audio_transcription.updated 是累积内容,而非增量内容)。
    • 如有需要,可使用工具:web_search、x_search、file_search、mcp、自定义 function。
  4. 音频 I/O(应用端)

    • 每个会话使用一个 AudioContext 进行采集和播放,并在用户手势中创建(符合自动播放策略)。请求 24 kHz;如果浏览器提供了其他采样率,请在发送前重采样。
    • 麦克风 → AudioWorklet,以约 100 ms 为单位分块 → input_audio_buffer.append(或使用二进制传输)。并行启动 WS 和麦克风;缓存较早到达的音频,并在连接打开后发送。
    • 立即播放 response.output_audio.delta;提前约 150 ms 排程,让各音频块无缝衔接。收到 input_audio_buffer.speech_started 时,停止所有已排程的音频(打断)。
    • 转录文本行:收到 input_audio_buffer.committed(item_id)时创建用户行,在 …transcription.updated 中填充;从 response.output_audio_transcript.delta / .done 获取助手文本,在 response.done 时结束轮次。
    • 使用函数工具时:发送 function_call_output,播放完成后再发送 response.create。
  5. Composer UI 约定

    • 在 Composer 右侧放置一个主按钮。Composer 为空时显示 波形图标(描边样式,例如 Phosphor WaveformIcon weight="bold";绝不使用 fill 样式,它在 16 px 下会显示为一团);点击后启动语音模式。存在任何文本时,显示经典的发送箭头;在语音模式下,该文本会发送到实时会话中(conversation.item.create + response.create)。文本回复流式传输时,显示停止方块。
    • 语音处于活动状态时,同一按钮显示动画波形(4 条柱,每条约 3 px 宽、间隔 2 px、高约 16 px,最小缩放比例为 0.4,以确保在 28 px 的按钮中仍清晰可见),点击后结束会话。动画由阶段驱动:聆听时较慢,说话时较快,连接中/思考时较慢且稍微变暗(不透明度 ≥ 0.75)。遵循 prefers-reduced-motion。不要使用 X 按钮或脉冲环。
    • 状态应显示在 Composer 内,而不是周围:占位文本显示 Connecting… / Listening… / Thinking… / Speaking…,并添加 sr-only role="status"。不要单独放置状态行。
    • 麦克风图标仅用于听写(/add-dictation)。绝不要将其用于语音模式。
  6. TS 骨架(默认)

const url = "wss://api.x.ai/v1/realtime?model=grok-voice-latest";
// Node: pass Authorization header. Browser: use xai-client-secret.<token> protocol.
const ws = new WebSocket(url /* , { headers: { Authorization: `Bearer ${token}` } } */);

ws.addEventListener("open", () => {
  ws.send(JSON.stringify({
    type: "session.update",
    session: {
      voice: "eve",
      instructions: "You are a helpful voice agent.",
      turn_detection: { type: "server_vad" },
    },
  }));
});

ws.addEventListener("message", (ev) => {
  const event = JSON.parse(String(ev.data));
  if (event.type === "response.output_audio.delta") {
    // decode base64 PCM and play
  }
});
  1. Python 版本(仅当应用使用 Python 时)
import json, os, websockets

url = "wss://api.x.ai/v1/realtime?model=grok-voice-latest"
headers = {"Authorization": f"Bearer {os.environ['XAI_API_KEY']}"}

async with websockets.connect(url, additional_headers=headers) as ws:
    await ws.send(json.dumps({
        "type": "session.update",
        "session": {
            "voice": "eve",
            "instructions": "You are a helpful voice agent.",
            "turn_detection": {"type": "server_vad"},
        },
    }))
    async for raw in ws:
        event = json.loads(raw)
        if event.get("type") == "response.output_audio.delta":
            pass  # decode and play
  1. 添加监测(首次人工测试前)

    • 运行 /debug-voice:它会提出计划,然后安装仅用于开发环境的日志接收器(POST /api/voice/log → .voice-logs/<sessionId>.ndjson,已加入 gitignore)、将音频缩减为字节数的客户端日志记录器,以及 UI 中的会话 ID;所有内容均使用应用自身的语言。
    • 同一个技能还包含修复循环,以及“症状 → 日志特征 → 修复”表。
  2. 冒烟测试

    • 通过 conversation.item.create + response.create 进行文本轮次;确认收到音频或转录事件。
    • 确认客户端中没有长期有效的密钥(在构建后的客户端包中 grep 环境变量名称和 client_secrets)。
    • 使用耳机将应用交给用户。在扬声器模式下,麦克风会收录回复,模型就会回答自己;这是回声,不是循环中的错误。
    • 使用 /debug-voice 迭代调试。

不在范围内

  • 仅语音转文本(/add-dictation)、朗读文本(/add-read-aloud)
  • 图像生成和纯文本推理
  • 虚构的端点、事件或 CLI 标志

评论

支持 Markdown