Files
Hua.Todo/docs/project/研发工单-v1.3.0/03-02-音频录制与转写.md
ShaoHua 9223ceca50 feat(mcp): 新增 MCP 服务基础设施,重构规则文件序号,新增 v1.3.0 工单文档
- 规则重组:全局/ 下 8 个规则合并为 6 个(01+02→01,05+06→04),序号顺延

- 新增项目规则 05-多入口功能同步规范(UI/语音入口覆盖检查)

- 新增 MCP 服务基础设施:Mcp/ 目录(DI 注册、端点扩展、动态工具描述符)、单元测试

- v1.3.0 工单文档:03 系列(会议任务拆分)、04(富文本描述与附件管理)

- MCP 接口与前端集成指南:docs/manual/08、09
2026-06-16 01:15:40 +08:00

7.0 KiB
Raw Permalink Blame History

研发工单 v1.3.0 - 03-02 音频录制与转写

父工单:03-会议任务拆分

依赖:03-01API 契约)


一、目标

实现前端音频录制(MediaRecorder API)和后端音频转写(STT)能力,打通"录音 → 上传 → 转写文字 → 保存为会议纪要"的完整链路。

二、范围

包含

  • 前端录音控件(AudioRecorder.vue
  • 前端录音组合式函数(useAudioRecorder.ts
  • 录音状态管理(录制中/暂停/停止/时长显示)
  • 音频上传 API 交互(POST multipart/form-data
  • 后端音频文件临时存储
  • 后端 STT 转写服务(SttService.cs
  • 转写结果回写 MeetingNotes

不包含

  • 实时转写(边录边转)
  • 音频持久存储(转写完成后删除音频文件)
  • 音频云同步
  • 语音指令输入(属于工单 02

三、前置条件

条件 说明
03-01 完成 MeetingControllerMeetingService 基础骨架就绪

四、详细规格

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

  // 音频格式:webmChrome/Firefox)、mp4Safari
  // 时长限制:最长 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