---
name: speaking-voice-input
overview: 在 Speaking.vue 中增加语音输入功能，调用豆包流式语音识别 API 实现语音转文字
todos:
  - id: update-config
    content: 在 config/index.js 中添加 DOUBAO_ASR_WS_PATH 配置
    status: completed
  - id: add-recording-state
    content: 在 Speaking.vue 中添加录音相关状态和变量
    status: completed
    dependencies:
      - update-config
  - id: implement-recording
    content: 实现录音功能（MediaRecorder 音频采集和转换）
    status: completed
    dependencies:
      - add-recording-state
  - id: implement-websocket
    content: 实现 WebSocket 流式识别（连接管理、消息收发）
    status: completed
    dependencies:
      - implement-recording
  - id: add-voice-input-ui
    content: 添加麦克风按钮 UI 和录音状态动画
    status: completed
    dependencies:
      - implement-websocket
  - id: cleanup-resources
    content: 添加组件卸载时的资源清理逻辑
    status: completed
    dependencies:
      - add-voice-input-ui
---

## 产品需求

在英语口语对话页面（Speaking.vue）中增加语音输入功能，让用户可以通过麦克风进行语音输入，系统调用豆包大模型流式语音识别 API 将语音转换为文字。

## 核心功能

- **麦克风按钮**：在输入框旁边添加麦克风图标按钮，支持点击开始/停止录音
- **实时录音**：使用浏览器 MediaRecorder API 采集麦克风音频（16kHz, 16bit, 单声道, PCM 格式）
- **流式识别**：通过 WebSocket 发送音频流到豆包 ASR API，实时接收识别结果
- **结果回填**：将识别文字自动填入输入框，用户可编辑后发送
- **状态反馈**：录音状态（空闲/录音中）的视觉反馈，包括按钮样式变化和波形动画

## 用户交互流程

1. 用户点击麦克风按钮，开始录音
2. 页面显示录音中状态，按钮变为红色闪烁
3. 用户说话，音频数据通过 WebSocket 实时发送到服务器
4. 服务器返回识别结果，显示在输入框中
5. 用户点击停止按钮或再次点击麦克风停止录音
6. 用户确认输入内容后点击发送按钮

## 技术栈

- 前端框架：Vue 3 + Composition API
- 样式：Scss（现有项目使用）
- 音频采集：浏览器 MediaRecorder API
- 实时通信：WebSocket
- 认证方式：与 TTS 相同（X-Api-App-Id + X-Api-Access-Key）

## 实现方案

### 1. 配置更新 (config/index.js)

添加流式 ASR WebSocket 地址配置：

```javascript
// 豆包流式语音识别 ASR
export const DOUBAO_ASR_WS_PATH = "wss://openspeech.bytedance.com/api/v1/asr/ws_binary";
```

### 2. Speaking.vue 功能实现

#### 录音控制

- 使用 `navigator.mediaDevices.getUserMedia` 获取麦克风权限
- 使用 `MediaRecorder` API 录制音频（mimeType: 'audio/webm;codecs=opus' 或 'audio/pcm'）
- 由于浏览器不直接支持录制 PCM，需要录制后转换或使用 AudioContext 重采样

#### WebSocket 通信

- 建立 WebSocket 连接，使用认证头
- 发送初始化消息（包含音频参数配置）
- 分帧发送音频数据（建议每 40ms 一帧）
- 接收并处理识别结果消息

#### 音频处理

由于浏览器 MediaRecorder 不直接支持录制 PCM，需要：

- 方案一：录制 webm/opus 格式，发送时解码为 PCM
- 方案二：使用 AudioContext + ScriptProcessor/AudioWorklet 实时采集 PCM
- 推荐方案一，实现更简单，兼容性更好

#### UI 组件

- 麦克风按钮（SVG 图标）
- 录音状态动画（波形或脉冲效果）
- 录音时长显示（可选）

## 关键代码结构

### 录音状态管理

```javascript
const isRecording = ref(false);
const recordingDuration = ref(0);
let mediaRecorder = null;
let audioContext = null;
let websocket = null;
```

### WebSocket 消息处理

```javascript
// 初始化消息格式
{ 
  "app": { "appid": DOUBAO_APP_ID, "token": DOUBAO_ACCESS_TOKEN },
  "user": { "uid": "speaking_asr_" + Date.now() },
  "audio": { "format": "pcm", "rate": 16000, "bits": 16, "channel": 1 }
}
```

## 性能考虑

- 音频帧发送间隔：40ms（与 16kHz 采样率匹配）
- WebSocket 心跳：防止连接断开
- 错误重连：录音中断时自动尝试重连
- 内存管理：及时释放音频资源

## 兼容性

- 使用 `MediaRecorder.isTypeSupported` 检测浏览器支持
- 降级处理：浏览器不支持时隐藏麦克风按钮

# Agent Extensions

此任务不需要使用任何 Agent Extensions