# 研发工单 v1.3.0 - 03-02 音频录制与转写 > 父工单:[03-会议任务拆分](./03-会议任务拆分.md) > > 依赖:03-01(API 契约) --- ## 一、目标 实现前端音频录制(MediaRecorder API)和后端音频转写(STT)能力,打通"录音 → 上传 → 转写文字 → 保存为会议纪要"的完整链路。 ## 二、范围 **包含**: - 前端录音控件(`AudioRecorder.vue`) - 前端录音组合式函数(`useAudioRecorder.ts`) - 录音状态管理(录制中/暂停/停止/时长显示) - 音频上传 API 交互(POST multipart/form-data) - 后端音频文件临时存储 - 后端 STT 转写服务(`SttService.cs`) - 转写结果回写 `MeetingNotes` **不包含**: - 实时转写(边录边转) - 音频持久存储(转写完成后删除音频文件) - 音频云同步 - 语音指令输入(属于工单 02) ## 三、前置条件 | 条件 | 说明 | |---|---| | 03-01 完成 | `MeetingController`、`MeetingService` 基础骨架就绪 | ## 四、详细规格 ### 4.1 前端录音控件 **AudioRecorder.vue**: ``` ┌────────────────────────────────┐ │ 🎤 会议录音 │ │ │ │ ● 录制中... 00:15:23 │ │ ┌──────────────────────────┐ │ │ │ ▁▃▂▄▅▂▁▃▄▅▃▂▁▂▄▅▃▁ │ │ ← 简易波形 │ └──────────────────────────┘ │ │ │ │ [⏹ 停止录音] │ │ │ │ 录音时长限制:最长 2 小时 │ └────────────────────────────────┘ ``` 状态: - **就绪**:显示录音按钮 - **录制中**:显示停止按钮 + 时长计时 + 简易波形条 - **已停止**:显示"提交转写" / "重新录制" ### 4.2 useAudioRecorder 组合式函数 ```typescript /// 音频录制器组合式函数,封装 MediaRecorder API export function useAudioRecorder() { // 状态 const isRecording = ref(false) const isPaused = ref(false) const duration = ref(0) // 秒 const audioBlob = ref(null) const audioUrl = ref(null) // 用于预览播放 // 方法 async function startRecording(): Promise // 请求麦克风权限,开始录制 function stopRecording(): void // 停止录制,生成 Blob function resetRecording(): void // 重置状态 function getAudioBlob(): Blob | null // 获取录制结果 // 内部 let mediaRecorder: MediaRecorder | null = null let timerInterval: number | null = null // 音频格式:webm(Chrome/Firefox)、mp4(Safari) // 时长限制:最长 2 小时(7200 秒) return { isRecording, isPaused, duration, audioBlob, audioUrl, startRecording, stopRecording, resetRecording, getAudioBlob } } ``` ### 4.3 前端 API 模块 ```typescript // src/Hua.Todo.Web/src/api/meeting.ts /// 上传音频文件并请求转写 async function transcribeAudio(taskId: number, audioBlob: Blob): Promise { const formData = new FormData(); formData.append('audio', audioBlob, 'meeting.webm'); const apiBaseUrl = window.__API_BASE_URL__ || 'http://localhost:5173/api'; const resp = await fetch(`${apiBaseUrl}/meeting/${taskId}/transcribe`, { method: 'POST', body: formData }); if (!resp.ok) throw new Error(`转写请求失败: ${resp.status}`); return resp.json(); } ``` ### 4.4 后端 SttService ```csharp /// 语音转写服务接口 public interface ISttService { /// 将音频文件转写为文字 /// 转写文字 Task TranscribeAsync(Stream audioStream, string format, CancellationToken ct = default); } ``` 实现策略(按优先级): | 平台/环境 | 实现方式 | 说明 | |---|---|---| | Windows MAUI | `Windows.Media.SpeechRecognition` 文件识别 | 系统自带,离线可用 | | macOS/iOS | `SFSpeechRecognizer` 文件识别 | 需在线 | | Android | `SpeechRecognizer` | 需在线 | | Linux | WebKit 在线;本地 `whisper.cpp` 降级 | 多策略 | | 通用服务端 | 扩展 `LlmClientService` 调用 Whisper API | Host 端部署 | > 初期(v1.3.0)优先实现服务端 Whisper API 调用方式(通过 `LlmClientService` 扩展),后续版本各平台原生逐补。 ### 4.5 音频上传处理流程 ``` 前端 AudioRecorder → stopRecording → Blob (webm/mp4) ↓ POST /api/meeting/{taskId}/transcribe (multipart/form-data) ↓ MeetingController.Transcribe() ↓ 保存音频临时文件到 meetings/ 目录 ↓ 调用 ISttService.TranscribeAsync() ↓ 得到文字结果 ↓ 删除临时音频文件 ↓ 调用 MeetingService.SaveTranscript() 保存到数据库 ↓ 返回 TranscribeResponse { taskId, transcript, audioDuration } ``` ### 4.6 错误处理 | 场景 | 处理 | |---|---| | 音频格式不支持 | 返回 400 "不支持的音频格式,支持 webm/wav/mp3" | | 音频文件太大 | 返回 400 "音频文件过大,请控制录音在 2 小时以内" | | STT 服务不可用 | 返回 503 "转写服务暂不可用,请稍后重试" | | taskId 不是会议类型 | 返回 400 "该待办项不是会议类型" | ## 五、验收标准 | 验收项 | 验证方法 | 预期结果 | |---|---|---| | 录音按钮可用 | 点击录音按钮 | 浏览器弹出麦克风权限请求 | | 录制过程 | 授权后开始录制 | 显示录音时长,波形条有变化 | | 停止录音 | 点击停止按钮 | 时长停止,显示"提交转写"按钮 | | 重新录制 | 点击"重新录制" | 状态重置,可再次录制 | | 上传转写 | 提交录音文件 | 返回转写文字 | | 纪要保存 | 转写完成后查看任务 | `meetingNotes` 字段有转写文字 | | 权限拒绝 | 浏览器拒绝麦克风 | 提示"无法访问麦克风,请使用文字输入" | | 浏览器不支持 | IE/Safari 旧版等 | 提示"当前浏览器不支持录音,请使用文字输入" | ## 六、风险 | 风险 | 影响 | 应对 | |---|---|---| | Safari 不支持 webm | 无法录制 | 使用 mp4 格式(Safari 支持);MIME type 自动适配 | | STT 准确率不足 | 转写错误多 | 支持用户编辑修正转写结果 | | 长音频转写耗时长 | 用户等待 | 前端显示转写进度或"转写中"加载状态 | ## 七、Touch List | 文件路径 | 修改类型 | |---|---| | `src/Hua.Todo.Web/src/components/AudioRecorder.vue` | 新增 | | `src/Hua.Todo.Web/src/composables/useAudioRecorder.ts` | 新增 | | `src/Hua.Todo.Web/src/api/meeting.ts` | 新增 | | `src/Hua.Todo.Application/Meeting/SttService.cs` | 新增 | | `src/Hua.Todo.Application/Meeting/MeetingController.cs` | 修改 | --- **工单编号**:03-02 **标题**:音频录制与转写 **版本**:v1.3.0 **创建日期**:2026-06-16