9223ceca50
- 规则重组:全局/ 下 8 个规则合并为 6 个(01+02→01,05+06→04),序号顺延 - 新增项目规则 05-多入口功能同步规范(UI/语音入口覆盖检查) - 新增 MCP 服务基础设施:Mcp/ 目录(DI 注册、端点扩展、动态工具描述符)、单元测试 - v1.3.0 工单文档:03 系列(会议任务拆分)、04(富文本描述与附件管理) - MCP 接口与前端集成指南:docs/manual/08、09
7.0 KiB
7.0 KiB
研发工单 v1.3.0 - 03-02 音频录制与转写
父工单:03-会议任务拆分
依赖: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 组合式函数
/// <summary>音频录制器组合式函数,封装 MediaRecorder API</summary>
export function useAudioRecorder() {
// 状态
const isRecording = ref(false)
const isPaused = ref(false)
const duration = ref(0) // 秒
const audioBlob = ref<Blob | null>(null)
const audioUrl = ref<string | null>(null) // 用于预览播放
// 方法
async function startRecording(): Promise<void> // 请求麦克风权限,开始录制
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 模块
// src/Hua.Todo.Web/src/api/meeting.ts
/// <summary>上传音频文件并请求转写</summary>
async function transcribeAudio(taskId: number, audioBlob: Blob): Promise<TranscribeResponse>
{
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
/// <summary>语音转写服务接口</summary>
public interface ISttService
{
/// <summary>将音频文件转写为文字</summary>
/// <returns>转写文字</returns>
Task<string> 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